def test_save_1d_tensor(tempfile, file_options): mesh = UnitIntervalMesh(MPI.COMM_WORLD, 32) u = Function(TensorFunctionSpace(mesh, ("Lagrange", 2))) u.vector.set(1) VTKFile(tempfile + "u.pvd").write(u) for file_option in file_options: VTKFile(tempfile + "u.pvd", file_option).write(u)
def test_save_3d_tensor(tempdir, encoding, cell_type): filename = os.path.join(tempdir, "u3t.xdmf") mesh = UnitCubeMesh(MPI.comm_world, 4, 4, 4, cell_type) u = Function(TensorFunctionSpace(mesh, ("Lagrange", 2))) u.vector.set(1.0 + (1j if has_petsc_complex else 0)) with XDMFFile(mesh.mpi_comm(), filename, encoding=encoding) as file: file.write(u)
def test_save_2d_tensor(tempdir, encoding, cell_type): filename = os.path.join(tempdir, "tensor.xdmf") mesh = UnitSquareMesh(MPI.COMM_WORLD, 16, 16, cell_type) u = Function(TensorFunctionSpace(mesh, ("Lagrange", 2))) u.vector.set(1.0 + (1j if has_petsc_complex else 0)) with XDMFFile(mesh.mpi_comm(), filename, "w", encoding=encoding) as file: file.write_mesh(mesh) file.write_function(u)
def test_save_3d_tensor(tempdir): mesh = UnitCubeMesh(MPI.COMM_WORLD, 8, 8, 8) u = Function(TensorFunctionSpace(mesh, ("Lagrange", 2))) with u.vector.localForm() as loc: loc.set(1.0) filename = os.path.join(tempdir, "u.pvd") with VTKFile(mesh.mpi_comm(), filename, "w") as vtk: vtk.write_function(u, 0.)
def test_save_3d_tensor(tempfile, file_options): mesh = UnitCubeMesh(MPI.COMM_WORLD, 8, 8, 8) u = Function(TensorFunctionSpace(mesh, ("Lagrange", 2))) u.vector.set(1) VTKFile(tempfile + "u.pvd").write(u) f = VTKFile(tempfile + "u.pvd") f.write(u, 0.) f.write(u, 1.) for file_option in file_options: VTKFile(tempfile + "u.pvd", file_option).write(u)
def test_save_2d_tensor(tempfile, file_options): mesh = UnitSquareMesh(MPI.comm_world, 16, 16) u = Function(TensorFunctionSpace(mesh, ("Lagrange", 2))) u.vector.set(1) VTKFile(tempfile + "u.pvd").write(u) f = VTKFile(tempfile + "u.pvd") f.write(u, 0.) f.write(u, 1.) for file_option in file_options: VTKFile(tempfile + "u.pvd", file_option).write(u)
def Q(mesh): return TensorFunctionSpace(mesh, ('CG', 1))
def __init__(self, io_params, time_params, fem_params, constitutive_models, bc_dict, time_curves, io, comm=None): problem_base.__init__(self, io_params, time_params, comm) self.problem_physics = 'solid' self.simname = io_params['simname'] self.io = io # number of distinct domains (each one has to be assigned a own material model) self.num_domains = len(constitutive_models) self.order_disp = fem_params['order_disp'] try: self.order_pres = fem_params['order_pres'] except: self.order_pres = 1 self.quad_degree = fem_params['quad_degree'] self.incompressible_2field = fem_params['incompressible_2field'] self.fem_params = fem_params self.constitutive_models = constitutive_models # collect domain data self.dx_, self.rho0, self.rayleigh, self.eta_m, self.eta_k = [], [], [False]*self.num_domains, [], [] for n in range(self.num_domains): # integration domains self.dx_.append(dx(subdomain_data=self.io.mt_d, subdomain_id=n+1, metadata={'quadrature_degree': self.quad_degree})) # data for inertial and viscous forces: density and damping if self.timint != 'static': self.rho0.append(constitutive_models['MAT'+str(n+1)+'']['inertia']['rho0']) if 'rayleigh_damping' in constitutive_models['MAT'+str(n+1)+''].keys(): self.rayleigh[n] = True self.eta_m.append(constitutive_models['MAT'+str(n+1)+'']['rayleigh_damping']['eta_m']) self.eta_k.append(constitutive_models['MAT'+str(n+1)+'']['rayleigh_damping']['eta_k']) try: self.prestress_initial = fem_params['prestress_initial'] except: self.prestress_initial = False # type of discontinuous function spaces if str(self.io.mesh.ufl_cell()) == 'tetrahedron' or str(self.io.mesh.ufl_cell()) == 'triangle3D': dg_type = "DG" if (self.order_disp > 1 or self.order_pres > 1) and self.quad_degree < 3: raise ValueError("Use at least a quadrature degree of 3 or more for higher-order meshes!") elif str(self.io.mesh.ufl_cell()) == 'hexahedron' or str(self.io.mesh.ufl_cell()) == 'quadrilateral3D': dg_type = "DQ" if (self.order_disp > 1 or self.order_pres > 1) and self.quad_degree < 5: raise ValueError("Use at least a quadrature degree of 5 or more for higher-order meshes!") else: raise NameError("Unknown cell/element type!") # create finite element objects for u and p P_u = VectorElement("CG", self.io.mesh.ufl_cell(), self.order_disp) P_p = FiniteElement("CG", self.io.mesh.ufl_cell(), self.order_pres) # function spaces for u and p self.V_u = FunctionSpace(self.io.mesh, P_u) self.V_p = FunctionSpace(self.io.mesh, P_p) # Quadrature tensor, vector, and scalar elements Q_tensor = TensorElement("Quadrature", self.io.mesh.ufl_cell(), degree=1, quad_scheme="default") Q_vector = VectorElement("Quadrature", self.io.mesh.ufl_cell(), degree=1, quad_scheme="default") Q_scalar = FiniteElement("Quadrature", self.io.mesh.ufl_cell(), degree=1, quad_scheme="default") # not yet working - we cannot interpolate into Quadrature elements with the current dolfinx version currently! #self.Vd_tensor = FunctionSpace(self.io.mesh, Q_tensor) #self.Vd_vector = FunctionSpace(self.io.mesh, Q_vector) #self.Vd_scalar = FunctionSpace(self.io.mesh, Q_scalar) # Quadrature function spaces (currently not properly functioning for higher-order meshes!!!) self.Vd_tensor = TensorFunctionSpace(self.io.mesh, (dg_type, self.order_disp-1)) self.Vd_vector = VectorFunctionSpace(self.io.mesh, (dg_type, self.order_disp-1)) self.Vd_scalar = FunctionSpace(self.io.mesh, (dg_type, self.order_disp-1)) # functions self.du = TrialFunction(self.V_u) # Incremental displacement self.var_u = TestFunction(self.V_u) # Test function self.dp = TrialFunction(self.V_p) # Incremental pressure self.var_p = TestFunction(self.V_p) # Test function self.u = Function(self.V_u, name="Displacement") self.p = Function(self.V_p, name="Pressure") # values of previous time step self.u_old = Function(self.V_u) self.v_old = Function(self.V_u) self.a_old = Function(self.V_u) self.p_old = Function(self.V_p) # a setpoint displacement for multiscale analysis self.u_set = Function(self.V_u) self.p_set = Function(self.V_p) self.tau_a_set = Function(self.Vd_scalar) # initial (zero) functions for initial stiffness evaluation (e.g. for Rayleigh damping) self.u_ini, self.p_ini, self.theta_ini, self.tau_a_ini = Function(self.V_u), Function(self.V_p), Function(self.Vd_scalar), Function(self.Vd_scalar) self.theta_ini.vector.set(1.0) self.theta_ini.vector.ghostUpdate(addv=PETSc.InsertMode.INSERT, mode=PETSc.ScatterMode.FORWARD) # growth stretch self.theta = Function(self.Vd_scalar, name="theta") self.theta_old = Function(self.Vd_scalar) self.growth_thres = Function(self.Vd_scalar) # initialize to one (theta = 1 means no growth) self.theta.vector.set(1.0), self.theta_old.vector.set(1.0) self.theta.vector.ghostUpdate(addv=PETSc.InsertMode.INSERT, mode=PETSc.ScatterMode.FORWARD), self.theta_old.vector.ghostUpdate(addv=PETSc.InsertMode.INSERT, mode=PETSc.ScatterMode.FORWARD) # active stress self.tau_a = Function(self.Vd_scalar, name="tau_a") self.tau_a_old = Function(self.Vd_scalar) self.amp_old, self.amp_old_set = Function(self.Vd_scalar), Function(self.Vd_scalar) self.amp_old.vector.set(1.0), self.amp_old_set.vector.set(1.0) self.amp_old.vector.ghostUpdate(addv=PETSc.InsertMode.INSERT, mode=PETSc.ScatterMode.FORWARD), self.amp_old_set.vector.ghostUpdate(addv=PETSc.InsertMode.INSERT, mode=PETSc.ScatterMode.FORWARD) # prestressing history defgrad and spring prestress if self.prestress_initial: self.F_hist = Function(self.Vd_tensor, name="Defgrad_hist") self.u_pre = Function(self.V_u) else: self.F_hist = None self.u_pre = None self.internalvars = {"theta" : self.theta, "tau_a" : self.tau_a} self.internalvars_old = {"theta" : self.theta_old, "tau_a" : self.tau_a_old} # reference coordinates self.x_ref = Function(self.V_u) self.x_ref.interpolate(self.x_ref_expr) if self.incompressible_2field: self.ndof = self.u.vector.getSize() + self.p.vector.getSize() else: self.ndof = self.u.vector.getSize() # initialize solid time-integration class self.ti = timeintegration.timeintegration_solid(time_params, fem_params, time_curves, self.t_init, self.comm) # check for materials that need extra treatment (anisotropic, active stress, growth, ...) have_fiber1, have_fiber2 = False, False self.have_active_stress, self.active_stress_trig, self.have_frank_starling, self.have_growth = False, 'ode', False, False self.mat_active_stress, self.mat_growth, self.mat_remodel, self.mat_growth_dir, self.mat_growth_trig, self.mat_growth_thres = [False]*self.num_domains, [False]*self.num_domains, [False]*self.num_domains, [None]*self.num_domains, [None]*self.num_domains, []*self.num_domains self.localsolve, growth_dir = False, None self.actstress = [] for n in range(self.num_domains): if 'holzapfelogden_dev' in self.constitutive_models['MAT'+str(n+1)+''].keys() or 'guccione_dev' in self.constitutive_models['MAT'+str(n+1)+''].keys(): have_fiber1, have_fiber2 = True, True if 'active_fiber' in self.constitutive_models['MAT'+str(n+1)+''].keys(): have_fiber1 = True self.mat_active_stress[n], self.have_active_stress = True, True # if one mat has a prescribed active stress, all have to be! if 'prescribed_curve' in self.constitutive_models['MAT'+str(n+1)+'']['active_fiber']: self.active_stress_trig = 'prescribed' if 'prescribed_multiscale' in self.constitutive_models['MAT'+str(n+1)+'']['active_fiber']: self.active_stress_trig = 'prescribed_multiscale' if self.active_stress_trig == 'ode': act_curve = self.ti.timecurves(self.constitutive_models['MAT'+str(n+1)+'']['active_fiber']['activation_curve']) self.actstress.append(activestress_activation(self.constitutive_models['MAT'+str(n+1)+'']['active_fiber'], act_curve)) if self.actstress[-1].frankstarling: self.have_frank_starling = True if self.active_stress_trig == 'prescribed': self.ti.funcs_to_update.append({self.tau_a : self.ti.timecurves(self.constitutive_models['MAT'+str(n+1)+'']['active_fiber']['prescribed_curve'])}) if 'active_iso' in self.constitutive_models['MAT'+str(n+1)+''].keys(): self.mat_active_stress[n], self.have_active_stress = True, True # if one mat has a prescribed active stress, all have to be! if 'prescribed_curve' in self.constitutive_models['MAT'+str(n+1)+'']['active_iso']: self.active_stress_trig = 'prescribed' if 'prescribed_multiscale' in self.constitutive_models['MAT'+str(n+1)+'']['active_iso']: self.active_stress_trig = 'prescribed_multiscale' if self.active_stress_trig == 'ode': act_curve = self.ti.timecurves(self.constitutive_models['MAT'+str(n+1)+'']['active_iso']['activation_curve']) self.actstress.append(activestress_activation(self.constitutive_models['MAT'+str(n+1)+'']['active_iso'], act_curve)) if self.active_stress_trig == 'prescribed': self.ti.funcs_to_update.append({self.tau_a : self.ti.timecurves(self.constitutive_models['MAT'+str(n+1)+'']['active_iso']['prescribed_curve'])}) if 'growth' in self.constitutive_models['MAT'+str(n+1)+''].keys(): self.mat_growth[n], self.have_growth = True, True self.mat_growth_dir[n] = self.constitutive_models['MAT'+str(n+1)+'']['growth']['growth_dir'] self.mat_growth_trig[n] = self.constitutive_models['MAT'+str(n+1)+'']['growth']['growth_trig'] # need to have fiber fields for the following growth options if self.mat_growth_dir[n] == 'fiber' or self.mat_growth_trig[n] == 'fibstretch': have_fiber1 = True if self.mat_growth_dir[n] == 'radial': have_fiber1, have_fiber2 = True, True # in this case, we have a theta that is (nonlinearly) dependent on the deformation, theta = theta(C(u)), # therefore we need a local Newton iteration to solve for equilibrium theta (return mapping) prior to entering # the global Newton scheme - so flag localsolve to true if self.mat_growth_trig[n] != 'prescribed' and self.mat_growth_trig[n] != 'prescribed_multiscale': self.localsolve = True self.mat_growth_thres.append(self.constitutive_models['MAT'+str(n+1)+'']['growth']['growth_thres']) else: self.mat_growth_thres.append(as_ufl(0)) # for the case that we have a prescribed growth stretch over time, append curve to functions that need time updates # if one mat has a prescribed growth model, all have to be! if self.mat_growth_trig[n] == 'prescribed': self.ti.funcs_to_update.append({self.theta : self.ti.timecurves(self.constitutive_models['MAT'+str(n+1)+'']['growth']['prescribed_curve'])}) if 'remodeling_mat' in self.constitutive_models['MAT'+str(n+1)+'']['growth'].keys(): self.mat_remodel[n] = True else: self.mat_growth_thres.append(as_ufl(0)) # full linearization of our remodeling law can lead to excessive compiler times for ffcx... :-/ # let's try if we might can go without one of the critial terms (derivative of remodeling fraction w.r.t. C) try: self.lin_remod_full = fem_params['lin_remodeling_full'] except: self.lin_remod_full = True # growth threshold (as function, since in multiscale approach, it can vary element-wise) if self.have_growth and self.localsolve: growth_thres_proj = project(self.mat_growth_thres, self.Vd_scalar, self.dx_) self.growth_thres.vector.ghostUpdate(addv=PETSc.InsertMode.ADD, mode=PETSc.ScatterMode.REVERSE) self.growth_thres.interpolate(growth_thres_proj) # read in fiber data if have_fiber1: fibarray = ['fiber'] if have_fiber2: fibarray.append('sheet') # fiber function space - vector defined on quadrature points V_fib = self.Vd_vector self.fib_func = self.io.readin_fibers(fibarray, V_fib, self.dx_) else: self.fib_func = None # for multiscale G&R analysis self.tol_stop_large = 0 # initialize kinematics class self.ki = solid_kinematics_constitutive.kinematics(fib_funcs=self.fib_func, F_hist=self.F_hist) # initialize material/constitutive class self.ma = [] for n in range(self.num_domains): self.ma.append(solid_kinematics_constitutive.constitutive(self.ki, self.constitutive_models['MAT'+str(n+1)+''], self.incompressible_2field, mat_growth=self.mat_growth[n], mat_remodel=self.mat_remodel[n])) # initialize solid variational form class self.vf = solid_variationalform.variationalform(self.var_u, self.du, self.var_p, self.dp, self.io.n0, self.x_ref) # initialize boundary condition class self.bc = boundaryconditions.boundary_cond_solid(bc_dict, self.fem_params, self.io, self.ki, self.vf, self.ti) if self.prestress_initial: # initialize prestressing history deformation gradient Id_proj = project(Identity(len(self.u)), self.Vd_tensor, self.dx_) self.F_hist.interpolate(Id_proj) self.bc_dict = bc_dict # Dirichlet boundary conditions if 'dirichlet' in self.bc_dict.keys(): self.bc.dirichlet_bcs(self.V_u) self.set_variational_forms_and_jacobians()
def Q(mesh): return TensorFunctionSpace(mesh, ('Lagrange', 1))
def __init__(self, io_params, time_params, fem_params, constitutive_models, bc_dict, time_curves, io, comm=None): problem_base.__init__(self, io_params, time_params, comm) self.problem_physics = 'fluid' self.simname = io_params['simname'] self.io = io # number of distinct domains (each one has to be assigned a own material model) self.num_domains = len(constitutive_models) self.order_vel = fem_params['order_vel'] self.order_pres = fem_params['order_pres'] self.quad_degree = fem_params['quad_degree'] # collect domain data self.dx_, self.rho = [], [] for n in range(self.num_domains): # integration domains self.dx_.append( dx(subdomain_data=self.io.mt_d, subdomain_id=n + 1, metadata={'quadrature_degree': self.quad_degree})) # data for inertial forces: density self.rho.append(constitutive_models['MAT' + str(n + 1) + '']['inertia']['rho']) self.incompressible_2field = True # always true! self.localsolve = False # no idea what might have to be solved locally... self.prestress_initial = False # guess prestressing in fluid is somehow senseless... self.p11 = as_ufl( 0 ) # can't think of a fluid case with non-zero 11-block in system matrix... # type of discontinuous function spaces if str(self.io.mesh.ufl_cell()) == 'tetrahedron' or str( self.io.mesh.ufl_cell()) == 'triangle3D': dg_type = "DG" if (self.order_vel > 1 or self.order_pres > 1) and self.quad_degree < 3: raise ValueError( "Use at least a quadrature degree of 3 or more for higher-order meshes!" ) elif str(self.io.mesh.ufl_cell()) == 'hexahedron' or str( self.io.mesh.ufl_cell()) == 'quadrilateral3D': dg_type = "DQ" if (self.order_vel > 1 or self.order_pres > 1) and self.quad_degree < 5: raise ValueError( "Use at least a quadrature degree of 5 or more for higher-order meshes!" ) else: raise NameError("Unknown cell/element type!") # create finite element objects for v and p self.P_v = VectorElement("CG", self.io.mesh.ufl_cell(), self.order_vel) self.P_p = FiniteElement("CG", self.io.mesh.ufl_cell(), self.order_pres) # function spaces for v and p self.V_v = FunctionSpace(self.io.mesh, self.P_v) self.V_p = FunctionSpace(self.io.mesh, self.P_p) # a discontinuous tensor, vector, and scalar function space self.Vd_tensor = TensorFunctionSpace(self.io.mesh, (dg_type, self.order_vel - 1)) self.Vd_vector = VectorFunctionSpace(self.io.mesh, (dg_type, self.order_vel - 1)) self.Vd_scalar = FunctionSpace(self.io.mesh, (dg_type, self.order_vel - 1)) # functions self.dv = TrialFunction(self.V_v) # Incremental velocity self.var_v = TestFunction(self.V_v) # Test function self.dp = TrialFunction(self.V_p) # Incremental pressure self.var_p = TestFunction(self.V_p) # Test function self.v = Function(self.V_v, name="Velocity") self.p = Function(self.V_p, name="Pressure") # values of previous time step self.v_old = Function(self.V_v) self.a_old = Function(self.V_v) self.p_old = Function(self.V_p) self.ndof = self.v.vector.getSize() + self.p.vector.getSize() # initialize fluid time-integration class self.ti = timeintegration.timeintegration_fluid( time_params, fem_params, time_curves, self.t_init, self.comm) # initialize kinematics_constitutive class self.ki = fluid_kinematics_constitutive.kinematics() # initialize material/constitutive class self.ma = [] for n in range(self.num_domains): self.ma.append( fluid_kinematics_constitutive.constitutive( self.ki, constitutive_models['MAT' + str(n + 1) + ''])) # initialize fluid variational form class self.vf = fluid_variationalform.variationalform( self.var_v, self.dv, self.var_p, self.dp, self.io.n0) # initialize boundary condition class self.bc = boundaryconditions.boundary_cond_fluid( bc_dict, fem_params, self.io, self.ki, self.vf, self.ti) self.bc_dict = bc_dict # Dirichlet boundary conditions if 'dirichlet' in self.bc_dict.keys(): self.bc.dirichlet_bcs(self.V_v) self.set_variational_forms_and_jacobians()