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()
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 __init__(self, io_params, time_params, model_params, time_curves, coupling_params={}, comm=None): problem_base.__init__(self, io_params, time_params, comm) self.problem_physics = 'flow0d' self.simname = io_params['simname'] self.time_params = time_params # only relevant to syspul* models try: self.chamber_models = model_params['chamber_models'] except: self.chamber_models = {} try: self.excitation_curve = model_params['excitation_curve'] except: self.excitation_curve = None try: initial_file = time_params['initial_file'] except: initial_file = '' # could use extra write frequency setting for 0D model (i.e. for coupled problem) try: self.write_results_every_0D = io_params['write_results_every_0D'] except: self.write_results_every_0D = io_params['write_results_every'] # for restart try: self.write_restart_every = io_params['write_restart_every'] except: self.write_restart_every = -1 # could use extra output path setting for 0D model (i.e. for coupled problem) try: self.output_path_0D = io_params['output_path_0D'] except: self.output_path_0D = io_params['output_path'] try: valvelaws = model_params['valvelaws'] except: valvelaws = { 'av': ['pwlin_pres', 0], 'mv': ['pwlin_pres', 0], 'pv': ['pwlin_pres', 0], 'tv': ['pwlin_pres', 0] } try: self.cq = coupling_params['coupling_quantity'] except: self.cq = ['volume'] try: self.eps_periodic = time_params['eps_periodic'] except: self.eps_periodic = 1.0e-20 try: self.periodic_checktype = time_params['periodic_checktype'] except: self.periodic_checktype = 'allvar' try: self.prescribed_variables = model_params['prescribed_variables'] except: self.prescribed_variables = {} try: self.perturb_type = model_params['perturb_type'][0] except: self.perturb_type = None try: self.perturb_factor = model_params['perturb_type'][1] except: self.perturb_factor = 1. try: self.perturb_id = model_params['perturb_type'][2] except: self.perturb_id = -1 try: self.perturb_after_cylce = model_params['perturb_after_cylce'] except: self.perturb_after_cylce = -1 # definitely set to -1 if we don't have a perturb type if self.perturb_type is None: self.perturb_after_cylce = -1 self.have_induced_pert = False # initialize 0D model class if model_params['modeltype'] == '2elwindkessel': from cardiovascular0D_2elwindkessel import cardiovascular0D2elwindkessel self.cardvasc0D = cardiovascular0D2elwindkessel( model_params['parameters'], cq=self.cq, comm=self.comm) elif model_params['modeltype'] == '4elwindkesselLsZ': from cardiovascular0D_4elwindkesselLsZ import cardiovascular0D4elwindkesselLsZ self.cardvasc0D = cardiovascular0D4elwindkesselLsZ( model_params['parameters'], cq=self.cq, comm=self.comm) elif model_params['modeltype'] == '4elwindkesselLpZ': from cardiovascular0D_4elwindkesselLpZ import cardiovascular0D4elwindkesselLpZ self.cardvasc0D = cardiovascular0D4elwindkesselLpZ( model_params['parameters'], cq=self.cq, comm=self.comm) elif model_params['modeltype'] == 'syspul': from cardiovascular0D_syspul import cardiovascular0Dsyspul self.cardvasc0D = cardiovascular0Dsyspul( model_params['parameters'], chmodels=self.chamber_models, cq=self.cq, valvelaws=valvelaws, comm=self.comm) elif model_params['modeltype'] == 'syspulcap': from cardiovascular0D_syspulcap import cardiovascular0Dsyspulcap self.cardvasc0D = cardiovascular0Dsyspulcap( model_params['parameters'], chmodels=self.chamber_models, cq=self.cq, valvelaws=valvelaws, comm=self.comm) elif model_params['modeltype'] == 'syspulcapcor': from cardiovascular0D_syspulcap import cardiovascular0Dsyspulcapcor self.cardvasc0D = cardiovascular0Dsyspulcapcor( model_params['parameters'], chmodels=self.chamber_models, cq=self.cq, valvelaws=valvelaws, comm=self.comm) elif model_params['modeltype'] == 'syspulcaprespir': from cardiovascular0D_syspulcaprespir import cardiovascular0Dsyspulcaprespir self.cardvasc0D = cardiovascular0Dsyspulcaprespir( model_params['parameters'], chmodels=self.chamber_models, cq=self.cq, valvelaws=valvelaws, comm=self.comm) else: raise NameError("Unknown 0D modeltype!") # vectors and matrices self.dK = PETSc.Mat().createAIJ(size=(self.cardvasc0D.numdof, self.cardvasc0D.numdof), bsize=None, nnz=None, csr=None, comm=self.comm) self.dK.setUp() self.K = PETSc.Mat().createAIJ(size=(self.cardvasc0D.numdof, self.cardvasc0D.numdof), bsize=None, nnz=None, csr=None, comm=self.comm) self.K.setUp() self.s, self.s_old, self.s_mid = self.K.createVecLeft( ), self.K.createVecLeft(), self.K.createVecLeft() self.sTc, self.sTc_old = self.K.createVecLeft(), self.K.createVecLeft() self.df, self.df_old = self.K.createVecLeft(), self.K.createVecLeft() self.f, self.f_old = self.K.createVecLeft(), self.K.createVecLeft() self.aux, self.aux_old, self.aux_mid = np.zeros( self.cardvasc0D.numdof), np.zeros( self.cardvasc0D.numdof), np.zeros(self.cardvasc0D.numdof) self.s_set = self.K.createVecLeft() # set point for multisale analysis self.c, self.y = [], [] # initialize flow0d time-integration class self.ti = timeintegration.timeintegration_flow0d( time_params, time_curves, self.t_init, self.comm) if initial_file: initialconditions = self.cardvasc0D.set_initial_from_file( initial_file) else: initialconditions = time_params['initial_conditions'] self.cardvasc0D.initialize(self.s, initialconditions) self.cardvasc0D.initialize(self.s_old, initialconditions) self.cardvasc0D.initialize(self.sTc_old, initialconditions) self.theta_ost = time_params['theta_ost']