def generateMesh(self, maxh): mesh = self.collection.GenerateMesh(maxh=maxh) mesh.GenerateVolumeMesh() tmp_name = datetime.now().isoformat() mesh.Export(f'{tmp_name}.msh', 'Gmsh2 Format') meshconvert.convert2xml(f'{tmp_name}.msh', f'{tmp_name}.xml') os.remove(f'{tmp_name}.msh') os.remove(f'{tmp_name}_facet_region.xml') self.mesh = dolfin.Mesh(f'{tmp_name}.xml') os.remove(f'{tmp_name}.xml') self.domains = dolfin.MeshFunction('size_t', self.mesh, f'{tmp_name}_physical_region.xml') os.remove(f'{tmp_name}_physical_region.xml') self.domains.array()[:] -= self.domains.array().min() self.boundaries = dolfin.MeshFunction('size_t', self.mesh, 2, 0) for ii, subdomain in enumerate(self.csg_boundaries): subdomain.mark(self.boundaries, ii + 1)
def get(self): """ Unzip and convert to xml if possible.""" mesh = output = None import tempfile import os if not os.path.isfile(self.params): return None params = self.params try: split = os.path.splitext(params) if split[-1] == '.gz': # unzip the mesh import gzip f = gzip.open(params, 'rb') content = f.read() f.close() input = tempfile.NamedTemporaryFile( suffix=os.path.splitext(split[0])[-1], delete=False) input.write(content) input.close() params = input.name split = os.path.splitext(params) if split[-1] != '.xml': # convert using dolfin's meshconvert from dolfin_utils.meshconvert import meshconvert output = tempfile.NamedTemporaryFile( suffix='.xml', delete=False) output.close() meshconvert.convert2xml(params, output.name) params = output.name # use Mesh constructor with filename mesh = Mesh(params) try: os.unlink(output.name) except OSError: pass os.unlink(input.name) # many things could go wrong here # just return None as mesh if mesh importing failed finally: return mesh
def get(self): """ Unzip and convert to xml if possible.""" mesh = output = None import tempfile import os if not os.path.isfile(self.params): return None params = self.params try: split = os.path.splitext(params) if split[-1] == '.gz': # unzip the mesh import gzip f = gzip.open(params, 'rb') content = f.read() f.close() input = tempfile.NamedTemporaryFile(suffix=os.path.splitext( split[0])[-1], delete=False) input.write(content) input.close() params = input.name split = os.path.splitext(params) if split[-1] != '.xml': # convert using dolfin's meshconvert from dolfin_utils.meshconvert import meshconvert output = tempfile.NamedTemporaryFile(suffix='.xml', delete=False) output.close() meshconvert.convert2xml(params, output.name) params = output.name # use Mesh constructor with filename mesh = Mesh(params) try: os.unlink(output.name) except OSError: pass os.unlink(input.name) # many things could go wrong here # just return None as mesh if mesh importing failed finally: return mesh
def main(argv): "Main function" # Get command-line arguments try: opts, args = getopt.getopt(argv, "hi:o:", ["help", "input=", "output="]) except getopt.GetoptError: usage() sys.exit(2) # Get options iformat = None oformat = None for opt, arg in opts: if opt in ("-h", "--help"): usage() sys.exit() elif opt in ("-i", "--input"): iformat = arg elif opt in ("-o", "--output"): oformat = arg # Check that we got two filenames if not len(args) == 2: usage() sys.exit(2) # Get filenames ifilename = args[0] ofilename = args[1] # Can only convert to XML if oformat and oformat != "xml": error("Unable to convert to format %s." % (oformat, )) # Convert to XML meshconvert.convert2xml(ifilename, ofilename, iformat=iformat)
"gmsh", "-2", "-o", subdir + meshname + ".msh", subdir + meshname + ".geo" ]) except OSError: print( "-----------------------------------------------------------------------------" ) print(" Error: unable to generate the mesh using gmsh") print( " Make sure that you have gmsh installed and have added it to your system PATH" ) print( "-----------------------------------------------------------------------------" ) meshconvert.convert2xml(subdir + meshname + ".msh", subdir + meshname + ".xml", "gmsh") # Convert to XDMF MPI.barrier(mpi_comm_world()) mesh = Mesh(subdir + meshname + ".xml") XDMF = XDMFFile(mpi_comm_world(), subdir + meshname + ".xdmf") XDMF.write(mesh) XDMF.read(_mesh) if os.path.isfile(subdir + meshname + "_physical_region.xml") and os.path.isfile( subdir + meshname + "_facet_region.xml"): if MPI.rank(mpi_comm_world()) == 0: mesh = Mesh(subdir + meshname + ".xml") subdomains = MeshFunction( "size_t", mesh, subdir + meshname + "_physical_region.xml")
def Fracking(hsize, pressure_max, ell, E, nu, Model, law): #======================================================================================= # Input date #======================================================================================= # Geometry L = 4.0 # length H = 4.0 # height #hsize= 0.01 # target cell size meshname = "fracking_hsize%g" % (hsize) # Material constants #ell = Constant(4 * hsize) # internal length scale #E = 10. # Young modulus #nu = 0.3 # Poisson ratio biot = 0. #Biot coefficient PlaneStress = False gc = 1. # fracture toughness k_ell = Constant(1.0e-12) # residual stiffness #law = "AT1" # effective toughness if law == "AT2": Gc = gc / (1 + hsize / (2 * ell)) #AT2 elif law == "AT1": Gc = gc / (1 + 3 * hsize / (8 * ell)) #AT1 else: Gc = gc Gc = 1. ModelB = False if not ModelB: # Model A (isotropic model) Model = 'Isotropic' else: # Model B (Amor's model) Model = 'Amor' # Stopping criteria for the alternate minimization max_iterations = 50 tolerance = 1.0e-5 # Loading ut = 0.0 # reference value for the loading (imposed displacement) body_force = Constant((0., 0.)) # bulk load pressure_min = 0. # load multiplier min value #pressure_max = 1. # load multiplier max value pressure_steps = 10 # number of time steps WheelerApproach = False #======================================================================================= # Geometry and mesh generation #======================================================================================= # Generate a XDMF/HDF5 based mesh from a Gmsh string geofile = \ """ lc = DefineNumber[ %g, Name "Parameters/lc" ]; H = 4; L = 4; Point(1) = {0, 0, 0, 10*lc}; Point(2) = {L, 0, 0, 10*lc}; Point(3) = {L, H, 0, 10*lc}; Point(4) = {0, H, 0, 10*lc}; Point(5) = {1.8, H/2, 0, 1*lc}; Point(6) = {2.2, H/2, 0, 1*lc}; Line(1) = {1, 2}; Line(2) = {2, 3}; Line(3) = {3, 4}; Line(4) = {4, 1}; Line Loop(5) = {1, 2, 3, 4}; Plane Surface(30) = {5}; Line(6) = {5, 6}; Line{6} In Surface{30}; Physical Surface(1) = {30}; Physical Line(101) = {6}; """%(hsize) subdir = "meshes/" _mesh = Mesh() #creat empty mesh object if not os.path.isfile(subdir + meshname + ".xdmf"): if MPI.rank(mpi_comm_world()) == 0: # Create temporary .geo file defining the mesh if os.path.isdir(subdir) == False: os.mkdir(subdir) fgeo = open(subdir + meshname + ".geo", "w") fgeo.writelines(geofile) fgeo.close() # Calling gmsh and dolfin-convert to generate the .xml mesh (as well as a MeshFunction file) try: subprocess.call([ "gmsh", "-2", "-o", subdir + meshname + ".msh", subdir + meshname + ".geo" ]) except OSError: print( "-----------------------------------------------------------------------------" ) print(" Error: unable to generate the mesh using gmsh") print( " Make sure that you have gmsh installed and have added it to your system PATH" ) print( "-----------------------------------------------------------------------------" ) meshconvert.convert2xml(subdir + meshname + ".msh", subdir + meshname + ".xml", "gmsh") # Convert to XDMF MPI.barrier(mpi_comm_world()) mesh = Mesh(subdir + meshname + ".xml") XDMF = XDMFFile(mpi_comm_world(), subdir + meshname + ".xdmf") XDMF.write(mesh) XDMF.read(_mesh) if os.path.isfile(subdir + meshname + "_physical_region.xml") and os.path.isfile( subdir + meshname + "_facet_region.xml"): if MPI.rank(mpi_comm_world()) == 0: mesh = Mesh(subdir + meshname + ".xml") subdomains = MeshFunction( "size_t", mesh, subdir + meshname + "_physical_region.xml") boundaries = MeshFunction( "size_t", mesh, subdir + meshname + "_facet_region.xml") HDF5 = HDF5File(mesh.mpi_comm(), subdir + meshname + "_physical_facet.h5", "w") HDF5.write(mesh, "/mesh") HDF5.write(subdomains, "/subdomains") HDF5.write(boundaries, "/boundaries") print("Finish writting physical_facet to HDF5") if MPI.rank(mpi_comm_world()) == 0: # Keep only the .xdmf mesh #os.remove(subdir + meshname + ".geo") #os.remove(subdir + meshname + ".msh") #os.remove(subdir + meshname + ".xml") # Info print("Mesh completed") # Read the mesh if existing else: XDMF = XDMFFile(mpi_comm_world(), subdir + meshname + ".xdmf") XDMF.read(_mesh) mesh = Mesh('meshes/fracking_hsize' + str(float(hsize)) + '.xml') mesh_fun = MeshFunction( "size_t", mesh, "meshes/fracking_hsize" + str(float(hsize)) + "_facet_region.xml") #plt.figure(1) #plot(mesh, "2D mesh") #plt.interactive(True) ndim = mesh.geometry().dim() # get number of space dimensions #======================================================================================= # Constitutive functions of the damage model #======================================================================================= def a(alpha_): """ Modulation of the elastic stiffness """ if law == "AT1": return (1 - alpha_)**2 elif law == "AT2": return (1 - alpha_)**2 elif law == "ATk": return (1 - w(alpha_)) / (1 + (k - 1) * w(alpha_)) def w(alpha_): """ Local energy dissipation """ if law == "AT1": return alpha_ elif law == "AT2": return alpha_**2 elif law == "ATk": return 1 - (1 - alpha_)**2 #======================================================================================= # strain, stress and strain energy for Isotropic and Amor's model #======================================================================================= def angle_bracket_plus(a): return (a + abs(a)) / 2 def angle_bracket_minus(a): return (a - abs(a)) / 2 #---------------------------------------------------------------------------------------- def g(alpha_): """ degradation function """ return ((1 - alpha_)**2 + k_ell) #---------------------------------------------------------------------------------------- def eps(u_): """ Geometrical strain """ return sym(grad(u_)) def dev_eps(u_): """ """ return eps(u_) - 1 / 3 * tr(eps(u_)) * Identity(ndim) #---------------------------------------------------------------------------------------- def sigma0(u_): """ Application of the sound elasticy tensor on the strain tensor """ Id = Identity(len(u_)) return 2.0 * mu * eps(u_) + lmbda * tr(eps(u_)) * Id def sigma_A(u_, alpha_): """ Stress Model A """ return g(alpha_) * sigma0(u_) def sigma_B(u_, alpha_): """ Stress Model B """ return g(alpha_) * ( (lmbda + 2 / 3 * mu) * (angle_bracket_plus(tr(eps(u_))) * Identity(ndim)) + 2 * mu * dev_eps(u_)) + (lmbda + 2 / 3 * mu) * ( angle_bracket_minus(tr(dev_eps(u_))) * Identity(ndim)) #---------------------------------------------------------------------------------------- def psi_0(u_): """ The strain energy density for a linear isotropic ma- terial """ return 0.5 * lmbda * tr(eps(u_))**2 + mu * eps(u_)**2 def psi_A(u_, alpha_): """ The strain energy density for model A """ return g(alpha_) * psi_0(u_) def psi_B(u_, alpha_): """ The strain energy density for model B """ return g(alpha_) * (0.5 * K * (angle_bracket_plus(tr(dev_eps(u_))))**2 + mu * dev_eps(u_)**2) + 0.5 * K * ( angle_bracket_minus(tr(dev_eps(u_))))**2 #---------------------------------------------------------------------------------------- if not ModelB: # Model A (isotropic model) psi = psi_A sigma = sigma_A else: # Model B (Amor's model) psi = psi_B sigma = sigma_B #======================================================================================= # others definitions #======================================================================================= prefix = "%s-%s-L%s-H%.2f-S%.4f-l%.4f" % (law, Model, L, H, hsize, ell) save_dir = "Fracking_result/" + prefix + "/" if os.path.isdir(save_dir): shutil.rmtree(save_dir) # zero and unit vectors zero_v = Constant((0., ) * ndim) e1 = [Constant([1., 0.]), Constant((1., 0., 0.))][ndim - 2] # Normalization constant for the dissipated energy # to get Griffith surface energy for ell going to zero z = sympy.Symbol("z", positive=True) c_w = float(4 * sympy.integrate(sympy.sqrt(w(z)), (z, 0, 1))) # plane strain or plane stress if not PlaneStress: # plane strain lmbda = E * nu / ((1.0 + nu) * (1.0 - 2.0 * nu)) else: # plane stress lmbda = E * nu / (1.0 - nu**2) # shear modulus mu = E / (2.0 * (1.0 + nu)) #======================================================================================= # Define boundary sets for boundary conditions #======================================================================================= class Right(SubDomain): def inside(self, x, on_boundary): return near((x[0] - L) * 0.01, 0) class Left(SubDomain): def inside(self, x, on_boundary): return near((x[0]) * 0.01, 0.) class Top(SubDomain): def inside(self, x, on_boundary): return near((x[1] - H) * 0.01, 0) class Bottom(SubDomain): def inside(self, x, on_boundary): return near((x[1]) * 0.01, 0) # Initialize sub-domain instances right = Right() left = Left() top = Top() bottom = Bottom() # define meshfunction to identify boundaries by numbers boundaries = FacetFunction("size_t", mesh) boundaries.set_all(9999) right.mark(boundaries, 1) # mark top as 1 left.mark(boundaries, 2) # mark top as 2 top.mark(boundaries, 3) # mark top as 3 bottom.mark(boundaries, 4) # mark bottom as 4 # Define new measure including boundary naming ds = Measure("ds")[boundaries] # left: ds(1), right: ds(2) #======================================================================================= # Variational formulation #======================================================================================= # Create function space for 2D elasticity + Damage V_u = VectorFunctionSpace(mesh, "CG", 1) V_alpha = FunctionSpace(mesh, "CG", 1) # Define the function, test and trial fields u_, u, u_t = Function(V_u), TrialFunction(V_u), TestFunction(V_u) alpha_, alpha, alpha_t = Function(V_alpha), TrialFunction( V_alpha), TestFunction(V_alpha) alpha_0 = interpolate( Constant(0.0), V_alpha) # initial (known) alpha, undamaged everywhere. #======================================================================================= # Dirichlet boundary condition for a traction test boundary #======================================================================================= # Define a time dependent pressure p_b = Expression("t", t=0.0, degree=1) Pressure = interpolate(p_b, V_alpha) # bc - u (imposed displacement) u_R = zero_v u_L = zero_v u_T = Expression(( "0.", "t", ), t=0.0, degree=1) u_B = Expression(( "0.", "-t", ), t=0.0, degree=1) Gamma_u_0 = DirichletBC(V_u, u_R, boundaries, 1) Gamma_u_1 = DirichletBC(V_u, u_L, boundaries, 2) Gamma_u_2 = DirichletBC(V_u, u_T, boundaries, 3) Gamma_u_3 = DirichletBC(V_u, u_B, boundaries, 4) bc_u = [Gamma_u_0, Gamma_u_1, Gamma_u_2, Gamma_u_3] # bc - alpha (zero damage) Gamma_alpha_0 = DirichletBC(V_alpha, 0.0, boundaries, 1) Gamma_alpha_1 = DirichletBC(V_alpha, 0.0, boundaries, 2) Gamma_alpha_2 = DirichletBC(V_alpha, 0.0, boundaries, 3) Gamma_alpha_3 = DirichletBC(V_alpha, 0.0, boundaries, 4) Gamma_alpha_4 = DirichletBC(V_alpha, 1.0, mesh_fun, 101) bc_alpha = [ Gamma_alpha_0, Gamma_alpha_1, Gamma_alpha_2, Gamma_alpha_3, Gamma_alpha_4 ] #==================================================================================== # Define problem and solvers #==================================================================================== elastic_energy = psi(u_, alpha_) * dx external_work = dot(body_force, u_) * dx if not WheelerApproach: # Bourdin approach, 2012 , SPE 159154, equation (5) pressurized_energy = Pressure * inner(u_, grad(alpha_)) * dx else: # M.F. Wheeler et al., CAMAME, 2014, eqution (4) pressurized_energy = -(biot - 1.) * ( (1. - alpha_)**2 * Pressure * div(u_)) * dx + dot( (1 - alpha_)**2 * grad(Pressure), u_) * dx dissipated_energy = Gc / float(c_w) * ( w(alpha_) / ell + ell * inner(grad(alpha_), grad(alpha_))) * dx total_energy = elastic_energy + dissipated_energy + pressurized_energy - external_work # Residual and Jacobian of elasticity problem Du_total_energy = derivative(total_energy, u_, u_t) J_u = derivative(Du_total_energy, u_, u) # Residual and Jacobian of damage problem Dalpha_total_energy = derivative(total_energy, alpha_, alpha_t) J_alpha = derivative(Dalpha_total_energy, alpha_, alpha) # Variational problem for the displacement problem_u = NonlinearVariationalProblem(Du_total_energy, u_, bc_u, J_u) # Variational problem for the damage (non-linear to use variational inequality solvers of petsc) # Define the minimisation problem by using OptimisationProblem class class DamageProblem(OptimisationProblem): def __init__(self): OptimisationProblem.__init__(self) # Objective function def f(self, x): alpha_.vector()[:] = x return assemble(total_energy) # Gradient of the objective function def F(self, b, x): alpha_.vector()[:] = x assemble(Dalpha_total_energy, tensor=b) # Hessian of the objective function def J(self, A, x): alpha_.vector()[:] = x assemble(J_alpha, tensor=A) # Create the PETScTAOSolver problem_alpha = DamageProblem() # Parse (PETSc) parameters parameters.parse() # Set up the solvers solver_u = NonlinearVariationalSolver(problem_u) prm = solver_u.parameters prm["newton_solver"]["absolute_tolerance"] = 1E-8 prm["newton_solver"]["relative_tolerance"] = 1E-7 prm["newton_solver"]["maximum_iterations"] = 25 prm["newton_solver"]["relaxation_parameter"] = 1.0 prm["newton_solver"]["preconditioner"] = "default" prm["newton_solver"]["linear_solver"] = "mumps" #set_log_level(PROGRESS) solver_alpha = PETScTAOSolver() alpha_lb = interpolate(Expression("0.", degree=1), V_alpha) # lower bound, set to 0 alpha_ub = interpolate(Expression("1.", degree=1), V_alpha) # upper bound, set to 1 for bc in bc_alpha: bc.apply(alpha_lb.vector()) for bc in bc_alpha: bc.apply(alpha_ub.vector()) #======================================================================================= # To store results #======================================================================================= results = [] file_alpha = File(save_dir + "/alpha.pvd") # use .pvd if .xdmf is not working file_u = File(save_dir + "/u.pvd") # use .pvd if .xdmf is not working #======================================================================================= # Solving at each timestep #======================================================================================= load_multipliers = np.linspace(pressure_min, pressure_max, pressure_steps) energies = np.zeros((len(load_multipliers), 5)) iterations = np.zeros((len(load_multipliers), 2)) forces = np.zeros((len(load_multipliers), 2)) for (i_t, t) in enumerate(load_multipliers): print "\033[1;32m--- Time step %d: t = %g ---\033[1;m" % (i_t, t) #u_T.t = t*ut #u_B.t = t*ut p_b.t = t Pressure.assign(interpolate(p_b, V_alpha)) # Alternate mininimization # Initialization iter = 1 err_alpha = 1 # Iterations while err_alpha > tolerance and iter < max_iterations: # solve elastic problem solver_u.solve() # solve damage problem solver_alpha.solve(problem_alpha, alpha_.vector(), alpha_lb.vector(), alpha_ub.vector()) # test error err_alpha = (alpha_.vector() - alpha_0.vector()).norm('linf') # monitor the results if mpi_comm_world().rank == 0: print "Iteration: %2d, Error: %2.8g, alpha_max: %.8g" % ( iter, err_alpha, alpha_.vector().max()) # update iteration alpha_0.vector()[:] = alpha_.vector() iter += 1 # Update the lower bound to account for the irreversibility alpha_lb.vector()[:] = alpha_.vector() ## plot the damage fied #plt.figure(2) #plot(alpha_, range_min = 0., range_max = 1., key = "alpha", title = "Damage at loading %.4f"%(ut*t)) #plt.show() #plt.interactive(True) #======================================================================================= # Some post-processing #======================================================================================= # Save number of iterations for the time step iterations[i_t] = np.array([t, iter]) # Calculate the energies elastic_energy_value = assemble(elastic_energy) dissipated_energy_value = assemble(dissipated_energy) pressurized_energy_value = assemble(pressurized_energy) if mpi_comm_world().rank == 0: print("\nEnd of timestep %d with load multiplier %g" % (i_t, t)) print("AM: Iteration number: %i - Elastic_energy: %.3e" % (i_t, elastic_energy_value)) print("AM: Iteration number: %i - Dissipated_energy: %.3e" % (i_t, dissipated_energy_value)) print("AM: Iteration number: %i - pressurized_energy: %.3e" % (i_t, pressurized_energy_value)) print "\033[1;32m--------------------------------------------------------------\033[1;m" energies[i_t] = np.array([ t, elastic_energy_value, dissipated_energy_value, pressurized_energy_value, elastic_energy_value + dissipated_energy_value + pressurized_energy_value ]) # Calculate the axial force resultant forces[i_t] = np.array( [t, assemble(inner(sigma(u_, alpha_) * e1, e1) * ds(1))]) # Dump solution to file file_alpha << (alpha_, t) file_u << (u_, t) # Save some global quantities as a function of the time np.savetxt(save_dir + '/energies.txt', energies) np.savetxt(save_dir + '/forces.txt', forces) np.savetxt(save_dir + '/iterations.txt', iterations) #======================================================================================= # Save alpha and displacement data #======================================================================================= output_file_u = HDF5File(mpi_comm_world(), save_dir + "u_4_opening.h5", "w") # self.save_dir + "uO.h5" output_file_u.write(u_, "solution") output_file_u.close() output_file_alpha = HDF5File(mpi_comm_world(), save_dir + "alpha_4_opening.h5", "w") output_file_alpha.write(alpha_, "solution") output_file_alpha.close()
def Fracking(hsize, mu_dynamic, pressure_steps,j): #======================================================================================= # Input date #======================================================================================= # Geometry L = 200.0 # length H = 200.0 # height #hsize= 0.5 # target cell size meshname="fracking_hsize%g" % (hsize) # Stopping criteria for the alternate minimization max_iterations = 200 tolerance = 1.0e-5 # Loading pressure_min = 0. # load multiplier min value pressure_max = 5. # load multiplier max value #pressure_steps = 20 # number of time steps #==================================================================================== # To define pressure field #==================================================================================== f = Constant(0) kappa = 1.e-12 M_biot = 1. #mu_dynamic = 1. nu =0.34 E=6.e3 G =E/(2.*(1.+nu)) c = (2.*G*(1.-nu)/(1.-2.*nu))*kappa/mu_dynamic print c print G #t_stop = hsize**2 *mu_dynamic/(kappa*M_biot) # non dimensional time (s) #DeltaT=1.e-4#COE*hsize**2 *mu_dynamic/(kappa*M_biot) DeltaT=1e-3#hsize**2/c print DeltaT #Q=5.e-4 #======================================================================================= # Geometry and mesh generation #======================================================================================= # Generate a XDMF/HDF5 based mesh from a Gmsh string geofile = \ """ lc = DefineNumber[ %g, Name "Parameters/lc" ]; H = 200.; L = 200.; r=10.; a=10.; Point(1) = {0, 0, 0, 5*lc}; Point(2) = {L, 0, 0, 5*lc}; Point(3) = {L, H, 0, 5*lc}; Point(4) = {0, H, 0, 5*lc}; Point(5) = {L/2, H/2+r+a, 0, 0.1*lc}; Point(6) = {L/2, H/2+r, 0, 0.1*lc}; Point(7) = {L/2, H/2-r, 0, 0.1*lc}; Point(8) = {L/2, H/2-r-a, 0, 0.1*lc}; Point(9) = {L/2, H/2, 0, 0.1*lc}; Line(1) = {1, 2}; Line(2) = {2, 3}; Line(3) = {3, 4}; Line(4) = {4, 1}; Line Loop(5) = {1, 2, 3, 4}; Circle(8) = {6, 9, 7}; Circle(9) = {7, 9, 6}; Line Loop(11) = {8, 9}; Plane Surface(30) = {5,11}; Line(6) = {5, 6}; Line{6} In Surface{30}; Line(7) = {7, 8}; Line{7} In Surface{30}; Physical Surface(1) = {30}; Physical Line(101) = {6}; Physical Line(102) = {7}; """%(hsize) subdir = "meshes/" _mesh = Mesh() #creat empty mesh object if not os.path.isfile(subdir + meshname + ".xdmf"): if MPI.rank(mpi_comm_world()) == 0: # Create temporary .geo file defining the mesh if os.path.isdir(subdir) == False: os.mkdir(subdir) fgeo = open(subdir + meshname + ".geo", "w") fgeo.writelines(geofile) fgeo.close() # Calling gmsh and dolfin-convert to generate the .xml mesh (as well as a MeshFunction file) try: subprocess.call(["gmsh", "-2", "-o", subdir + meshname + ".msh", subdir + meshname + ".geo"]) except OSError: print("-----------------------------------------------------------------------------") print(" Error: unable to generate the mesh using gmsh") print(" Make sure that you have gmsh installed and have added it to your system PATH") print("-----------------------------------------------------------------------------") meshconvert.convert2xml(subdir + meshname + ".msh", subdir + meshname + ".xml", "gmsh") # Convert to XDMF MPI.barrier(mpi_comm_world()) mesh = Mesh(subdir + meshname + ".xml") XDMF = XDMFFile(mpi_comm_world(), subdir + meshname + ".xdmf") XDMF.write(mesh) XDMF.read(_mesh) if os.path.isfile(subdir + meshname + "_physical_region.xml") and os.path.isfile(subdir + meshname + "_facet_region.xml"): if MPI.rank(mpi_comm_world()) == 0: mesh = Mesh(subdir + meshname + ".xml") subdomains = MeshFunction("size_t", mesh, subdir + meshname + "_physical_region.xml") boundaries = MeshFunction("size_t", mesh, subdir + meshname + "_facet_region.xml") HDF5 = HDF5File(mesh.mpi_comm(), subdir + meshname + "_physical_facet.h5", "w") HDF5.write(mesh, "/mesh") HDF5.write(subdomains, "/subdomains") HDF5.write(boundaries, "/boundaries") print("Finish writting physical_facet to HDF5") if MPI.rank(mpi_comm_world()) == 0: # Keep only the .xdmf mesh #os.remove(subdir + meshname + ".geo") #os.remove(subdir + meshname + ".msh") #os.remove(subdir + meshname + ".xml") # Info print("Mesh completed") # Read the mesh if existing else: XDMF = XDMFFile(mpi_comm_world(), subdir + meshname + ".xdmf") XDMF.read(_mesh) mesh = Mesh('meshes/fracking_hsize'+str(float(hsize))+'.xml') #mesh_fun = MeshFunction("size_t", mesh,"meshes/fracking_hsize"+str(float(hsize))+"_facet_region.xml") #plt.figure(1) #plot(mesh, "2D mesh") #plt.interactive(False) ndim = mesh.geometry().dim() # get number of space dimensions #======================================================================================= # Constitutive functions of the damage model #======================================================================================= def a(alpha_): """ Modulation of the elastic stiffness """ if law == "AT1": return (1-alpha_)**2 elif law == "AT2": return (1-alpha_)**2 elif law == "ATk": return (1-w(alpha_))/(1+(k-1)*w(alpha_)) def w(alpha_): """ Local energy dissipation """ if law == "AT1": return alpha_ elif law == "AT2": return alpha_**2 elif law == "ATk": return 1-(1-alpha_)**2 #======================================================================================= # strain, stress and strain energy for Isotropic and Amor's model #======================================================================================= #======================================================================================= # others definitions #======================================================================================= prefix = "L%s-H%.2f-S%.4f-mu%s"%(L,H,hsize, j) save_dir = "Fracking_result/" + prefix + "/" if os.path.isdir(save_dir): shutil.rmtree(save_dir) # zero and unit vectors zero_v = Constant((0.,)*ndim) e1 = [Constant([1.,0.]),Constant((1.,0.,0.))][ndim-2] #======================================================================================= # Define boundary sets for boundary conditions #======================================================================================= class Right(SubDomain): def inside(self, x, on_boundary): return near((x[0] - L) * 0.01, 0) class Left(SubDomain): def inside(self, x, on_boundary): return near((x[0]) * 0.01, 0.) class Top(SubDomain): def inside(self, x, on_boundary): return near((x[1] - H) * 0.01, 0) class Bottom(SubDomain): def inside(self, x, on_boundary): return near((x[1]) * 0.01, 0) class Void(SubDomain): def inside(self, x, on_boundary): #return x[0] <= 2.5 and x[0] >= 1.5 and x[1] <= 2.5 and x[1] >= 1.5 and on_boundary H = 200. L = 200. radius = 10. return x[0] <= L/2+1.5*radius and x[0] >= L/2-1.5*radius and x[1] <= H/2+1.5*radius and x[1] >= H/2-1.5*radius and on_boundary # Initialize sub-domain instances right=Right() left=Left() top=Top() bottom=Bottom() void=Void() # define meshfunction to identify boundaries by numbers boundaries = FacetFunction("size_t", mesh) boundaries.set_all(9999) right.mark(boundaries, 1) # mark top as 1 left.mark(boundaries, 2) # mark top as 2 top.mark(boundaries, 3) # mark top as 3 bottom.mark(boundaries, 4) # mark bottom as 4 void.mark(boundaries, 5) # mark void as 5 # Define new measure including boundary naming #ds = Measure("ds")[boundaries] # left: ds(1), right: ds(2) ds=Measure('ds', domain=mesh, subdomain_data=boundaries) #======================================================================================= # Variational formulation #======================================================================================= # Create function space for 2D elasticity + Damage V_p = FunctionSpace(mesh, "CG", 1) # Define the function, test and trial fields P_, P, P_t= Function(V_p), TrialFunction(V_p), TestFunction(V_p), P_0 = interpolate(Expression("0.0", degree=1), V_p) #======================================================================================= # Dirichlet boundary condition for a traction test boundary #======================================================================================= ## bc - P (imposed pressure) P_C = Expression("p", p=0.0, degree=1) Gamma_P_0 = DirichletBC(V_p, 0.0, boundaries, 1) Gamma_P_1 = DirichletBC(V_p, 0.0, boundaries, 2) Gamma_P_2 = DirichletBC(V_p, 0.0, boundaries, 3) Gamma_P_3 = DirichletBC(V_p, 0.0, boundaries, 4) Gamma_P_4 = DirichletBC(V_p, 1.0, boundaries, 5) bc_P = [ Gamma_P_0, Gamma_P_1, Gamma_P_2, Gamma_P_3, Gamma_P_4] #==================================================================================== # Define problem and solvers #==================================================================================== Pressure = P_*P*dx +DeltaT*c*inner(nabla_grad(P), nabla_grad(P_))*dx-(P_0 +DeltaT*f)*P*dx#-DeltaT*Q*P*ds(1) # Wang et. al 2017 eq(8) #Jacobian of pressure problem J_p = derivative(Pressure, P_, P_t) problem_pressure = NonlinearVariationalProblem(Pressure, P_, bc_P, J=J_p) solver_pressure = NonlinearVariationalSolver(problem_pressure) #======================================================================================= # To store results #======================================================================================= results = [] file_p = File(save_dir+"/p.pvd") #======================================================================================= # Solving at each timestep #======================================================================================= load_multipliers = np.linspace(pressure_min,pressure_max,pressure_steps) iteration = 0; err_P = 1; # Iterations while err_P>tolerance and iteration<max_iterations: # solve pressure problem solver_pressure.solve() err_P = (P_.vector() - P_0.vector()).norm('linf') if mpi_comm_world().rank == 0: print "Iteration: %2d, pressure_Error: %2.8g, P_max: %.8g" %(iteration, err_P, P_.vector().max()) iteration += 1 P_0.vector()[:] = P_.vector() file_p << P_
def Fracking(E, nu, hsize, ell, law, ModelB, ka, kb, k, mu_dynamic): #======================================================================================= # Input date #======================================================================================= # Geometry L = 200. # length H = 200. # height #hsize= 0.8 # target cell size radius = Constant(10.) meshname = "fracking_hsize%g" % (hsize) # Material constants #E = 6.e3 # Young modulus #nu = 0.34 # Poisson ratio PlaneStress = False # Stopping criteria for the alternate minimization max_iterations = 200 tolerance = 1.0e-8 # Loading body_force = Constant((0., 0.)) # bulk load pressure_min = 0. # load multiplier min value pressure_max = 1. # load multiplier max value pressure_steps = 100 # number of time steps #==================================================================================== # To define pressure field #==================================================================================== biot = 1.0 kappa = 1.e-12 #is the permeability of the rock #m^2 #mu_dynamic= 0.79e-9 #is the dynamic viscosity of the fluid #MPa f = Constant(0) G = E / (2. * (1. + nu)) c = (2. * G * (1. - nu) / (1. - 2. * nu)) * kappa / mu_dynamic DeltaT = 1e-3 #hsize**2 *mu_dynamic/(kappa*M_biot) # non dimensional time (s) #======================================================================================= # Geometry and mesh generation #======================================================================================= # Generate a XDMF/HDF5 based mesh from a Gmsh string geofile = \ """ lc = DefineNumber[ %g, Name "Parameters/lc" ]; H = 200.; L = 200.; r=10.; a=10.; Point(1) = {0, 0, 0, 5*lc}; Point(2) = {L, 0, 0, 5*lc}; Point(3) = {L, H, 0, 5*lc}; Point(4) = {0, H, 0, 5*lc}; Point(5) = {L/2, H/2+r+a, 0, 0.1*lc}; Point(6) = {L/2, H/2+r, 0, 0.1*lc}; Point(7) = {L/2, H/2-r, 0, 0.1*lc}; Point(8) = {L/2, H/2-r-a, 0, 0.1*lc}; Point(9) = {L/2, H/2, 0, 0.1*lc}; Line(1) = {1, 2}; Line(2) = {2, 3}; Line(3) = {3, 4}; Line(4) = {4, 1}; Line Loop(5) = {1, 2, 3, 4}; Circle(8) = {6, 9, 7}; Circle(9) = {7, 9, 6}; Line Loop(11) = {8, 9}; Plane Surface(30) = {5,11}; Line(6) = {5, 6}; Line{6} In Surface{30}; Line(7) = {7, 8}; Line{7} In Surface{30}; Physical Surface(1) = {30}; Physical Line(101) = {6}; Physical Line(102) = {7}; """%(hsize) subdir = "meshes/" _mesh = Mesh() #creat empty mesh object if not os.path.isfile(subdir + meshname + ".xdmf"): if MPI.rank(mpi_comm_world()) == 0: # Create temporary .geo file defining the mesh if os.path.isdir(subdir) == False: os.mkdir(subdir) fgeo = open(subdir + meshname + ".geo", "w") fgeo.writelines(geofile) fgeo.close() # Calling gmsh and dolfin-convert to generate the .xml mesh (as well as a MeshFunction file) try: subprocess.call([ "gmsh", "-2", "-o", subdir + meshname + ".msh", subdir + meshname + ".geo" ]) except OSError: print( "-----------------------------------------------------------------------------" ) print(" Error: unable to generate the mesh using gmsh") print( " Make sure that you have gmsh installed and have added it to your system PATH" ) print( "-----------------------------------------------------------------------------" ) meshconvert.convert2xml(subdir + meshname + ".msh", subdir + meshname + ".xml", "gmsh") # Convert to XDMF MPI.barrier(mpi_comm_world()) mesh = Mesh(subdir + meshname + ".xml") XDMF = XDMFFile(mpi_comm_world(), subdir + meshname + ".xdmf") XDMF.write(mesh) XDMF.read(_mesh) if os.path.isfile(subdir + meshname + "_physical_region.xml") and os.path.isfile( subdir + meshname + "_facet_region.xml"): if MPI.rank(mpi_comm_world()) == 0: mesh = Mesh(subdir + meshname + ".xml") subdomains = MeshFunction( "size_t", mesh, subdir + meshname + "_physical_region.xml") boundaries = MeshFunction( "size_t", mesh, subdir + meshname + "_facet_region.xml") HDF5 = HDF5File(mesh.mpi_comm(), subdir + meshname + "_physical_facet.h5", "w") HDF5.write(mesh, "/mesh") HDF5.write(subdomains, "/subdomains") HDF5.write(boundaries, "/boundaries") print("Finish writting physical_facet to HDF5") if MPI.rank(mpi_comm_world()) == 0: # Keep only the .xdmf mesh #os.remove(subdir + meshname + ".geo") #os.remove(subdir + meshname + ".msh") #os.remove(subdir + meshname + ".xml") # Info print("Mesh completed") # Read the mesh if existing else: XDMF = XDMFFile(mpi_comm_world(), subdir + meshname + ".xdmf") XDMF.read(_mesh) mesh = Mesh('meshes/fracking_hsize' + str(float(hsize)) + '.xml') mesh_fun = MeshFunction( "size_t", mesh, "meshes/fracking_hsize" + str(float(hsize)) + "_facet_region.xml") ndim = mesh.geometry().dim() # get number of space dimensions #======================================================================================= # strain, stress and strain energy for Isotropic and Amor's model #======================================================================================= def eps(u_): """ Geometrical strain """ return sym(grad(u_)) #---------------------------------------------------------------------------------------- def sigma0(u_): """ Application of the sound elasticy tensor on the strain tensor """ Id = Identity(len(u_)) return 2.0 * mu * eps(u_) + lmbda * tr(eps(u_)) * Id #---------------------------------------------------------------------------------------- def psi_0(u_): """ The strain energy density for a linear isotropic ma- terial """ return 0.5 * lmbda * tr(eps(u_))**2 + mu * eps(u_)**2 #======================================================================================= # others definitions #======================================================================================= prefix = "%s-L%s-H%.2f-S%.4f-l%.4f-ka%s-kb%s-steps%s,mu%s" % ( law, L, H, hsize, ell, ka, kb, pressure_steps, k) save_dir = "Fracking_result/" + prefix + "/" if os.path.isdir(save_dir): shutil.rmtree(save_dir) # zero and unit vectors zero_v = Constant((0., ) * ndim) e1 = [Constant([1., 0.]), Constant((1., 0., 0.))][ndim - 2] e2 = [Constant([0., 1.]), Constant((0., 1., 0.))][ndim - 2] # plane strain or plane stress if not PlaneStress: # plane strain lmbda = E * nu / ((1.0 + nu) * (1.0 - 2.0 * nu)) else: # plane stress lmbda = E * nu / (1.0 - nu**2) # shear modulus mu = E / (2.0 * (1.0 + nu)) #======================================================================================= # Define boundary sets for boundary conditions #======================================================================================= class Right(SubDomain): def inside(self, x, on_boundary): return near((x[0] - L) * 0.01, 0) class Left(SubDomain): def inside(self, x, on_boundary): return near((x[0]) * 0.01, 0.) class Top(SubDomain): def inside(self, x, on_boundary): return near((x[1] - H) * 0.01, 0) class Bottom(SubDomain): def inside(self, x, on_boundary): return near((x[1]) * 0.01, 0) class Void(SubDomain): def inside(self, x, on_boundary): #return x[0] <= 2.5 and x[0] >= 1.5 and x[1] <= 2.5 and x[1] >= 1.5 and on_boundary H = 200. L = 200. radius = 10. return x[0] <= L / 2 + 1.5 * radius and x[ 0] >= L / 2 - 1.5 * radius and x[ 1] <= H / 2 + 1.5 * radius and x[ 1] >= H / 2 - 1.5 * radius and on_boundary # Initialize sub-domain instances right = Right() left = Left() top = Top() bottom = Bottom() void = Void() # define meshfunction to identify boundaries by numbers boundaries = FacetFunction("size_t", mesh) boundaries.set_all(9999) right.mark(boundaries, 1) # mark top as 1 left.mark(boundaries, 2) # mark top as 2 top.mark(boundaries, 3) # mark top as 3 bottom.mark(boundaries, 4) # mark bottom as 4 void.mark(boundaries, 5) # mark void as 5 # Define new measure including boundary naming ds = Measure("ds")[boundaries] # left: ds(1), right: ds(2) #======================================================================================= # Variational formulation #======================================================================================= # Create function space for 2D elasticity + Damage V_u = VectorFunctionSpace(mesh, "CG", 1) V_p = FunctionSpace(mesh, "CG", 1) # Define the function, test and trial fields u_, u, u_t = Function(V_u), TrialFunction(V_u), TestFunction(V_u) P_, P, P_t = Function(V_p), TrialFunction(V_p), TestFunction(V_p), P_0 = interpolate(Expression("0.0", degree=1), V_p) u_0 = interpolate(zero_v, V_u) ############################################################################################################## # read the displacement data from a plain strain elasticity problem imposed by in-situ stress prefix_stress = "L%s-H%.2f-%s-%g" % (L, H, 'DispBC', hsize) save_dir_stress = "Elasticity_result/" + prefix_stress + "/" # To read the solution for u_ u_imported = Function(V_u) input_file_u = HDF5File(mesh.mpi_comm(), save_dir_stress + "u_4_bc.h5", "r") input_file_u.read(u_imported, "solution") input_file_u.close() class MyExpr(Expression): def eval(self, values, x): point = (x[0], x[1]) values[0] = u_imported(point)[0] values[1] = u_imported(point)[1] def value_shape(self): return (2, ) my_expr = MyExpr(degree=1) ############################################################################################################## #======================================================================================= # Dirichlet boundary condition for a traction test boundary #======================================================================================= Gamma_u_0 = DirichletBC(V_u, my_expr, boundaries, 1) Gamma_u_1 = DirichletBC(V_u, my_expr, boundaries, 2) Gamma_u_2 = DirichletBC(V_u, my_expr, boundaries, 3) Gamma_u_3 = DirichletBC(V_u, my_expr, boundaries, 4) bc_u = [Gamma_u_0, Gamma_u_1, Gamma_u_2, Gamma_u_3] ## bc - P (imposed pressure) P_C = Expression("p", p=0.0, degree=1) Gamma_P_0 = DirichletBC(V_p, 0.0, boundaries, 1) Gamma_P_1 = DirichletBC(V_p, 0.0, boundaries, 2) Gamma_P_2 = DirichletBC(V_p, 0.0, boundaries, 3) Gamma_P_3 = DirichletBC(V_p, 0.0, boundaries, 4) #Gamma_P_4 = DirichletBC(V_p, P_C, mesh_fun, 101) Gamma_P_4 = DirichletBC(V_p, 1.0, boundaries, 5) bc_P = [Gamma_P_0, Gamma_P_1, Gamma_P_2, Gamma_P_3, Gamma_P_4] #==================================================================================== # Define problem and solvers #==================================================================================== Pressure = P_ * P * dx + DeltaT * c * inner(nabla_grad(P), nabla_grad( P_)) * dx - (P_0 + DeltaT * f) * P * dx #-DeltaT*Q*P*ds(5) # Wang et. al 2017 eq(8) #------------------------------------------------------------------------------------ elastic_energy = psi_0(u_) * dx - biot * P_ * div(u_) * dx external_work = dot( body_force, u_) * dx #+ dot(sigma_R, u_)*ds(1)+ dot(sigma_T, u_)*ds(3) total_energy = elastic_energy + external_work # Residual and Jacobian of elasticity problem Du_total_energ = derivative(total_energy, u_, u_t) J_u = derivative(Du_total_energ, u_, u) #Jacobian of pressure problem J_p = derivative(Pressure, P_, P_t) # Variational problem for the displacement problem_u = NonlinearVariationalProblem(Du_total_energ, u_, bc_u, J_u) # Parse (PETSc) parameters parameters.parse() # Set up the solvers solver_u = NonlinearVariationalSolver(problem_u) prm = solver_u.parameters prm["newton_solver"]["absolute_tolerance"] = 1E-6 prm["newton_solver"]["relative_tolerance"] = 1E-6 prm["newton_solver"]["maximum_iterations"] = 200 prm["newton_solver"]["relaxation_parameter"] = 1.0 prm["newton_solver"]["preconditioner"] = "default" prm["newton_solver"]["linear_solver"] = "mumps" problem_pressure = NonlinearVariationalProblem(Pressure, P_, bc_P, J=J_p) solver_pressure = NonlinearVariationalSolver(problem_pressure) #======================================================================================= # To store results #======================================================================================= results = [] file_u = File(save_dir + "/u.pvd") # use .pvd if .xdmf is not working file_p = File(save_dir + "/p.pvd") file_stress_tt = File(save_dir + "/stress_tt.pvd") file_stress_rr = File(save_dir + "/stress_rr.pvd") file_stress_rt = File(save_dir + "/stress_rt.pvd") #======================================================================================= # Solving at each timestep #======================================================================================= iteration = 0 iter = 0 err_P = 1 err_alpha = 1 # Iterations while iter < pressure_steps: # solve pressure problem solver_pressure.solve() err_P = (P_.vector() - P_0.vector()).norm('linf') if mpi_comm_world().rank == 0: print "Iteration: %2d, pressure_Error: %2.8g, P_max: %.8g" % ( iter, err_P, P_.vector().max()) P_0.vector()[:] = P_.vector() # solve elastic problem solver_u.solve() if mpi_comm_world().rank == 0: print "elastic iteration: %2d" % (iter) u_0.vector()[:] = u_.vector() iter += 1 # Dump solution to file file_u << u_ file_p << P_ stress_tt = project(sigma0(u_)[0, 0], V_p) file_stress_tt << stress_tt stress_rr = project(sigma0(u_)[1, 1], V_p) file_stress_rr << stress_rr stress_rt = project(sigma0(u_)[0, 1], V_p) file_stress_rt << stress_rt
def create_patches(box=np.array([0, 0, 0, 1, 1, 1]), patch_num=3, patch_nums=None, alpha=1.25, beta=2.0, max_resolution=0.5, num=6, create_inclusions=False, skip_patches=[], prefix='test', logger=None, ldomain=False, corner_refine=3, hole=False, hole_radius=None, layers=1, max_refines=1, elem_per_layer=3): if logger is not None: info = logger.info else: info = print basedim = 3 low = box[:basedim].copy() high = box[basedim:].copy() lengths = high - low diameter = np.sqrt(lengths @ lengths) myeps = sa_utils.myeps * diameter center = (high + low) * .5 info('low {:s}, high {:s}, lengths {:s}, center {:s}, diameter {:.2e}'. format(str(low), str(high), str(lengths), str(center), diameter)) layer_bricks = [] layer_hz = lengths[2] / layers layer_low = np.array( [low[0] - lengths[0], low[1] - lengths[1], low[2] - lengths[2]]) layer_high = np.array( [low[0] + lengths[0], low[1] + lengths[1], low[2] + 2 * lengths[2]]) for ii in range(layers - 1): for jj in range(1, elem_per_layer + 1): layer_bricks.append( OrthoBrick( Pnt(*layer_low), Pnt(low[0] + lengths[0], low[1] + lengths[1], low[2] + (ii + jj * 1. / elem_per_layer) * layer_hz))) info('layer [{:d}/{:d}], {:s}, {:s}'.format( ii, layers, str(layer_low), str( np.array([ low[0] + lengths[0], low[1] + lengths[1], low[2] + ii * layer_hz ])))) for jj in range(1, elem_per_layer): layer_bricks.append( OrthoBrick( Pnt(*layer_low), Pnt( low[0] + lengths[0], low[1] + lengths[1], low[2] + (layers - 1 + jj * 1. / elem_per_layer) * layer_hz))) layer_bricks.append(OrthoBrick(Pnt(*layer_low), Pnt(*layer_high))) sublayers = len(layer_bricks) info('layer [{:d}/{:d}], {:s}, {:s}'.format(layers, layers, str(layer_low), str(layer_high))) info('{:d} layers, {:d} sublayers, {:d} bricks'.format( layers, sublayers, len(layer_bricks))) bc_dict = dict() left = dolfin.AutoSubDomain( lambda xx, on: on and dolfin.near(xx[0], low[0], eps=myeps)) bc_dict[1] = left right = dolfin.AutoSubDomain( lambda xx, on: on and dolfin.near(xx[0], high[0], eps=myeps)) bc_dict[2] = right front = dolfin.AutoSubDomain( lambda xx, on: on and dolfin.near(xx[1], low[1], eps=myeps)) bc_dict[3] = front back = dolfin.AutoSubDomain( lambda xx, on: on and dolfin.near(xx[1], high[1], eps=myeps)) bc_dict[4] = back bottom = dolfin.AutoSubDomain( lambda xx, on: on and dolfin.near(xx[2], low[2], eps=myeps)) bc_dict[5] = bottom top = dolfin.AutoSubDomain( lambda xx, on: on and dolfin.near(xx[2], high[2], eps=myeps)) bc_dict[6] = top border = dolfin.AutoSubDomain(lambda xx, on: on) if ldomain: corner_lr = dolfin.AutoSubDomain( lambda xx, on: on and (xx >= center - myeps).all() and dolfin.near( xx[0], center[0], eps=myeps)) bc_dict[7] = corner_lr corner_fb = dolfin.AutoSubDomain( lambda xx, on: on and (xx >= center - myeps).all() and dolfin.near( xx[1], center[1], eps=myeps)) bc_dict[8] = corner_fb corner_bt = dolfin.AutoSubDomain( lambda xx, on: on and (xx >= center - myeps).all() and dolfin.near( xx[2], center[2], eps=myeps)) bc_dict[9] = corner_bt corner_subdomains = [] corner_close = 0.1 * diameter + myeps for ii in range(corner_refine): corner_subdomains.append( dolfin.AutoSubDomain( (lambda what: lambda xx, on: np.sqrt(xx @ xx) < what )(corner_close))) corner_close *= 0.5 if create_inclusions and num: info('random inclusions') if num: number = num * num * num info('n = ' + str(number)) inc_radius = 0.5 / num info('r = ' + str(inc_radius)) nodes = [] radii = [] rnd_low = low - 0.5 * inc_radius rnd_high = high + 0.5 * inc_radius width = rnd_high - rnd_low while (len(nodes) < number): notok = True while (notok): new = rnd.rand(3) * width + rnd_low radius = (0.5 + rnd.rand()) * inc_radius notok = False for old, rr in zip(nodes, radii): diff = new - old if np.sqrt(diff.dot(diff)) < 1.3 * (radius + rr): notok = True break nodes.append(new.copy()) radii.append(radius) nodes = np.array(nodes) radii = np.array(radii) info('found locations for ' + str(len(nodes)) + ' inclusions') np.savetxt(prefix + '/' + prefix + '_inclusions.csv', np.hstack((nodes, radii.reshape(len(nodes), 1))), fmt='%.15e', delimiter=', ') del nodes, radii, number, inc_radius nohole_whole = OrthoBrick(Pnt(*low), Pnt(*high)) if ldomain is True: nohole_whole = nohole_whole - OrthoBrick( Pnt(*center), Pnt(*(center + 2 * (high - center)))) if num: data = np.loadtxt(prefix + '/' + prefix + '_inclusions.csv', delimiter=', ') number = len(data) else: number = 0 if number: nodes = data[:, :3] radii = data[:, 3] inclusions = Sphere(Pnt(*nodes[0]), radii[0]) for kk in range(1, len(nodes)): inclusions += Sphere(Pnt(*nodes[kk]), radii[kk]) nohole_matrix = nohole_whole - inclusions nohole_incs = nohole_whole * inclusions if hole_radius is not None: hole = True if hole: if hole_radius is None: hole_radius = lengths[1] / 9. near_hole = dolfin.AutoSubDomain(lambda xx, on: on and np.sqrt( (xx[0] - center[0]) * (xx[0] - center[0]) + (xx[1] - center[1]) * (xx[1] - center[1])) < hole_radius + 1e4 * myeps) bc_dict[10] = near_hole if patch_nums is None: hh = lengths[0] / float(patch_num) patch_nums = np.array(np.ceil(lengths / hh), dtype=int) hs = lengths / patch_nums hs_alpha = hs * alpha * 0.5 hs_beta = hs_alpha * beta patches = [] patches_ext = [] for kk in range(patch_nums[2]): pt_z = low[0] + (0.5 + kk) * hs[2] for jj in range(patch_nums[1]): pt_y = low[1] + (0.5 + jj) * hs[1] for ii in range(patch_nums[0]): pt_x = low[2] + (0.5 + ii) * hs[0] pt_center = np.array([pt_x, pt_y, pt_z]) pt_low = pt_center - hs_alpha if ldomain and (p_low >= center - myeps).all(): print('[{:d}, {:d}, {:d}] skipped'.format(ii, jj, kk)) continue patches.append( OrthoBrick(Pnt(*(pt_center - hs_alpha)), Pnt(*(pt_center + hs_alpha)))) patches_ext.append( OrthoBrick(Pnt(*(pt_center - hs_beta)), Pnt(*(pt_center + hs_beta))) - patches[-1]) patch_num = len(patches) print('[{:d}] patches total'.format(patch_num)) patch_fill = int(np.log(patch_num) / np.log(10.)) + 1 pt_low = dict() pt_high = dict() pt_inside = dict() info('Patch size computations') sa_utils.makedirs_norace(prefix + '/' + prefix + '_patch_descriptors') ff = open(prefix + '/' + prefix + '_patch_descriptors/0.csv', 'w') ff.write('idx, left, right, front, back, bottom, top\n') for kk in range(patch_num): info(str(kk + 1) + '/' + str(patch_num)) geo = CSGeometry() geo.Add(nohole_whole * patches[kk]) mesh = geo.GenerateMesh(maxh=max_resolution) del geo mesh.Export('tmp.msh', 'Gmsh2 Format') del mesh meshconvert.convert2xml('tmp.msh', 'tmp.xml') os.remove('tmp.msh') os.remove('tmp_facet_region.xml') os.remove('tmp_physical_region.xml') mesh = dolfin.Mesh('tmp.xml') os.remove('tmp.xml') nodes = mesh.coordinates() del mesh pt_low[kk] = np.min(nodes, axis=0) pt_high[kk] = np.max(nodes, axis=0) ff.write('%d, %.15e, %.15e, %.15e, %.15e, %.15e, %.15e\n' % (kk, pt_low[kk][0], pt_high[kk][0], pt_low[kk][1], pt_high[kk][1], pt_low[kk][2], pt_high[kk][2])) del nodes pt_inside[kk] = dolfin.AutoSubDomain(lambda xx, on: (pt_low[ kk] - myeps <= xx).all() and (xx <= pt_high[kk] + myeps).all()) ff.close() info('Patch size computations finished') hole_ratio = hole_radius / lengths[1] for ref in range(max_refines): info('Start meshing resolution {:d}/{:d}'.format(ref + 1, max_refines)) res = max_resolution * 0.5**ref if hole: hole_maxh = res * hole_ratio # hole_maxh = np.min([res*hole_ratio, lengths[2]/layers]) if number: matrix = nohole_matrix - Cylinder( Pnt(center[0], center[1], center[2] - diameter), Pnt(center[0], center[1], center[2] + diameter), hole_radius).maxh(hole_maxh) incs = nohole_matrix - Cylinder( Pnt(center[0], center[1], center[2] - diameter), Pnt(center[0], center[1], center[2] + diameter), hole_radius).maxh(hole_maxh) else: whole = nohole_whole - Cylinder( Pnt(center[0], center[1], center[2] - diameter), Pnt(center[0], center[1], center[2] + diameter), hole_radius).maxh(hole_maxh) dirname = '{:s}/{:s}_{:d}_patches/0/'.format(prefix, prefix, ref) sa_utils.makedirs_norace(dirname) basename = '{:s}/{:s}_{:d}'.format(prefix, prefix, ref) info('Global CSG') geo = CSGeometry() if number: geo.Add(matrix * layer_bricks[0]) for ii in range(1, sublayers): geo.Add(matrix * (layer_bricks[ii] - layer_bricks[ii - 1])) geo.Add(incs * layer_bricks[0]) for ii in range(1, sublayers): geo.Add(incs * (layer_bricks[ii] - layer_bricks[ii - 1])) else: geo.Add(whole * layer_bricks[0]) for ii in range(1, sublayers): geo.Add(whole * (layer_bricks[ii] - layer_bricks[ii - 1])) info('Global CSG constructed') mesh = geo.GenerateMesh(maxh=res) info('Global surface meshed') del geo gc.collect() mesh.GenerateVolumeMesh() mesh.Export(basename + '.msh', 'Gmsh2 Format') meshconvert.convert2xml(basename + '.msh', basename + '.xml') del mesh os.remove(basename + '.msh') os.remove(basename + '_facet_region.xml') info('Global volume meshed') gc.collect() global_mesh = dolfin.Mesh(basename + '.xml') tmp_nodes = global_mesh.coordinates() tmp_low = np.min(tmp_nodes, axis=0) tmp_high = np.max(tmp_nodes, axis=0) info('global mesh: {:s}, {:s}, {:s}'.format( str(tmp_low), str(tmp_high), str(top.inside(tmp_high, True)))) os.remove(basename + '.xml') info('Correcting cell markers') global_domains_tmp = dolfin.MeshFunction( 'size_t', global_mesh, basename + '_physical_region.xml') os.remove(basename + '_physical_region.xml') global_domains_tmp.array()[:] -= np.min(global_domains_tmp.array()) global_domains_tmp.array()[:] //= elem_per_layer global_domains = dolfin.MeshFunction('size_t', global_mesh, basedim, 0) if number: where = np.where(global_domains_tmp.array() < layers) global_domains.array( )[where] = 4 * global_domains_tmp.array()[where] where = np.where(layers <= global_domains_tmp.array()) global_domains.array( )[where] = 4 * (global_domains_tmp.array()[where] - layers) + 1 del where else: global_domains.array()[:] = 4 * global_domains_tmp.array() del global_domains_tmp if ldomain: for ii in range(corner_refine): mf = dolfin.CellFunction('bool', global_mesh, False) corner_subdomains[ii].mark(mf, True) global_mesh = dolfin.refine(global_mesh, mf) global_domains = dolfin.adapt(global_domains, global_mesh) del mf inside_fun = dolfin.MeshFunction('bool', global_mesh, basedim, True) global_mesh = dolfin.refine(global_mesh, inside_fun) global_domains = dolfin.adapt(global_domains, global_mesh) info('Correcting facet markers') global_facets = dolfin.MeshFunction('size_t', global_mesh, basedim - 1, 0) for key in bc_dict: bc_dict[key].mark(global_facets, key) sa_hdf5.write_dolfin_mesh(global_mesh, basename, cell_function=global_domains, facet_function=global_facets) del global_facets, global_mesh, global_domains, basename gc.collect() for kk in range(patch_num): if kk in skip_patches: continue info(str(kk) + '/' + str(patch_num)) basename = 'patch_' + str(kk).zfill(patch_fill) extname = basename + '_' + str(beta) info(' csg') geo = CSGeometry() if number: geo.Add(matrix * layer_bricks[0] * patches[kk]) for ii in range(1, sublayers): geo.Add(matrix * (layer_bricks[ii] - layer_bricks[ii - 1]) * patches[kk]) geo.Add(incs * layer_bricks[0] * patches[kk]) for ii in range(1, sublayers): geo.Add(incs * (layer_bricks[ii] - layer_bricks[ii - 1]) * patches[kk]) geo.Add(matrix * layer_bricks[0] * patches_ext[kk]) for ii in range(1, sublayers): geo.Add(matrix * (layer_bricks[ii] - layer_bricks[ii - 1]) * patches_ext[kk]) geo.Add(incs * layer_bricks[0] * patches_ext[kk]) for ii in range(1, sublayers): geo.Add(incs * (layer_bricks[ii] - layer_bricks[ii - 1]) * patches_ext[kk]) else: geo.Add(whole * layer_bricks[0] * patches[kk]) for ii in range(1, sublayers): geo.Add(whole * (layer_bricks[ii] - layer_bricks[ii - 1]) * patches[kk]) geo.Add(whole * layer_bricks[0] * patches_ext[kk]) for ii in range(1, sublayers): geo.Add(whole * (layer_bricks[ii] - layer_bricks[ii - 1]) * patches_ext[kk]) info(' csg done') mesh = geo.GenerateMesh(maxh=res) info(' surface meshed') del geo gc.collect() mesh.GenerateVolumeMesh() info(' volume meshed') mesh.Export(dirname + '/' + basename + '.msh', 'Gmsh2 Format') meshconvert.convert2xml(dirname + '/' + basename + '.msh', dirname + '/' + basename + '.xml') del mesh os.remove(dirname + '/' + basename + '.msh') os.remove(dirname + '/' + basename + '_facet_region.xml') gc.collect() ext_mesh = dolfin.Mesh(dirname + '/' + basename + '.xml') os.remove(dirname + '/' + basename + '.xml') info(' cell function') ext_domains_tmp = dolfin.MeshFunction( 'size_t', ext_mesh, dirname + '/' + basename + '_physical_region.xml') os.remove(dirname + '/' + basename + '_physical_region.xml') ext_domains_tmp.array()[:] -= np.min(ext_domains_tmp.array()) ext_domains_tmp.array()[:] //= elem_per_layer ext_domains = dolfin.MeshFunction('size_t', ext_mesh, basedim, 0) if number: where = np.where(ext_domains_tmp.array() < layers) ext_domains.array()[where] = 4 * ext_domains_tmp.array()[where] where = np.where( layers <= ext_domains_tmp.array() < 2 * layers) ext_domains.array( )[where] = 4 * (ext_domains_tmp.array()[where] - layers) + 1 where = np.where( 2 * layers <= ext_domains_tmp.array() < 3 * layers) ext_domains.array()[where] = 4 * ( ext_domains_tmp.array()[where] - 2 * layers) + 2 where = np.where(3 * layers <= ext_domains_tmp.array()) ext_domains.array()[where] = 4 * ( ext_domains_tmp.array()[where] - 3 * layers) + 3 del where else: where = np.where(ext_domains_tmp.array() < layers) ext_domains.array()[where] = 4 * ext_domains_tmp.array()[where] where = np.where(layers <= ext_domains_tmp.array()) ext_domains.array( )[where] = 4 * (ext_domains_tmp.array()[where] - layers) + 2 del ext_domains_tmp if ldomain: for ii in range(corner_refine): mf = dolfin.CellFunction('bool', ext_mesh, False) corner_subdomains[ii].mark(mf, True) ext_mesh = dolfin.refine(ext_mesh, mf) ext_domains = dolfin.adapt(ext_domains, ext_mesh) del mf inside_fun = dolfin.MeshFunction('bool', ext_mesh, basedim, False) pt_inside[kk].mark(inside_fun, True) ext_mesh = dolfin.refine(ext_mesh, inside_fun) del inside_fun ext_domains = dolfin.adapt(ext_domains, ext_mesh) info(' cell function done') pt_mesh = dolfin.SubMesh(ext_mesh, pt_inside[kk]) pt_domains = dolfin.MeshFunction('size_t', pt_mesh, basedim, 0) tree = ext_mesh.bounding_box_tree() for cell in dolfin.cells(pt_mesh): global_index = tree.compute_first_entity_collision( cell.midpoint()) pt_domains[cell] = ext_domains[dolfin.Cell( ext_mesh, global_index)] del tree pt_facets = dolfin.MeshFunction('size_t', pt_mesh, basedim - 1, 0) border.mark(pt_facets, 100) for key in bc_dict: bc_dict[key].mark(pt_facets, key) sa_hdf5.write_dolfin_mesh(pt_mesh, '{:s}/{:s}'.format(dirname, basename), cell_function=pt_domains, facet_function=pt_facets) tmp_nodes = ext_mesh.coordinates() tmp_low = np.min(tmp_nodes, axis=0) tmp_high = np.max(tmp_nodes, axis=0) is_part = (tmp_low > low + myeps).any() or (tmp_high < high - myeps).any() del tmp_low, tmp_high, tmp_nodes info('patch [{:d}/{:d}], beta [{:.2e}] is real subdomain [{:}]'. format(kk + 1, patch_num, beta, is_part)) if is_part: vals = np.arange(1, 11) else: vals = np.unique(pt_facets.array()) vals = vals[np.where(vals > 0)] patch_dict = dict() for key in bc_dict: if key in vals: patch_dict[key] = bc_dict[key] else: patch_dict[key] = dolfin.AutoSubDomain( (lambda what: (lambda xx, on: bc_dict[what].inside( xx, on) and pt_inside[kk].inside(xx, on)))(key)) ext_facets = dolfin.MeshFunction('size_t', ext_mesh, basedim - 1, 0) border.mark(ext_facets, 100) for key in patch_dict: patch_dict[key].mark(ext_facets, key) del patch_dict, vals sa_hdf5.write_dolfin_mesh(ext_mesh, dirname + '/' + basename + '_' + str(beta), cell_function=ext_domains, facet_function=ext_facets) del ext_mesh, ext_domains, ext_facets, pt_mesh, pt_domains, pt_facets gc.collect() del pt_low, pt_high, pt_inside
import dolfin from netgen.csg import * from dolfin_utils.meshconvert import meshconvert box = OrthoBrick(Pnt(-1, -1, -1), Pnt(1, 1, 1)) cone = Cone(Pnt(0, 0, -1), Pnt(0, 0, 2), 0, 2) * Plane(Pnt( 0, 0, -1), Vec(0, 0, -1)) * Plane(Pnt(0, 0, 2), Vec(1, 0, 0)) geo = CSGeometry() geo.Add(box * cone) mesh = geo.GenerateMesh(maxh=0.2) mesh.GenerateVolumeMesh() mesh.Export('tmp.msh', 'Gmsh2 Format') meshconvert.convert2xml('tmp.msh', 'tmp.xml') bla = dolfin.Mesh('tmp.xml') dolfin.File('tmp.pvd') << bla
def Fracking(E, nu, hsize, ell, law, ModelB, ka, kb, q, pressure_steps): #======================================================================================= # Input date #======================================================================================= # Geometry L = 170. # length H = 170. # height #hsize= 0.8 # target cell size radius = Constant(5.) meshname = "fracking_hsize%g" % (hsize) # Material constants #ell = Constant(2 * hsize) # internal length scale #E = 6.e3 # Young modulus #nu = 0.34 # Poisson ratio biot = 0. #Biot coefficient PlaneStress = False gc = 1. # fracture toughness k_ell = Constant(1.0e-10) # residual stiffness #law = "AT1" # effective toughness if law == "AT2": Gc = gc / (1 + hsize / (2 * ell)) #AT2 elif law == "AT1": Gc = gc / (1 + 3 * hsize / (8 * ell)) #AT1 else: Gc = gc #ModelB= False # Stopping criteria for the alternate minimization max_iterations = 200 tolerance = 1.0e-5 # Loading ut = 1.e-5 # reference value for the loading (imposed displacement) st = 1 # reference value for the loading (imposed stress) body_force = Constant((0., 0.)) # bulk load pressure_min = 0. # load multiplier min value pressure_max = 1. # load multiplier max value #pressure_steps = 1 # number of time steps WheelerApproach = True #==================================================================================== # To define pressure field #==================================================================================== biot = 0.85 phi = 0.01 #porosity K_f = 0.625e3 #is the pore fluid bulk modulus #MPa K_s = 10e3 #is the porous medium solid grain bulk modulus #MPa M_biot = 1 / (phi / K_f + (biot - phi) / K_s) #1./M_biot=phi/K_f+(alpha-phi)/K_s #MPa print "M_biot", M_biot kappa = 1.e-12 #is the permeability of the rock #m^2 mu_dynamic = 0.79e-9 #is the dynamic viscosity of the fluid #MPa f = Constant(0) t_stop = H**2 * mu_dynamic / (kappa * M_biot) # non dimensional time (s) DeltaT = t_stop / (pressure_steps - 1) #q=3.e-8 #======================================================================================= # Geometry and mesh generation #======================================================================================= # Generate a XDMF/HDF5 based mesh from a Gmsh string geofile = \ """ lc = DefineNumber[ %g, Name "Parameters/lc" ]; H = 170.; L = 170.; r=5.; a=1.; Point(1) = {0, 0, 0, 1*lc}; Point(2) = {L, 0, 0, 1*lc}; Point(3) = {L, H, 0, 1*lc}; Point(4) = {0, H, 0, 1*lc}; Point(5) = {L/2, H/2+r+a, 0, 1*lc}; Point(6) = {L/2, H/2+r, 0, 1*lc}; Point(7) = {L/2, H/2-r, 0, 1*lc}; Point(8) = {L/2, H/2-r-a, 0, 1*lc}; Point(9) = {L/2, H/2, 0, 1*lc}; Line(1) = {1, 2}; Line(2) = {2, 3}; Line(3) = {3, 4}; Line(4) = {4, 1}; Line Loop(5) = {1, 2, 3, 4}; Circle(8) = {6, 9, 7}; Circle(9) = {7, 9, 6}; Line Loop(11) = {8, 9}; Plane Surface(30) = {5,11}; Line(6) = {5, 6}; Line{6} In Surface{30}; Line(7) = {7, 8}; Line{7} In Surface{30}; Physical Surface(1) = {30}; Physical Line(101) = {6}; Physical Line(102) = {7}; Physical Line(103) = {8}; Physical Line(104) = {9}; """%(hsize) subdir = "meshes/" _mesh = Mesh() #creat empty mesh object if not os.path.isfile(subdir + meshname + ".xdmf"): if MPI.rank(mpi_comm_world()) == 0: # Create temporary .geo file defining the mesh if os.path.isdir(subdir) == False: os.mkdir(subdir) fgeo = open(subdir + meshname + ".geo", "w") fgeo.writelines(geofile) fgeo.close() # Calling gmsh and dolfin-convert to generate the .xml mesh (as well as a MeshFunction file) try: subprocess.call([ "gmsh", "-2", "-o", subdir + meshname + ".msh", subdir + meshname + ".geo" ]) except OSError: print( "-----------------------------------------------------------------------------" ) print(" Error: unable to generate the mesh using gmsh") print( " Make sure that you have gmsh installed and have added it to your system PATH" ) print( "-----------------------------------------------------------------------------" ) meshconvert.convert2xml(subdir + meshname + ".msh", subdir + meshname + ".xml", "gmsh") # Convert to XDMF MPI.barrier(mpi_comm_world()) mesh = Mesh(subdir + meshname + ".xml") XDMF = XDMFFile(mpi_comm_world(), subdir + meshname + ".xdmf") XDMF.write(mesh) XDMF.read(_mesh) if os.path.isfile(subdir + meshname + "_physical_region.xml") and os.path.isfile( subdir + meshname + "_facet_region.xml"): if MPI.rank(mpi_comm_world()) == 0: mesh = Mesh(subdir + meshname + ".xml") subdomains = MeshFunction( "size_t", mesh, subdir + meshname + "_physical_region.xml") boundaries = MeshFunction( "size_t", mesh, subdir + meshname + "_facet_region.xml") HDF5 = HDF5File(mesh.mpi_comm(), subdir + meshname + "_physical_facet.h5", "w") HDF5.write(mesh, "/mesh") HDF5.write(subdomains, "/subdomains") HDF5.write(boundaries, "/boundaries") print("Finish writting physical_facet to HDF5") if MPI.rank(mpi_comm_world()) == 0: # Keep only the .xdmf mesh #os.remove(subdir + meshname + ".geo") #os.remove(subdir + meshname + ".msh") #os.remove(subdir + meshname + ".xml") # Info print("Mesh completed") # Read the mesh if existing else: XDMF = XDMFFile(mpi_comm_world(), subdir + meshname + ".xdmf") XDMF.read(_mesh) mesh = Mesh('meshes/fracking_hsize' + str(float(hsize)) + '.xml') mesh_fun = MeshFunction( "size_t", mesh, "meshes/fracking_hsize" + str(float(hsize)) + "_facet_region.xml") #plt.figure(1) #plot(mesh, "2D mesh") #plt.interactive(False) ndim = mesh.geometry().dim() # get number of space dimensions #======================================================================================= # Constitutive functions of the damage model #======================================================================================= def a(alpha_): """ Modulation of the elastic stiffness """ if law == "AT1": return (1 - alpha_)**2 elif law == "AT2": return (1 - alpha_)**2 elif law == "ATk": return (1 - w(alpha_)) / (1 + (k - 1) * w(alpha_)) def w(alpha_): """ Local energy dissipation """ if law == "AT1": return alpha_ elif law == "AT2": return alpha_**2 elif law == "ATk": return 1 - (1 - alpha_)**2 #======================================================================================= # strain, stress and strain energy for Isotropic and Amor's model #======================================================================================= def angle_bracket_plus(a): return (a + abs(a)) / 2 def angle_bracket_minus(a): return (a - abs(a)) / 2 #---------------------------------------------------------------------------------------- def g(alpha_): """ degradation function """ return ((1 - alpha_)**2 + k_ell) #---------------------------------------------------------------------------------------- def eps(u_): """ Geometrical strain """ return sym(grad(u_)) def dev_eps(u_): """ """ return eps(u_) - 1 / 3 * tr(eps(u_)) * Identity(ndim) #---------------------------------------------------------------------------------------- def sigma0(u_): """ Application of the sound elasticy tensor on the strain tensor """ Id = Identity(len(u_)) return 2.0 * mu * eps(u_) + lmbda * tr(eps(u_)) * Id def sigma_A(u_, alpha_): """ Stress Model A """ return g(alpha_) * sigma0(u_) def sigma_B(u_, alpha_): """ Stress Model B """ return g(alpha_) * ( (lmbda + 2 / 3 * mu) * (angle_bracket_plus(tr(eps(u_))) * Identity(ndim)) + 2 * mu * dev_eps(u_)) + (lmbda + 2 / 3 * mu) * ( angle_bracket_minus(tr(dev_eps(u_))) * Identity(ndim)) #---------------------------------------------------------------------------------------- def psi_0(u_): """ The strain energy density for a linear isotropic ma- terial """ return 0.5 * lmbda * tr(eps(u_))**2 + mu * eps(u_)**2 def psi_A(u_, alpha_): """ The strain energy density for model A """ return g(alpha_) * psi_0(u_) def psi_B(u_, alpha_): """ The strain energy density for model B """ return g(alpha_) * (0.5 * (lmbda + 2 / 3 * mu) * (angle_bracket_plus(tr(dev_eps(u_))))**2 + mu * dev_eps(u_)**2) + 0.5 * (lmbda + 2 / 3 * mu) * ( angle_bracket_minus(tr(dev_eps(u_))))**2 #---------------------------------------------------------------------------------------- if not ModelB: # Model A (isotropic model) psi = psi_A sigma = sigma_A else: # Model B (Amor's model) psi = psi_B sigma = sigma_B #======================================================================================= # others definitions #======================================================================================= prefix = "%s-L%s-H%.2f-S%.4f-l%.4f-ka%s-kb%s-steps%s" % ( law, L, H, hsize, ell, ka, kb, pressure_steps) save_dir = "Fracking_result/" + prefix + "/" if os.path.isdir(save_dir): shutil.rmtree(save_dir) # zero and unit vectors zero_v = Constant((0., ) * ndim) e1 = [Constant([1., 0.]), Constant((1., 0., 0.))][ndim - 2] # Normalization constant for the dissipated energy # to get Griffith surface energy for ell going to zero z = sympy.Symbol("z", positive=True) c_w = float(4 * sympy.integrate(sympy.sqrt(w(z)), (z, 0, 1))) # plane strain or plane stress if not PlaneStress: # plane strain lmbda = E * nu / ((1.0 + nu) * (1.0 - 2.0 * nu)) else: # plane stress lmbda = E * nu / (1.0 - nu**2) # shear modulus mu = E / (2.0 * (1.0 + nu)) #======================================================================================= # Define boundary sets for boundary conditions #======================================================================================= class Right(SubDomain): def inside(self, x, on_boundary): return near((x[0] - L) * 0.01, 0) class Left(SubDomain): def inside(self, x, on_boundary): return near((x[0]) * 0.01, 0.) class Top(SubDomain): def inside(self, x, on_boundary): return near((x[1] - H) * 0.01, 0) class Bottom(SubDomain): def inside(self, x, on_boundary): return near((x[1]) * 0.01, 0) class Void(SubDomain): def inside(self, x, on_boundary): #return x[0] <= 2.5 and x[0] >= 1.5 and x[1] <= 2.5 and x[1] >= 1.5 and on_boundary H = 170 L = 170 radius = 5. return x[0] <= L / 2 + 2 * radius and x[ 0] >= L / 2 - 2 * radius and x[1] <= H / 2 + 2 * radius and x[ 1] >= H / 2 - 2 * radius and on_boundary # Initialize sub-domain instances right = Right() left = Left() top = Top() bottom = Bottom() void = Void() # define meshfunction to identify boundaries by numbers boundaries = FacetFunction("size_t", mesh) boundaries.set_all(9999) right.mark(boundaries, 1) # mark top as 1 left.mark(boundaries, 2) # mark top as 2 top.mark(boundaries, 3) # mark top as 3 bottom.mark(boundaries, 4) # mark bottom as 4 void.mark(boundaries, 5) # mark void as 5 # Define new measure including boundary naming ds = Measure("ds")[boundaries] # left: ds(1), right: ds(2) #======================================================================================= # Variational formulation #======================================================================================= # Create function space for 2D elasticity + Damage V_u = VectorFunctionSpace(mesh, "CG", 1) V_alpha = FunctionSpace(mesh, "CG", 1) V_p = FunctionSpace(mesh, "CG", 1) # Define the function, test and trial fields u_, u, u_t = Function(V_u), TrialFunction(V_u), TestFunction(V_u) alpha_, alpha, alpha_t = Function(V_alpha), TrialFunction( V_alpha), TestFunction(V_alpha) P_, P, P_t = Function(V_p), TrialFunction(V_p), TestFunction(V_p), alpha_0 = Function(V_alpha) #define_alpha_0=Expression("x[1] == 2. & x[0] <= 2.2 & x[0] >=1.8 ? 1.0 : 0.0", degree=1) #define_alpha_0=Expression("(x[0] == 2. & x[1] <= 1.75 & x[1] >=1.55) ? 1.0 : 0.0", degree=1) #alpha_0.interpolate(define_alpha_0) #added by Mostafa alpha_0 = interpolate( Constant(0.0), V_alpha) # initial (known) alpha, undamaged everywhere. P_0 = interpolate(Expression("0.1", degree=1), V_p) #======================================================================================= # Dirichlet boundary condition for a traction test boundary #======================================================================================= # bc - u (imposed displacement) u_R = zero_v #Expression(("-2*p", "0.",), p=0.0, degree=1) u_L = zero_v #Expression(("-2*p", "0.",), p=0.0, degree=1) u_T = zero_v #Expression(("0.", "-p",), p=0.0, degree=1) u_B = zero_v #Expression(("0.", "-p",), p=0.0, degree=1) Gamma_u_0 = DirichletBC(V_u, u_R, boundaries, 1) Gamma_u_1 = DirichletBC(V_u, u_L, boundaries, 2) Gamma_u_2 = DirichletBC(V_u, u_T, boundaries, 3) Gamma_u_3 = DirichletBC(V_u, u_B, boundaries, 4) bc_u = [Gamma_u_1, Gamma_u_3, Gamma_u_0, Gamma_u_2] # bc - alpha (zero damage) Gamma_alpha_0 = DirichletBC(V_alpha, 0.0, boundaries, 1) Gamma_alpha_1 = DirichletBC(V_alpha, 0.0, boundaries, 2) Gamma_alpha_2 = DirichletBC(V_alpha, 0.0, boundaries, 3) Gamma_alpha_3 = DirichletBC(V_alpha, 0.0, boundaries, 4) Gamma_alpha_4 = DirichletBC(V_alpha, 1.0, mesh_fun, 101) Gamma_alpha_5 = DirichletBC(V_alpha, 1.0, mesh_fun, 102) bc_alpha = [ Gamma_alpha_0, Gamma_alpha_1, Gamma_alpha_2, Gamma_alpha_3, Gamma_alpha_4, Gamma_alpha_5 ] ## bc - P (imposed pressure) P_C = Expression("p", p=0.0, degree=1) Gamma_P_0 = DirichletBC(V_p, 0.1, boundaries, 1) Gamma_P_1 = DirichletBC(V_p, 0.1, boundaries, 2) Gamma_P_2 = DirichletBC(V_p, 0.1, boundaries, 3) Gamma_P_3 = DirichletBC(V_p, 0.1, boundaries, 4) #Gamma_P_4 = DirichletBC(V_p, P_C, mesh_fun, 101) #Gamma_P_4 = DirichletBC(V_p, P_C, boundaries, 5) bc_P = [Gamma_P_0, Gamma_P_1, Gamma_P_2, Gamma_P_3] #, Gamma_P_4] ## bc - Q (imposed Flowrate) Q = Expression("p*q", p=0.0, q=q, degree=1) # bc - sigma (imposed traction) sigma_R = Expression(( "-p", "0.", ), p=0.0, degree=1) #traction on TOP boundary sigma_T = Expression(( "0.", "-p", ), p=0.0, degree=1) #traction on TOP boundary #==================================================================================== # Define problem and solvers #==================================================================================== Pressure = 1. / M_biot * P_ * P * dx + DeltaT * kappa * exp( pow(ka * alpha_, kb)) / mu_dynamic * inner( nabla_grad(P), nabla_grad(P_)) * dx - ( 1 / M_biot * P_0 + DeltaT * f) * P * dx - DeltaT * Q * P * ds( 5) # Wang et. al 2017 eq(8) #------------------------------------------------------------------------------------ elastic_energy = psi(u_, alpha_) * dx external_work = dot( body_force, u_) * dx #+ dot(sigma_R, u_)*ds(1)+ dot(sigma_T, u_)*ds(3) if not WheelerApproach: # Bourdin approach, 2012 , SPE 159154, equation (5) pressurized_energy = P_ * inner(u_, grad(alpha_)) * dx else: # M.F. Wheeler et al., CAMAME, 2014, eqution (4) pressurized_energy = -(biot - 1.) * ( (1. - alpha_)**2 * P_ * div(u_)) * dx + dot( (1 - alpha_)**2 * grad(P_), u_) * dx dissipated_energy = Gc / float(c_w) * ( w(alpha_) / ell + ell * inner(grad(alpha_), grad(alpha_))) * dx total_energy = elastic_energy + dissipated_energy + pressurized_energy - external_work # Residual and Jacobian of elasticity problem Du_total_energ = derivative(total_energy, u_, u_t) J_u = derivative(Du_total_energ, u_, u) # Residual and Jacobian of damage problem Dalpha_total_energy = derivative(total_energy, alpha_, alpha_t) J_alpha = derivative(Dalpha_total_energy, alpha_, alpha) #Jacobian of pressure problem J_p = derivative(Pressure, P_, P_t) # Variational problem for the displacement problem_u = NonlinearVariationalProblem(Du_total_energ, u_, bc_u, J_u) # Variational problem for the damage (non-linear to use variational inequality solvers of petsc) # Define the minimisation problem by using OptimisationProblem class class DamageProblem(OptimisationProblem): def __init__(self): OptimisationProblem.__init__(self) # Objective function def f(self, x): alpha_.vector()[:] = x return assemble(total_energy) # Gradient of the objective function def F(self, b, x): alpha_.vector()[:] = x assemble(Dalpha_total_energy, tensor=b) # Hessian of the objective function def J(self, A, x): alpha_.vector()[:] = x assemble(J_alpha, tensor=A) # Create the PETScTAOSolver problem_alpha = DamageProblem() # Parse (PETSc) parameters parameters.parse() # Set up the solvers solver_u = NonlinearVariationalSolver(problem_u) prm = solver_u.parameters prm["newton_solver"]["absolute_tolerance"] = 1E-6 prm["newton_solver"]["relative_tolerance"] = 1E-6 prm["newton_solver"]["maximum_iterations"] = 200 prm["newton_solver"]["relaxation_parameter"] = 1.0 prm["newton_solver"]["preconditioner"] = "default" prm["newton_solver"]["linear_solver"] = "mumps" solver_alpha = PETScTAOSolver() alpha_lb = interpolate(Expression("0.", degree=1), V_alpha) # lower bound, set to 0 alpha_ub = interpolate(Expression("1.", degree=1), V_alpha) # upper bound, set to 1 for bc in bc_alpha: bc.apply(alpha_lb.vector()) for bc in bc_alpha: bc.apply(alpha_ub.vector()) problem_pressure = NonlinearVariationalProblem(Pressure, P_, bc_P, J=J_p) solver_pressure = NonlinearVariationalSolver(problem_pressure) #======================================================================================= # To store results #======================================================================================= results = [] file_alpha = File(save_dir + "/alpha.pvd") # use .pvd if .xdmf is not working file_u = File(save_dir + "/u.pvd") # use .pvd if .xdmf is not working file_p = File(save_dir + "/p.pvd") #======================================================================================= # Solving at each timestep #======================================================================================= load_multipliers = np.linspace(pressure_min, pressure_max, pressure_steps) energies = np.zeros((len(load_multipliers), 5)) iterations = np.zeros((len(load_multipliers), 2)) forces = np.zeros((len(load_multipliers), 2)) Borehole_Pressure = np.zeros((len(load_multipliers), 5)) for (i_p, p) in enumerate(load_multipliers): print "\033[1;32m--- Time step %d: time = %g, Flowrate= %g ---\033[1;m" % ( i_p, i_p * DeltaT, p * q) #u_R.p = p*ut #u_L.p = p#*ut #u_B.p = p#*ut #u_T.p = p*ut #P_C.p = p Q.p = p * q #sigma_T.p = p*st #sigma_R.p = p*st iteration = 0 iter = 0 err_P = 1 err_alpha = 1 # Iterations while err_P > tolerance and err_alpha > tolerance and iteration < max_iterations: # solve pressure problem solver_pressure.solve() err_P = (P_.vector() - P_0.vector()).norm('linf') if mpi_comm_world().rank == 0: print "Iteration: %2d, pressure_Error: %2.8g, P_max: %.8g" % ( iter, err_P, P_.vector().max()) P_0.vector()[:] = P_.vector() # solve elastic problem solver_u.solve() if mpi_comm_world().rank == 0: print "elastic iteration: %2d" % (iter) # solve damage problem solver_alpha.solve(problem_alpha, alpha_.vector(), alpha_lb.vector(), alpha_ub.vector()) # test error err_alpha = (alpha_.vector() - alpha_0.vector()).norm('linf') # monitor the results if mpi_comm_world().rank == 0: print "alpha iteration: %2d, Error: %2.8g" % (iter, err_alpha) # update iteration alpha_0.vector()[:] = alpha_.vector() iter += 1 # Update the lower bound to account for the irreversibility alpha_lb.vector()[:] = alpha_.vector() #plt.figure(2) #plot(P_, key = "P", title = "Pressure %.4f"%(p*pressure_max)) #plt.show() #plt.interactive(True) # plot the damage fied #plt.figure(3) #plot(alpha_, range_min = 0., range_max = 1., key = "alpha", title = "Damage at loading %.4f"%(p*pressure_max)) #plt.show() #plt.interactive(True) #======================================================================================= # Some post-processing #======================================================================================= # Save number of iterations for the time step iterations[i_p] = np.array([p, iter]) # Calculate the energies elastic_energy_value = assemble(elastic_energy) dissipated_energy_value = assemble(dissipated_energy) pressurized_energy_value = assemble(pressurized_energy) if mpi_comm_world().rank == 0: print("\nEnd of timestep %d with load multiplier %g" % (i_p, p)) print("AM: Iteration number: %i - Elastic_energy: %.3e" % (i_p, elastic_energy_value)) print("AM: Iteration number: %i - Dissipated_energy: %.3e" % (i_p, dissipated_energy_value)) print("AM: Iteration number: %i - pressurized_energy: %.3e" % (i_p, pressurized_energy_value)) print "\033[1;32m--------------------------------------------------------------\033[1;m" energies[i_p] = np.array([ p, elastic_energy_value, dissipated_energy_value, pressurized_energy_value, elastic_energy_value + dissipated_energy_value + pressurized_energy_value ]) # Calculate the axial force resultant forces[i_p] = np.array( [p, assemble(inner(sigma(u_, alpha_) * e1, e1) * ds(1))]) # max pressure point_a = (L / 2, H / 2 + radius) point_b = (L / 2 + radius, H / 2) point_c = (L / 2, H / 2 - radius) point_d = (L / 2 - radius, H / 2) P_point_a = P_(point_a) P_point_b = P_(point_b) P_point_c = P_(point_c) P_point_d = P_(point_d) Borehole_Pressure[i_p] = np.array( [p, P_point_a, P_point_b, P_point_c, P_point_d]) # Dump solution to file file_alpha << (alpha_, p) file_u << (u_, p) file_p << (P_, p) # Save some global quantities as a function of the time np.savetxt(save_dir + '/energies.txt', energies) np.savetxt(save_dir + '/forces.txt', forces) np.savetxt(save_dir + '/iterations.txt', iterations) np.savetxt(save_dir + '/pressureboreholes.txt', Borehole_Pressure) #======================================================================================= # Plot energy and stresses #======================================================================================= #def critical_stress(): # xs = sympy.Symbol('x') # wx = w(xs); sx = 1/(E*H*a(xs)); # res = sympy.sqrt(2*(Gc*H/c_w)*wx.diff(xs)/(sx.diff(xs)*ell)) # return res.evalf(subs={xs:0}) #def plot_stress(): # plt.plot(forces[:,0], forces[:,1], 'b-o', linewidth = 2) # plt.xlabel('Displacement') # plt.ylabel('Force') # force_cr = critical_stress() # plt.axvline(x = force_cr/(E*H)*L, color = 'grey', linestyle = '--', linewidth = 2) # plt.axhline(y = force_cr, color = 'grey', linestyle = '--', linewidth = 2) #def plot_energy(): # p1, = plt.plot(energies[:,0], energies[:,1],'b-o',linewidth=2) # p2, = plt.plot(energies[:,0], energies[:,2],'r-o',linewidth=2) # p3, = plt.plot(energies[:,0], energies[:,3],'k--',linewidth=2) # plt.legend([p1, p2, p3], ["Elastic","Dissipated","Total"]) # plt.xlabel('Displacement') # plt.ylabel('Energies') # force_cr = critical_stress() # plt.axvline(x = force_cr/(E*H)*L, color = 'grey',linestyle = '--', linewidth = 2) # plt.axhline(y = H,color = 'grey', linestyle = '--', linewidth = 2) #def plot_energy_stress(): # plt.subplot(211) # plot_stress() # plt.subplot(212) # plot_energy() # plt.savefig(save_dir+'/energies_force.png') # plt.show() def plot_PressureEvolution(): plt.xlabel('Time steps') plt.ylabel('Pressure (MPa)') p1, = plt.plot(Borehole_Pressure[:, 0], Borehole_Pressure[:, 1], 'b-o', linewidth=2) p2, = plt.plot(Borehole_Pressure[:, 0], Borehole_Pressure[:, 2], 'r-o', linewidth=2) p3, = plt.plot(Borehole_Pressure[:, 0], Borehole_Pressure[:, 3], 'k-o', linewidth=2) p4, = plt.plot(Borehole_Pressure[:, 0], Borehole_Pressure[:, 4], 'g-o', linewidth=2) plt.legend([p1, p2, p3, p4], ["Point A", "Point B", "Point C", "Point D"]) def plot_PressurePoint(): plot_PressureEvolution() plt.savefig(save_dir + '/PressurePoint.png') plt.show() # Project and write stress field to post-processing file s = sigma_A(u_, alpha_) - (1. / 3) * tr(sigma_A(u_, alpha_)) * Identity( ndim) # deviatoric stress von_Mises = sqrt(3. / 2 * inner(s, s)) V = FunctionSpace(mesh, 'P', 1) von_Mises = project(von_Mises, V) File(save_dir + "von_Mises.pvd") << von_Mises stress_tr = project(tr(sigma_A(u_, alpha_)), V) File(save_dir + "stress_tr.pvd") << stress_tr VV = VectorFunctionSpace(mesh, "CG", 1) Velocity_darcy = -kappa * exp( (ka * alpha_)**kb) * Identity(ndim) / mu_dynamic * nabla_grad(P_) Velocity_D = project(Velocity_darcy, VV) File(save_dir + "Velocity_D.pvd") << Velocity_D #plot_energy_stress() #plt.interactive(True) plot_PressurePoint()
def Fracking(E, nu, hsize, ell, law, ModelB, load_steps): #======================================================================================= # Input date #======================================================================================= # Geometry L = 1.0 # length H = 1.0 # height #hsize= 1.0e-2 # target cell size meshname = "fracture_hsize%g" % (hsize) # Material constants #ell = Constant(4* hsize) # internal length scale #E = 6e3 # Young modulus MPa #nu = 0.3 # Poisson ratio PlaneStress = False gc = 2.7 #2.7e-3 #1.0 # fracture toughness MPa.mm k_ell = Constant(1.0e-12) # residual stiffness #law = "AT2" # effective toughness if law == "AT2": Gc = gc / (1 + hsize / (2 * ell)) #AT2 elif law == "AT1": Gc = gc / (1 + 3 * hsize / (8 * ell)) #AT1 else: Gc = gc #?? #ModelB= False if not ModelB: # Model A (isotropic model) Model = 'Isotropic' else: # Model B (Amor's model) Model = 'Amor' # Stopping criteria for the alternate minimization max_iterations = 1000 tolerance = 1.0e-6 # Loading ut = 6.e-3 # reference value for the loading (imposed displacement) body_force = Constant((0., 0.)) # bulk load load_min = 0. # load multiplier min value load_max = 1. # load multiplier max value #load_steps = 20 # number of time steps #======================================================================================= # Geometry and mesh generation #======================================================================================= # Generate a XDMF/HDF5 based mesh from a Gmsh string geofile = \ """ lc = DefineNumber[ %g, Name "Parameters/lc" ]; // Geometry Boundary Point(1) = {0,0,0,lc}; Point(2) = {1,0,0,lc}; Point(3) = {1,.5,0,lc}; Point(4) = {1,1,0,lc}; Point(5) = {0,1,0,lc}; Point(6) = {0,.5,0,lc}; Line(1) ={1,2}; Line(2) ={2,3}; Line(3) ={3,4}; Line(4) ={4,5}; Line(5) ={5,6}; // Crack Geometry Point(7) = {.5,.5,0,lc}; Point(8) = {0,.5,0,lc}; Line(7) = {6,7}; // <-- dummy divider Line(8) = {7,3}; // <-- crack // added by Vahid Line(9) = {7,8}; // <-- crack Line(6) ={8,1}; //Make line loops and surfaces Line Loop(1) = {1,2,-8,9,6}; // Bottom half Line Loop(2) = {3,4,5,7,8}; // Top half Plane Surface(1) = {1}; Plane Surface(2) = {2}; //Assign physical IDs (numbers picked just so they will be obvious in .msh file) Physical Surface(100) = {1}; // bottom will have ID 100 Physical Surface(200) = {2}; // top will have ID 101 Physical Line(101) = {7}; // crack will have ID 10 Physical Line(201) = {9}; // crack will have ID 10 // more physical ids on top and bottom for boundary conditions in a solver // Physical Line(1) = {1}; // Physical Line(2) = {4}; """%(hsize) subdir = "meshes/" _mesh = Mesh() #creat empty mesh object if not os.path.isfile(subdir + meshname + ".xdmf"): if MPI.rank(mpi_comm_world()) == 0: # Create temporary .geo file defining the mesh if os.path.isdir(subdir) == False: os.mkdir(subdir) fgeo = open(subdir + meshname + ".geo", "w") fgeo.writelines(geofile) fgeo.close() # Calling gmsh and dolfin-convert to generate the .xml mesh (as well as a MeshFunction file) try: subprocess.call([ "gmsh", "-2", "-o", subdir + meshname + ".msh", subdir + meshname + ".geo" ]) except OSError: print( "-----------------------------------------------------------------------------" ) print(" Error: unable to generate the mesh using gmsh") print( " Make sure that you have gmsh installed and have added it to your system PATH" ) print( "-----------------------------------------------------------------------------" ) meshconvert.convert2xml(subdir + meshname + ".msh", subdir + meshname + ".xml", "gmsh") # Convert to XDMF MPI.barrier(mpi_comm_world()) mesh = Mesh(subdir + meshname + ".xml") XDMF = XDMFFile(mpi_comm_world(), subdir + meshname + ".xdmf") XDMF.write(mesh) XDMF.read(_mesh) if os.path.isfile(subdir + meshname + "_physical_region.xml") and os.path.isfile( subdir + meshname + "_facet_region.xml"): if MPI.rank(mpi_comm_world()) == 0: mesh = Mesh(subdir + meshname + ".xml") subdomains = MeshFunction( "size_t", mesh, subdir + meshname + "_physical_region.xml") boundaries = MeshFunction( "size_t", mesh, subdir + meshname + "_facet_region.xml") HDF5 = HDF5File(mesh.mpi_comm(), subdir + meshname + "_physical_facet.h5", "w") HDF5.write(mesh, "/mesh") HDF5.write(subdomains, "/subdomains") HDF5.write(boundaries, "/boundaries") print("Finish writting physical_facet to HDF5") if MPI.rank(mpi_comm_world()) == 0: # Keep only the .xdmf mesh #os.remove(subdir + meshname + ".geo") #os.remove(subdir + meshname + ".msh") #os.remove(subdir + meshname + ".xml") # Info print("Mesh completed") # Read the mesh if existing else: XDMF = XDMFFile(mpi_comm_world(), subdir + meshname + ".xdmf") XDMF.read(_mesh) mesh = Mesh('meshes/fracture_hsize' + str(float(hsize)) + '.xml') mesh_fun = MeshFunction( "size_t", mesh, "meshes/fracture_hsize" + str(float(hsize)) + "_facet_region.xml") #plt.figure(1) #plot(mesh, "2D mesh") #plt.interactive(True) ndim = mesh.geometry().dim() # get number of space dimensions #======================================================================================= # Constitutive functions of the damage model #======================================================================================= def a(alpha_): """ Modulation of the elastic stiffness """ if law == "AT1": return (1 - alpha_)**2 elif law == "AT2": return (1 - alpha_)**2 elif law == "ATk": return (1 - w(alpha_)) / (1 + (k - 1) * w(alpha_)) def w(alpha_): """ Local energy dissipation """ if law == "AT1": return alpha_ elif law == "AT2": return alpha_**2 elif law == "ATk": return 1 - (1 - alpha_)**2 #======================================================================================= # strain, stress and strain energy for Isotropic and Amor's model #======================================================================================= def angle_bracket_plus(a): return (a + abs(a)) / 2 def angle_bracket_minus(a): return (a - abs(a)) / 2 #---------------------------------------------------------------------------------------- def g(alpha_): """ degradation function """ return ((1 - alpha_)**2 + k_ell) #---------------------------------------------------------------------------------------- def eps(u_): """ Geometrical strain """ return sym(grad(u_)) def dev_eps(u_): """ """ return eps(u_) - 1 / 3 * tr(eps(u_)) * Identity(ndim) #---------------------------------------------------------------------------------------- def sigma0(u_): """ Application of the sound elasticy tensor on the strain tensor """ Id = Identity(len(u_)) return 2.0 * mu * eps(u_) + lmbda * tr(eps(u_)) * Id def sigma_A(u_, alpha_): """ Stress Model A """ return g(alpha_) * sigma0(u_) def sigma_B(u_, alpha_): """ Stress Model B """ K = lmbda + 2 / 3 * mu return g(alpha_) * ( K * ( angle_bracket_plus( tr(eps(u_))) * Identity(ndim) )+ 2*mu*dev_eps(u_) ) \ + K*( angle_bracket_minus(tr(dev_eps(u_))) * Identity(ndim)) #---------------------------------------------------------------------------------------- def psi_0(u_): """ The strain energy density for a linear isotropic ma- terial """ return 0.5 * lmbda * tr(eps(u_))**2 + mu * eps(u_)**2 def psi_A(u_, alpha_): """ The strain energy density for model A """ return g(alpha_) * psi_0(u_) def psi_B(u_, alpha_): """ The strain energy density for model B """ K = lmbda + 2 / 3 * mu return g(alpha_) * (0.5 * K * (angle_bracket_plus(tr(dev_eps(u_))))**2 + mu * dev_eps(u_)**2) + 0.5 * K * ( angle_bracket_minus(tr(dev_eps(u_))))**2 #---------------------------------------------------------------------------------------- if not ModelB: # Model A (isotropic model) psi = psi_A sigma = sigma_A else: # Model B (Amor's model) psi = psi_B sigma = sigma_B #======================================================================================= # others definitions #======================================================================================= prefix = "%s-%s-L%s-H%.2f-S%.4f-l%.4f-load_steps%s " % ( law, Model, L, H, hsize, ell, load_steps) save_dir = "Fracture_QS_result/" + prefix + "/" if os.path.isdir(save_dir): shutil.rmtree(save_dir) # zero and unit vectors zero_v = Constant((0., ) * ndim) e1 = [Constant([1., 0.]), Constant((1., 0., 0.))][ndim - 2] e2 = [Constant([0., 1.]), Constant((0., 1., 0.))][ndim - 2] # Normalization constant for the dissipated energy # to get Griffith surface energy for ell going to zero z = sympy.Symbol("z", positive=True) c_w = float(4 * sympy.integrate(sympy.sqrt(w(z)), (z, 0, 1))) # plane strain or plane stress if not PlaneStress: # plane strain lmbda = 121.15e3 # E*nu/((1.0+nu)*(1.0-2.0*nu)) else: # plane stress lmbda = 121.15e3 # E*nu/(1.0-nu**2) # shear modulus mu = 80.77e3 # E / (2.0 * (1.0 + nu)) #======================================================================================= # Define boundary sets for boundary conditions #======================================================================================= class Right(SubDomain): def inside(self, x, on_boundary): return near((x[0] - L) * 0.01, 0) class Left(SubDomain): def inside(self, x, on_boundary): return near((x[0]) * 0.01, 0.) class Top(SubDomain): def inside(self, x, on_boundary): return near((x[1] - H) * 0.01, 0) class Bottom(SubDomain): def inside(self, x, on_boundary): return near((x[1]) * 0.01, 0) # Initialize sub-domain instances right = Right() left = Left() top = Top() bottom = Bottom() # define meshfunction to identify boundaries by numbers boundaries = FacetFunction("size_t", mesh) boundaries.set_all(9999) right.mark(boundaries, 1) # mark top as 1 left.mark(boundaries, 2) # mark top as 2 top.mark(boundaries, 3) # mark top as 3 bottom.mark(boundaries, 4) # mark bottom as 4 # Define new measure including boundary naming ds = Measure("ds")[boundaries] # left: ds(1), right: ds(2) #======================================================================================= # Variational formulation #======================================================================================= # Create function space for 2D elasticity + Damage V_u = VectorFunctionSpace(mesh, "CG", 1) V_alpha = FunctionSpace(mesh, "CG", 1) # Define the function, test and trial fields u_, u, u_t = Function(V_u), TrialFunction(V_u), TestFunction(V_u) alpha_, alpha, alpha_t = Function(V_alpha), TrialFunction( V_alpha), TestFunction(V_alpha) alpha_0 = Function(V_alpha) define_alpha_0 = Expression( "x[1] == 0.5 & x[0] <= 0.5 & x[0] >=0 ? 1.0 : 0.0", degree=1) alpha_0.interpolate(define_alpha_0) #added by Mostafa #alpha_0 = interpolate(Constant(0.0), V_alpha) # initial (known) alpha, undamaged everywhere. #======================================================================================= # Dirichlet boundary condition for a traction test boundary #======================================================================================= # bc - u (imposed displacement) u_R = zero_v #Expression(("t", "0.",), t=0.0, degree=1) u_L = zero_v u_T = Expression(( "0.", "t", ), t=0.0, degree=1) u_B = Expression(( "0.", "-t", ), t=0.0, degree=1) Gamma_u_0 = DirichletBC(V_u, u_R, boundaries, 1) Gamma_u_1 = DirichletBC(V_u, u_L, boundaries, 2) Gamma_u_2 = DirichletBC(V_u, u_T, boundaries, 3) Gamma_u_3 = DirichletBC(V_u, zero_v, boundaries, 4) bc_u = [Gamma_u_2, Gamma_u_3] # bc - alpha (zero damage) Gamma_alpha_0 = DirichletBC(V_alpha, Constant(0.0), boundaries, 1) Gamma_alpha_1 = DirichletBC(V_alpha, Constant(0.0), boundaries, 2) Gamma_alpha_2 = DirichletBC(V_alpha, Constant(0.0), boundaries, 3) Gamma_alpha_3 = DirichletBC(V_alpha, Constant(0.0), boundaries, 4) Gamma_alpha_4 = DirichletBC(V_alpha, Constant(1.0), mesh_fun, 101) bc_alpha = [ ] #Gamma_alpha_0, Gamma_alpha_1, Gamma_alpha_2, Gamma_alpha_3]#, Gamma_alpha_4] # bc - sigma (imposed traction) sigma_T = Expression(( "0.", "t", ), t=0.0, degree=1) #traction on TOP boundary sigma_B = Expression(( "0.", "-t", ), t=0.0, degree=1) #traction on TOP boundary #==================================================================================== # Define problem and solvers #==================================================================================== elastic_energy = psi(u_, alpha_) * dx external_work = dot( body_force, u_) * dx #+ dot(sigma_T, u_)*ds(3)+ dot(sigma_B, u_)*ds(4) dissipated_energy = Gc / float(c_w) * ( w(alpha_) / ell + ell * inner(grad(alpha_), grad(alpha_))) * dx print c_w total_energy = elastic_energy + dissipated_energy - external_work # First derivatives of energies (Residual) Du_total_energy = derivative(total_energy, u_, u_t) Dalpha_total_energy = derivative(total_energy, alpha_, alpha_t) # Second derivatives of energies (Jacobian) J_u = derivative(Du_total_energy, u_, u) J_alpha = derivative(Dalpha_total_energy, alpha_, alpha) # Variational problem for the displacement problem_u = NonlinearVariationalProblem(Du_total_energy, u_, bc_u, J_u) # Variational problem for the damage (non-linear to use variational inequality solvers of petsc) # Define the minimisation problem by using OptimisationProblem class class DamageProblem(OptimisationProblem): def __init__(self): OptimisationProblem.__init__(self) # Objective function def f(self, x): alpha_.vector()[:] = x return assemble(total_energy) # Gradient of the objective function def F(self, b, x): alpha_.vector()[:] = x assemble(Dalpha_total_energy, tensor=b) # Hessian of the objective function def J(self, A, x): alpha_.vector()[:] = x assemble(J_alpha, tensor=A) # Create the PETScTAOSolver problem_alpha = DamageProblem() # Parse (PETSc) parameters parameters.parse() #------------------- # Solver setup #------------------- # Set up the solvers solver_u = NonlinearVariationalSolver(problem_u) prm = solver_u.parameters prm["newton_solver"]["absolute_tolerance"] = 1E-6 prm["newton_solver"]["relative_tolerance"] = 1E-6 prm["newton_solver"]["maximum_iterations"] = 100 prm["newton_solver"]["relaxation_parameter"] = 1.0 prm["newton_solver"]["preconditioner"] = "default" prm["newton_solver"]["linear_solver"] = "mumps" #set_log_level(PROGRESS) solver_alpha = PETScTAOSolver() alpha_lb = interpolate(Expression("0.", degree=1), V_alpha) # lower bound, set to 0 alpha_ub = interpolate(Expression("1.", degree=1), V_alpha) # upper bound, set to 1 #info(solver_alpha.parameters,True) # uncomment to see available parameters for bc in bc_alpha: bc.apply(alpha_lb.vector()) for bc in bc_alpha: bc.apply(alpha_ub.vector()) #======================================================================================= # To store results #======================================================================================= results = [] file_alpha = File(save_dir + "/alpha.pvd") # use .pvd if .xdmf is not working file_u = File(save_dir + "/u.pvd") # use .pvd if .xdmf is not working #======================================================================================= # Solving at each timestep #======================================================================================= load_multipliers = np.linspace(load_min, load_max, load_steps) energies = np.zeros((len(load_multipliers), 4)) iterations = np.zeros((len(load_multipliers), 2)) forces_x = np.zeros((len(load_multipliers), 2)) forces_y = np.zeros((len(load_multipliers), 2)) for (i_t, t) in enumerate(load_multipliers): print "\033[1;32m--- Time step %d: t = %g ---\033[1;m" % (i_t, t) u_T.t = t * ut #u_B.t = t*ut #sigma_T.t = t #sigma_B.t = t # Alternate mininimization # Initialization iter = 1 err_alpha = 1 # Iterations while err_alpha > tolerance and iter < max_iterations: # solve elastic problem solver_u.solve() #plt.figure(2) #plot(u_, title = "Displacement %.4f"%(ut*t)) #plt.show() # solve damage problem solver_alpha.solve(problem_alpha, alpha_.vector(), alpha_lb.vector(), alpha_ub.vector()) # plot the damage fied #plt.figure(3) #plot(alpha_, range_min = 0., range_max = 1., key = "alpha", title = "Damage at loading %.4f"%(ut*t)) #plt.show() # test error err_alpha = (alpha_.vector() - alpha_0.vector()).norm('linf') # monitor the results if mpi_comm_world().rank == 0: print "Iteration: %2d, Error: %2.8g, alpha_max: %.8g" % ( iter, err_alpha, alpha_.vector().max()) # update iteration alpha_0.vector()[:] = alpha_.vector() iter += 1 # Update the lower bound to account for the irreversibility alpha_lb.vector()[:] = alpha_.vector() #plt.interactive(True) #======================================================================================= # Some post-processing #======================================================================================= # Save number of iterations for the time step iterations[i_t] = np.array([t, iter]) # Calculate the energies elastic_energy_value = assemble(elastic_energy) surface_energy_value = assemble(dissipated_energy) if mpi_comm_world().rank == 0: print("\nEnd of timestep %d with load multiplier %g" % (i_t, t)) print("AM: Iteration number: %i - Elastic_energy: %.3e" % (i_t, elastic_energy_value)) print("AM: Iteration number: %i - Dissipated_energy: %.3e" % (i_t, surface_energy_value)) print "\033[1;32m--------------------------------------------------------------\033[1;m" energies[i_t] = np.array([ t, elastic_energy_value, surface_energy_value, elastic_energy_value + surface_energy_value ]) # Calculate the axial force resultant forces_x[i_t] = np.array( [ut * t, assemble(inner(sigma(u_, alpha_) * e1, e1) * ds(3))]) forces_y[i_t] = np.array( [ut * t, assemble(inner(sigma(u_, alpha_) * e2, e2) * ds(3))]) # Dump solution to file file_alpha << (alpha_, t) file_u << (u_, t) # Save some global quantities as a function of the time np.savetxt(save_dir + '/energies.txt', energies) np.savetxt(save_dir + '/forces_x.txt', forces_x) np.savetxt(save_dir + '/forces_y.txt', forces_y) np.savetxt(save_dir + '/iterations.txt', iterations) #======================================================================================= # Plot energy and stresses #======================================================================================= #def critical_stress(): # xs = sympy.Symbol('x') # wx = w(xs); sx = 1/(E*H*a(xs)); # res = sympy.sqrt(2*(Gc*H/c_w)*wx.diff(xs)/(sx.diff(xs)*ell)) # return res.evalf(subs={xs:0}) def plot_stress(): plt.plot(forces[:, 0], forces[:, 1], 'b-o', linewidth=2) plt.xlabel('Displacement') plt.ylabel('Force') #force_cr = critical_stress() #plt.axvline(x = force_cr/(E*H)*L, color = 'grey', linestyle = '--', linewidth = 2) #plt.axhline(y = force_cr, color = 'grey', linestyle = '--', linewidth = 2) def plot_energy(): p1, = plt.plot(energies[:, 0], energies[:, 1], 'b-o', linewidth=2) p2, = plt.plot(energies[:, 0], energies[:, 2], 'r-o', linewidth=2) p3, = plt.plot(energies[:, 0], energies[:, 3], 'k--', linewidth=2) plt.legend([p1, p2, p3], ["Elastic", "Dissipated", "Total"]) plt.xlabel('Displacement') plt.ylabel('Energies') #force_cr = critical_stress() #plt.axvline(x = force_cr/(E*H)*L, color = 'grey',linestyle = '--', linewidth = 2) #plt.axhline(y = H,color = 'grey', linestyle = '--', linewidth = 2) #def plot_energy_stress(): # plt.subplot(211) # plot_stress() # plt.subplot(212) # plot_energy() # plt.savefig(save_dir+'/energies_force.png') #plt.show() #plot_energy_stress() #plt.interactive(True) #======================================================================================= # Save alpha and displacement data #======================================================================================= output_file_u = HDF5File(mpi_comm_world(), save_dir + "u_4_opening.h5", "w") # self.save_dir + "uO.h5" output_file_u.write(u_, "solution") output_file_u.close() output_file_alpha = HDF5File(mpi_comm_world(), save_dir + "alpha_4_opening.h5", "w") output_file_alpha.write(alpha_, "solution") output_file_alpha.close()
def createMesh(self): print("Defining mesh geometry...") self.initMesher() #subdomains is a dictionary keyed by 'left', 'top', etc. with the #face subdomains as values. #electrodes is a list of the electrode subdomains. self.subdomains, self.electrodes = self.mesher.createGeometry() # attempt to use meshio to import the mesh first, fallback to # dolfin-convert failing that try: print("Converting mesh from .msh to .xdmf using meshio...") f_gmsh = os.path.join(self.exporter.abs_in_dir, "domain.msh") f_mesh_xdmf = os.path.join(self.exporter.abs_in_dir, "mesh.xdmf") f_mf_xdmf = os.path.join(self.exporter.abs_in_dir, "mf.xdmf") f_cf_xdmf = os.path.join(self.exporter.abs_in_dir, "cf.xdmf") gm_dict_type = 'gmsh:physical' # 'gmsh:geometrical' msh = meshio.read(f_gmsh) for cell in msh.cells: if cell.type == "triangle": triangle_cells = cell.data elif cell.type == "tetra": tetra_cells = cell.data for key in msh.cell_data_dict[gm_dict_type].keys(): if key == "triangle": triangle_data = msh.cell_data_dict[gm_dict_type][key] elif key == "tetra": tetra_data = msh.cell_data_dict[gm_dict_type][key] tetra_mesh = meshio.Mesh(points=msh.points, cells={"tetra": tetra_cells}) triangle_mesh = meshio.Mesh( points=msh.points, cells=[("triangle", triangle_cells)], cell_data={"name_to_read": [triangle_data]}) cell_function = meshio.Mesh( points=msh.points, cells=[("tetra", tetra_cells)], cell_data={"name_to_read": [tetra_data]}) meshio.write(f_mesh_xdmf, tetra_mesh) meshio.write(f_mf_xdmf, triangle_mesh) meshio.write(f_cf_xdmf, cell_function) print("Importing mesh from .xdmf...") self.mesh = dolfin.Mesh() with dolfin.XDMFFile(f_mesh_xdmf) as infile: infile.read(self.mesh) mvc = dolfin.MeshValueCollection("size_t", self.mesh, 2) with dolfin.XDMFFile(f_mf_xdmf) as infile: infile.read(mvc, "name_to_read") mf = dolfin.cpp.mesh.MeshFunctionSizet(self.mesh, mvc) mvc = dolfin.MeshValueCollection("size_t", self.mesh, 3) with dolfin.XDMFFile(f_cf_xdmf) as infile: infile.read(mvc, "name_to_read") cf = dolfin.cpp.mesh.MeshFunctionSizet(self.mesh, mvc) except: print( "meshio failed, reverting to legacy dolfin-convert conversion") #convert mesh to xml suitable for dolfin print("Converting mesh from .msh to .xml...") meshconvert.convert2xml( os.path.join(self.exporter.abs_in_dir, "domain.msh"), os.path.join(self.exporter.abs_in_dir, "domain.xml")) # legacy print("Importing mesh from .xml...") #set as mesh in model self.mesh = dolfin.Mesh( os.path.join(self.exporter.abs_in_dir, 'domain.xml'))
def mesher(geofile, meshname): subdir = "meshes/" _mesh = Mesh() #creat empty mesh object if not os.path.isfile(subdir + meshname + ".xdmf"): if MPI.rank(mpi_comm_world()) == 0: # Create temporary .geo file defining the mesh if os.path.isdir(subdir) == False: os.mkdir(subdir) fgeo = open(subdir + meshname + ".geo", "w") fgeo.writelines(geofile) fgeo.close() # Calling gmsh and dolfin-convert to generate the .xml mesh (as well as a MeshFunction file) try: subprocess.call(["gmsh", "-2", "-o", subdir + meshname + ".msh", subdir + meshname + ".geo"]) except OSError: print("-----------------------------------------------------------------------------") print(" Error: unable to generate the mesh using gmsh") print(" Make sure that you have gmsh installed and have added it to your system PATH") print("-----------------------------------------------------------------------------") return meshconvert.convert2xml(subdir + meshname + ".msh", subdir + meshname + ".xml", "gmsh") # Convert to XDMF MPI.barrier(mpi_comm_world()) mesh = Mesh(subdir + meshname + ".xml") XDMF = XDMFFile(mpi_comm_world(), subdir + meshname + ".xdmf") XDMF.write(mesh) XDMF.read(_mesh) if os.path.isfile(subdir + meshname + "_physical_region.xml") and os.path.isfile(subdir + meshname + "_facet_region.xml"): if MPI.rank(mpi_comm_world()) == 0: mesh = Mesh(subdir + meshname + ".xml") subdomains = MeshFunction("size_t", mesh, subdir + meshname + "_physical_region.xml") boundaries = MeshFunction("size_t", mesh, subdir + meshname + "_facet_region.xml") HDF5 = HDF5File(mesh.mpi_comm(), subdir + meshname + "_physical_facet.h5", "w") HDF5.write(mesh, "/mesh") HDF5.write(subdomains, "/subdomains") HDF5.write(boundaries, "/boundaries") print("Finish writting physical_facet to HDF5") if MPI.rank(mpi_comm_world()) == 0: # Keep only the .xdmf mesh os.remove(subdir + meshname + ".geo") os.remove(subdir + meshname + ".msh") #os.remove(subdir + meshname + ".xml") # Info print("Mesh completed") # Read the mesh if existing else: XDMF = XDMFFile(mpi_comm_world(), subdir + meshname + ".xdmf") XDMF.read(_mesh) return _mesh