def acoustic_main(theta, plot=False, level=0): """ theta is the parameter vector. here we have theta 0 = x1 theta 1 = x2 theta 2 = alpha theta 3 = beta """ x1 = theta[0] x2 = theta[1] alpha = theta[2]**2.0 beta = theta[3]**2.0 ML = 2**level #c=500 Nx = 40 * ML Ny = 40 * ML p0 = dl.Point(0., 0.) p1 = dl.Point(3, 2) rx = [1., 1.5, 2.] ry = [1.99, 1.99, 1.99] Nrx = len(rx) Nry = len(ry) Nr = Nry t0 = time.time() #beta/alpha=c^2=500**2 #beta=5000**2 #alpha=10**2 #defines the source model def source(t, x1, x2): delta = dl.Expression( 'M*exp(-(x[0]-x1)*(x[0]-x1)/(a*a)-(x[1]-x2)*(x[1]-x2)/(a*a))/a*(1-2*pi2*f02*t*t)*exp(-pi2*f02*t*t)', pi2=np.pi**2, a=1E-1, f02=f02, M=1E10, x1=x1, x2=x2, t=t, degree=1) return delta B = dl.Constant(beta) A = dl.Constant(alpha) mesh = dl.RectangleMesh(p0, p1, Nx, Ny) V = dl.FunctionSpace(mesh, "Lagrange", 1) c2 = beta / alpha hmin = mesh.hmin() dt = 0.15 * hmin / (c2**0.5) # Time variables t = 0 T = 0.003 Nt = int(np.ceil(T / dt)) if plot: print('value of Nt is ' + str(Nt)) print('dt is ' + str(dt)) time_ = np.zeros(Nt) U_wave = np.zeros((Nt, Nr)) # Previous and current solution u1 = dl.interpolate(dl.Constant(0.0), V) u0 = dl.interpolate(dl.Constant(0.0), V) # Variational problem at each time u = dl.TrialFunction(V) v = dl.TestFunction(V) M, K = dl.PETScMatrix(), dl.PETScMatrix() # Assembles matrices M = dl.assemble(A * u * v * dl.dx, tensor=M) f02 = 1000**2.0 K = dl.assemble(dl.inner(B * dl.grad(u), dl.grad(v)) * dl.dx, tensor=K) # M=dl.assemble(u*v*dl.dx) # K=dl.assemble(dl.inner(dl.grad(u),dl.grad(v))*dl.dx) delta = source(t, x1, x2) f = dl.interpolate(delta, V) # ABC class ABCdom(dl.SubDomain): def inside(self, x, on_boundary): return on_boundary and (x[1] < 2.0) abc_boundaryparts = dl.MeshFunction("size_t", mesh, mesh.topology().dim() - 1) ABCdom().mark(abc_boundaryparts, 1) #self.ds = Measure("ds")[abc_boundaryparts] ds = dl.Measure('ds', domain=mesh, subdomain_data=abc_boundaryparts) weak_d = dl.inner((A * B)**0.5 * u, v) * ds(1) class_bc_abc = ABCdom() # to make copies # builds the ABS matrix D = dl.assemble(weak_d) #saves if plot: ofile = dl.File('output/ud_.pvd') u = dl.Function(V) ti = 0 while t <= T: fv = dl.assemble(f * v * dl.dx) Kun = K * u1.vector() Dun = D * (u1.vector() - u0.vector()) / dt b = fv - Kun - Dun dl.solve(M, u.vector(), b) # dl.plot(u);plt.show() # import pdb # pdb.set_trace() u.vector( )[:] = dt**2.0 * u.vector()[:] + 2.0 * u1.vector()[:] - u0.vector()[:] #u=dt**2*u+2.0*u1-u0 u0.assign(u1) u1.assign(u) for rec in range(Nr): U_wave[ti, rec] = u([rx[rec], ry[rec]]) time_[ti] = t t += dt ti += 1 delta = source(t, x1, x2) f = dl.interpolate(delta, V) # Reduce the range of the solution so that we can see the waves if plot: ofile << (u, t) #print('Total time '+str(round(time.time()-t0,3))) return U_wave, time_
def __init__(self, box, sponge, nx, ny): """ Constructor INPUTS: - box = [x_min, x_max, y_min, y_max]: the bounding box of the computational domain - nx, ny: number of elements in the horizontal (axial) and vertical (transversal) direction """ self.box = box self.mesh = dl.UnitSquareMesh(nx, ny) box_sponge = [box[0], box[1] + sponge[0], box[2], box[3] + sponge[1]] grade = GradingFunctionLin(coordinate=1, cut_point=[.6, .7], slope=6) remap = Remap(box=box_sponge) self.mesh.move(grade) self.mesh.move(remap) class InletBoundary(dl.SubDomain): def inside(self, x, on_boundary): return on_boundary and abs(x[0] - box_sponge[0]) < dl.DOLFIN_EPS class SymmetryBoundary(dl.SubDomain): def inside(self, x, on_boundary): return on_boundary and abs(x[1] - box_sponge[2]) < dl.DOLFIN_EPS class OutletBoundary(dl.SubDomain): def inside(self, x, on_boundary): return on_boundary and abs(x[0] - box_sponge[1]) < dl.DOLFIN_EPS class TopBoundary(dl.SubDomain): def inside(self, x, on_boundary): return on_boundary and abs(x[1] - box_sponge[3]) < dl.DOLFIN_EPS self.boundary_parts = dl.FacetFunction("size_t", self.mesh) self.boundary_parts.set_all(0) Gamma_inlet = InletBoundary() Gamma_inlet.mark(self.boundary_parts, self.INLET) Gamma_axis = SymmetryBoundary() Gamma_axis.mark(self.boundary_parts, self.AXIS) Gamma_outlet = OutletBoundary() Gamma_outlet.mark(self.boundary_parts, self.OUTLET) Gamma_top = TopBoundary() Gamma_top.mark(self.boundary_parts, self.TOP) self.ds = dl.Measure("ds")[self.boundary_parts] class PhysicalDomain(dl.SubDomain): def inside(self, x, on_boundary): return x[0] < box[1] + dl.DOLFIN_EPS and x[ 1] < box[3] + dl.DOLFIN_EPS self.domain_parts = dl.CellFunction("size_t", self.mesh) self.domain_parts.set_all(self.SPONGE) P_Domain = PhysicalDomain() P_Domain.mark(self.domain_parts, self.PHYSICAL) self.dx = dl.Measure("dx")[self.domain_parts] self.xfun, self.yfun = dl.MeshCoordinates(self.mesh) self.x_start = dl.Constant(box[1] + .5 * sponge[0]) self.x_width = dl.Constant(.5 * sponge[0]) self.y_start = dl.Constant(box[3] + .5 * sponge[1]) self.y_width = dl.Constant(.5 * sponge[1]) self.s_x = dl.Constant(1.) + ( (dl.Constant(100) / self.x_width) * dl.max_value(self.xfun - self.x_start, dl.Constant(0.)))**2 self.s_y = dl.Constant(1.) + ( (dl.Constant(100) / self.y_width) * dl.max_value(self.yfun - self.y_start, dl.Constant(0.)))**2 self.sponge_fun = self.s_x * self.s_y
# f1 = [df.XDMFFile(comm, '../data/{}/uf{}.xdmf'.format(data_dir, i)) for i in range(N)] f2 = df.XDMFFile(comm, '../data/{}/mf.xdmf'.format(data_dir)) f3 = [df.XDMFFile(comm, '../data/{}/p{}.xdmf'.format(data_dir, i)) for i in range(N)] f4 = df.XDMFFile(comm, '../data/{}/du.xdmf'.format(data_dir)) # # Initialize 'set_xdmf_parameters' for XDMFFiles to be created # [set_xdmf_parameters(f1[i]) for i in range(N)] set_xdmf_parameters(f2) [set_xdmf_parameters(f3[i]) for i in range(N)] set_xdmf_parameters(f4) # # # Define new measures associated with exterior boundaries. dx = df.Measure("dx") ds = df.Measure("ds")(subdomain_data=boundaries) # # Set start variables for the calculations sum_fluid_mass = 0 theor_fluid_mass = 0 sum_disp = 0 domain_area = 1.0 # # phi = params.p['Parameter']["phi"] rho = params.p['Parameter']["rho"] qi = params.p['Parameter']["qi"] dt = params.p['Parameter']["dt"] tf = params.p['Parameter']["tf"] #
boundaries.set_all(mark["Internal"]) wall = Noslip() wall.mark(boundaries, mark["wall"]) left = Left() left.mark(boundaries, mark["inlet"]) right = Right() right.mark(boundaries, mark["outlet"]) #read viscosity coefficient from file mu = Constant(0.001) #Define HDG element and function space element_cls = geopart.stokes.incompressible.HDG2() W = element_cls.function_space(mesh) ds = dolfin.Measure('ds', domain=mesh, subdomain_data=boundaries) n = dolfin.FacetNormal(mesh) #Define boundary condition U = element_cls.create_solution_variable(W) p_in = dolfin.Constant(1.0) # pressure inlet p_out = dolfin.Constant(0.0) # pressure outlet noslip = dolfin.Constant([0.0] * mesh.geometry().dim()) # no-slip wall #Boundary conditions gN1 = (-p_out * dolfin.Identity(mesh.geometry().dim())) * n Neumann_outlet = dg.DGNeumannBC(ds(mark["outlet"]), gN1) gN2 = (-p_in * dolfin.Identity(mesh.geometry().dim())) * n Neumann_inlet = dg.DGNeumannBC(ds(mark["inlet"]), gN2) Dirichlet_wall = dg.DGDirichletBC(ds(mark["wall"]), noslip)
extH1 = dlfn.FunctionSpace(subMeshes[extId], P1) # size of function spaces m = intHCurl.dim() nn = intH1.dim() n = extH1.dim() # test and trial functions A = dlfn.TrialFunction(intHCurl) B = dlfn.TestFunction(intHCurl) u = dlfn.TrialFunction(intH1) phi = dlfn.TrialFunction(extH1) psi = dlfn.TestFunction(extH1) # measures and normal vectors dA, dV, normals = dict(), dict(), dict() for i in subIds: dA[i] = dlfn.Measure("ds", subMeshes[i], subdomain_data=facetSubMeshFuns[i]) dV[i] = dlfn.Measure("dx", subMeshes[i]) normals[i] = dlfn.FacetNormal(subMeshes[i]) intV = dlfn.assemble(dlfn.Constant(1.0) * dV[intId]) extV = dlfn.assemble(dlfn.Constant(1.0) * dV[extId]) #------------------------------------------------------------------------------# # solution functions #------------------------------------------------------------------------------# sol_A = dlfn.Function(intHCurl) sol_A0 = dlfn.Function(intHCurl) sol_phi = dlfn.Function(extH1) #------------------------------------------------------------------------------# # weak forms and assembly in interior #------------------------------------------------------------------------------# # linear forms in interior domain
def forward(theta,l=0,plot=False): # discretization Nx=int(28*2.**l) Ny=int(28*2.**l) #domain p0=dl.Point(0.,0.) p1=dl.Point(3,2) # creates mesh and function space mesh = dl.RectangleMesh(p0,p1,Nx,Ny) V=dl.FunctionSpace(mesh, "Lagrange", 1) #receiver location N_rec_x=5 rx=np.linspace(1,2,N_rec_x) ry=2*np.ones(len(rx)) # Source location x1=1.5 x2=1. cm=4 c_mult=0.1*cm #Obtains C2 #PRIOR=prior.prior_measure(mesh) #C2=PRIOR.sample(exp=True) #C2=cm+c_mult*np.exp(theta) C2=(theta) c=dl.Function(V) c.vector()[:]=C2[:] #dl.plot(c) A=dl.Constant(1.0) #PRIOR.plot_prior(C2) hmin=mesh.hmin() dt=0.1*hmin/(cm**2.0) #%% B=10.+c*c Nrx=len(rx) Nry=len(ry) Nr=Nry #beta/alpha=c^2=500**2 #beta=5000**2 #alpha=10**2 #defines the source model def source(t,x1,x2): delta =dl.Expression('M*exp(-(x[0]-x1)*(x[0]-x1)/(a*a)-(x[1]-x2)*(x[1]-x2)/(a*a))/a*(1-2*pi2*f02*t*t)*exp(-pi2*f02*t*t)' ,pi2=np.pi**2,a=6E-2, f02=f02, M=1E5,x1=x1,x2=x2,t=t,degree=1) return delta # Time variables t = 0; T =0.6 Nt=int(np.ceil(T/dt)) if plot: print('value of Nt is '+str(Nt)) print('dt is '+str(dt)) time_=np.zeros(Nt) U_wave=np.zeros((Nt,Nr)) # Previous and current solution u1= dl.interpolate(dl.Constant(0.0), V) u0= dl.interpolate(dl.Constant(0.0), V) # Variational problem at each time u = dl.TrialFunction(V) v = dl.TestFunction(V) M, K = dl.PETScMatrix(), dl.PETScMatrix()# Assembles matrices M=dl.assemble(A*u*v*dl.dx,tensor=M) f02=1000**2.0 K=dl.assemble(dl.inner(B*dl.grad(u),dl.grad(v))*dl.dx,tensor=K) # mass_form = A*u*v*dl.dx # mass_action_form = dl.action(mass_form, dl.Constant(1)) # M_consistent = dl.assemble(mass_form) # print("Consistent mass matrix:\n", np.array_str(M_consistent.array(), precision=3)) # M_lumped = dl.assemble(mass_form) # M_lumped.zero() # M_lumped.set_diagonal(dl.assemble(mass_action_form)) # print("Lumped mass matrix:\n", np.array_str(M_lumped.array(), precision=3)) # M=M_lumped if plot: ofile=dl.File('output/ud_.pvd') # M=dl.assemble(u*v*dl.dx) # K=dl.assemble(dl.inner(dl.grad(u),dl.grad(v))*dl.dx) delta =source(t,x1,x2) f=dl.interpolate(delta,V) # ABC class ABCdom(dl.SubDomain): def inside(self, x, on_boundary): return on_boundary and (x[1] < 2.0) abc_boundaryparts = dl.MeshFunction("size_t", mesh, mesh.topology().dim()-1) ABCdom().mark(abc_boundaryparts, 1) #self.ds = Measure("ds")[abc_boundaryparts] ds = dl.Measure('ds', domain=mesh, subdomain_data=abc_boundaryparts) weak_d = dl.inner((A*B)**0.5*u,v)*ds(1) #class_bc_abc = ABCdom() # to make copies # builds the ABS matrix D = dl.assemble(weak_d) # Find inverse mm=sp.csc_matrix(M.array()) I=sp.csc_matrix(np.eye(len(M.array()))) Minv=spsolve(mm, I) #%% qoi=0 #saves if plot: ofile=dl.File('output/ud_.pvd') u=dl.Function(V) ti=0 while t <= T: # if ti%100==0: # print('time step '+str(ti)+' out of '+str(Nt)) fv=dl.assemble(f*v*dl.dx) Kun=K*u1.vector() Dun=D*(u1.vector()-u0.vector())/dt b=fv-Kun-Dun #B=dl.Function(V) #B.vector()[:]=b[ u.vector()[:]=Minv@b[:] #dl.solve(M, u.vector(), b) # M_vect = dl.assemble(mass_action_form) # u = dl.Function(V) # u.vector().set_local(B.vector().get_local()/M_vect.get_local()) # dl.plot(u);plt.show() # import pdb # pdb.set_trace() u.vector()[:]=dt**2.0*u.vector()[:]+2.0*u1.vector()[:]-u0.vector()[:] #u=dt**2*u+2.0*u1-u0 u0.assign(u1) u1.assign(u) for rec in range(Nr): U_wave[ti,rec]=u([rx[rec],ry[rec]]) time_[ti]=t t += dt ti+=1 f =source(t,x1,x2) #f=dl.interpolate(delta,V) # Reduce the range of the solution so that we can see the waves if plot: ofile << (u, t) qoi1=dl.exp(dl.assemble(c*dl.dx)) qoi2=dl.assemble(dl.exp(c)*dl.dx) qoi3=dl.assemble(B*dl.dx) qoi4=6.0+dl.assemble(c*dl.dx) qoi5=np.max(c.vector()[:]) qoi6=10.0-c([1.5,1]) qoi7=np.exp(c([1.5,1])) # import pdb # pdb.set_trace() qoi=np.array((qoi1,qoi2,qoi3,qoi4,qoi5,qoi6,qoi7)) #np.save('wave.npy',U_wave) return U_wave, qoi
def get_measure(mesh, boundaries): return df.Measure("ds", domain=mesh, subdomain_data=boundaries)
def gen_bccont_fems(scheme='TH', bccontrol=True, verbose=False, strtomeshfile='', strtophysicalregions='', inflowvel=1., inflowprofile='parabola', movingwallcntrl=False, strtobcsobs=''): """ dictionary for the fem items for a general 2D flow setup with * inflow/outflow * boundary control Parameters ---------- scheme : {None, 'CR', 'TH'} the finite element scheme to be applied, 'CR' for Crouzieux-Raviart,\ 'TH' for Taylor-Hood, overrides `pdgree`, `vdgree`, defaults to `None` bccontrol : boolean, optional whether to consider boundary control via penalized Robin \ defaults to `True` movingwallcntrl : boolean, optional whether control is via moving boundaries Returns ------- femp : a dictionary with the keys: * `V`: FEM space of the velocity * `Q`: FEM space of the pressure * `diribcs`: list of the (Dirichlet) boundary conditions * `dbcsinds`: list vortex indices with (Dirichlet) boundary conditions * `dbcsvals`: list of values of the (Dirichlet) boundary conditions * `dirip`: list of the (Dirichlet) boundary conditions \ for the pressure * `fv`: right hand side of the momentum equation * `fp`: right hand side of the continuity equation * `charlen`: characteristic length of the setup * `odcoo`: dictionary with the coordinates of the \ domain of observation """ # Load mesh mesh = dolfin.Mesh(strtomeshfile) if scheme == 'CR': V = dolfin.VectorFunctionSpace(mesh, "CR", 1) Q = dolfin.FunctionSpace(mesh, "DG", 0) elif scheme == 'TH': V = dolfin.VectorFunctionSpace(mesh, "CG", 2) Q = dolfin.FunctionSpace(mesh, "CG", 1) boundaries = dolfin.MeshFunction('size_t', mesh, strtophysicalregions) with open(strtobcsobs) as f: cntbcsdata = json.load(f) inflowgeodata = cntbcsdata['inflow'] inflwpe = inflowgeodata['physical entity'] inflwin = np.array(inflowgeodata['inward normal']) inflwxi = np.array(inflowgeodata['xone']) inflwxii = np.array(inflowgeodata['xtwo']) leninflwb = np.linalg.norm(inflwxi-inflwxii) if inflowprofile == 'block': inflwprfl = dolfin.\ Expression(('cv*no', 'cv*nt'), cv=inflowvel, no=inflwin[0], nt=inflwin[1], element=V.ufl_element()) elif inflowprofile == 'parabola': inflwprfl = InflowParabola(degree=2, lenb=leninflwb, xone=inflwxi, normalvec=inflwin, inflowvel=inflowvel) bcin = dolfin.DirichletBC(V, inflwprfl, boundaries, inflwpe) diribcu = [bcin] # ## THE WALLS wallspel = cntbcsdata['walls']['physical entity'] gzero = dolfin.Constant((0, 0)) for wpe in wallspel: diribcu.append(dolfin.DirichletBC(V, gzero, boundaries, wpe)) bcdict = diribcu[-1].get_boundary_values() if not bccontrol: # treat the control boundaries as walls try: for cntbc in cntbcsdata['controlbcs']: diribcu.append(dolfin.DirichletBC(V, gzero, boundaries, cntbc['physical entity'])) except KeyError: pass # no control boundaries mvwdbcs = [] mvwtvs = [] try: for cntbc in cntbcsdata['moving walls']: center = np.array(cntbc['geometry']['center']) radius = cntbc['geometry']['radius'] if cntbc['type'] == 'circle': omega = 1. if movingwallcntrl else 0. rotcyl = RotatingCircle(degree=2, radius=radius, xcenter=center, omega=omega) else: raise NotImplementedError() mvwdbcs.append(dolfin.DirichletBC(V, rotcyl, boundaries, cntbc['physical entity'])) except KeyError: pass # no moving walls defined if not movingwallcntrl: diribcu.extend(mvwdbcs) # add the moving walls to the diri bcs mvwdbcs = [] # Create outflow boundary condition for pressure # TODO XXX why zero pressure?? is this do-nothing??? outflwpe = cntbcsdata['outflow']['physical entity'] g2 = dolfin.Constant(0) bc2 = dolfin.DirichletBC(Q, g2, boundaries, outflwpe) # Collect boundary conditions bcp = [bc2] # Create right-hand side function fv = dolfin.Constant((0, 0)) fp = dolfin.Constant(0) def initial_conditions(self, V, Q): u0 = dolfin.Constant((0, 0)) p0 = dolfin.Constant(0) return u0, p0 dbcinds, dbcvals = [], [] for bc in diribcu: bcdict = bc.get_boundary_values() dbcvals.extend(list(bcdict.values())) dbcinds.extend(list(bcdict.keys())) mvwbcinds, mvwbcvals = [], [] for bc in mvwdbcs: bcdict = bc.get_boundary_values() mvwbcvals.extend(list(bcdict.values())) mvwbcinds.extend(list(bcdict.keys())) # ## Control boundaries bcpes, bcshapefuns, bcds = [], [], [] if bccontrol: for cbc in cntbcsdata['controlbcs']: cpe = cbc['physical entity'] cxi, cxii = np.array(cbc['xone']), np.array(cbc['xtwo']) csf = _get_cont_shape_fun2D(xi=cxi, xii=cxii, element=V.ufl_element()) bcshapefuns.append(csf) bcpes.append(cpe) bcds.append(dolfin.Measure("ds", subdomain_data=boundaries)(cpe)) # ## Lift Drag Computation try: ldsurfpe = cntbcsdata['lift drag surface']['physical entity'] liftdragds = dolfin.Measure("ds", subdomain_data=boundaries)(ldsurfpe) bclds = dolfin.DirichletBC(V, gzero, boundaries, ldsurfpe) bcldsdict = bclds.get_boundary_values() ldsbcinds = list(bcldsdict.keys()) except KeyError: liftdragds = None # no domain specified for lift/drag ldsbcinds = None try: outflwpe = cntbcsdata['outflow']['physical entity'] outflowds = dolfin.Measure("ds", subdomain_data=boundaries)(outflwpe) except KeyError: outflowds = None # no domain specified for outflow try: odcoo = cntbcsdata['observation-domain-coordinates'] except KeyError: odcoo = None gbcfems = dict(V=V, Q=Q, dbcinds=dbcinds, dbcvals=dbcvals, mvwbcinds=mvwbcinds, mvwbcvals=mvwbcvals, mvwtvs=mvwtvs, dirip=bcp, outflowds=outflowds, # contrbcssubdomains=bcsubdoms, liftdragds=liftdragds, ldsbcinds=ldsbcinds, contrbcmeshfunc=boundaries, contrbcspes=bcpes, contrbcsshapefuns=bcshapefuns, cntrbcsds=bcds, odcoo=odcoo, fv=fv, fp=fp, charlen=cntbcsdata['characteristic length'], mesh=mesh) return gbcfems
id_subdomain_fix = 1 # Fixed boundary id id_subdomain_msr = 2 # Loaded boundary id id_subdomains_dic = 3 # displacement field measurement boundary id boundary_fix.mark(boundary_markers, id_subdomain_fix) boundary_msr.mark(boundary_markers, id_subdomain_msr) boundary_dic.mark(boundary_markers, id_subdomains_dic) ### Integration measures dx = dolfin.dx(domain=mesh) # for the whole domain ds = dolfin.ds(domain=mesh) # for the entire boundary ds_msr_T = dolfin.Measure('ds', mesh, subdomain_id=id_subdomain_msr, subdomain_data=boundary_markers) ds_msr_u = dolfin.Measure('ds', mesh, subdomain_id=id_subdomains_dic, subdomain_data=boundary_markers) ### Finite element function spaces V = dolfin.VectorFunctionSpace(mesh, 'CG', FINITE_ELEMENT_DEGREE) # Displacement field u = Function(V) ### Dirichlet boundary conditions
def comp_modeshape(mat_obj, mesh_obj, bc, save_path, neig): E = mat_obj.E rho = mat_obj.rho nu = mat_obj.nu Rext = mesh_obj.Rext Rint = mesh_obj.Rint if mesh_obj.h == 0.0: mesh = mesh_obj.create() elif mesh_obj.h > 0.0: mesh, cell_markers, facet_markers, tag_map = mesh_obj.load() cell_markers, facet_markers = define_markers(mesh, Rext, Rint) # save marker functions into files readable with Paraview df.File(save_path + "Marker_Functions/" + "cell_markers.pvd") << cell_markers df.File(save_path + "Marker_Functions/" + "facet_markers.pvd") << facet_markers # define subdomains and cell measurement dx = df.Measure("dx", domain=mesh, subdomain_data=cell_markers) # Parameters # Lame coefficient for constitutive relation def mu_func(E, nu): return E / 2.0 / (1.0 + nu) def lmbda_func(E, nu): return E * nu / (1.0 + nu) / (1.0 - 2.0 * nu) def E_func(mu, lmbda): return mu * (3.0 * lmbda + 2.0 * mu) / (lmbda + mu) def nu_func(mu, lmbda): return lmbda / (2.0 * (lmbda + mu)) s_unit = "m" t_unit = "ms" w_unit = "kg" E = E * convert_unit(1.0, "kg", w_unit) / ( convert_unit(1.0, "m", s_unit) * convert_unit(1.0, "s", t_unit)**2) rho = rho * convert_unit(1.0, "kg", w_unit) / (convert_unit( 1.0, "m", s_unit)**3) mu = mu_func(E, nu) lmbda = lmbda_func(E, nu) # dimention dim = mesh.topology().dim() # mesh coordinate x_coord = mesh.coordinates() # strain tensor def eps(v): return df.sym(df.grad(v)) # isotropic stress tensor def sigma(v): dim = v.geometric_dimension() return 2.0 * mu * eps(v) + lmbda * df.tr(eps(v)) * df.Identity(dim) # Define function space V = df.VectorFunctionSpace(mesh, "Lagrange", degree=1) du = df.TrialFunction(V) tu = df.TestFunction(V) # =========================== define eigenvalue problem =========================== # eigenvalue problem: [K]\{U\}=\lambda[M]\{U\} # eigenfrequency: \lambda=\omega^2 k_form = df.inner(sigma(du), eps(tu)) * dx l_form = df.Constant(1.0) * tu[0] * dx m_form = rho * df.dot(du, tu) * dx # =========================== Dirichlet Boundary Conditions =========================== if dim == 2: zero = df.Constant((0.0, 0.0)) elif dim == 3: zero = df.Constant((0.0, 0.0, 0.0)) # clamped outside dbc1 = df.DirichletBC(V, zero, facet_markers, 1) # clamped inside dbc2 = df.DirichletBC(V, zero, facet_markers, 2) # clamped inside and outside dbc3 = [dbc1, dbc2] def simulation_isotropic_c(save_path, Dbc, neig): df.File(save_path + "Marker_Functions/" + "cell_markers.pvd") << cell_markers df.File(save_path + "Marker_Functions/" + "facet_markers.pvd") << facet_markers eigensolver, K, M = define_eigen_solver(k_form, l_form, m_form, Dbc, "c") eigensolver.solve(neig) # converged eigenvalues and number of iterations conv = eigensolver.get_number_converged() # no_of_iterations = eigensolver.get_iteration_number() # does not have this function if mpi_rank == 0: print("\nNumber of converged eigenvalues: {:3d}".format(conv)) # print('\nNumber of iterations: {:3d}'.format(no_of_iterations)) freqs = get_mode_shape_and_frequency( save_path, eigensolver, V, s_unit, t_unit, w_unit, E, nu, rho, neig, K, M, m_form, k_form, ) return freqs def simulation_isotropic_ff(save_path, k_form, m_form, neig): df.File(save_path + "Marker_Functions/" + "cell_markers.pvd") << cell_markers df.File(save_path + "Marker_Functions/" + "facet_markers.pvd") << facet_markers eigensolver, K, M = define_eigen_solver(k_form, l_form, m_form, [], "ff") eigensolver.solve(neig) freqs = get_mode_shape_and_frequency( save_path, eigensolver, V, s_unit, t_unit, w_unit, E, nu, rho, neig, K, M, m_form, k_form, ) return freqs if bc == "FF": save_path_1 = save_path + "free_free/" freqs = simulation_isotropic_ff(save_path_1, k_form, m_form, neig) if bc == "CF": save_path_1 = save_path + "clamped_free/" freqs = simulation_isotropic_c(save_path_1, dbc2, neig) if bc == "FC": save_path_1 = save_path + "free_clamped/" freqs = simulation_isotropic_c(save_path_1, dbc1, neig) if bc == "CC": save_path_1 = save_path + "clamped_clamped/" freqs = simulation_isotropic_c(save_path_1, dbc3, neig) return freqs
def variational_forms(self, dt: df.Constant) -> Tuple[Any, Any]: """Create the variational forms corresponding to the given discretization of the given system of equations. *Arguments* kn (:py:class:`ufl.Expr` or float) The time step *Returns* (lhs, rhs) (:py:class:`tuple` of :py:class:`ufl.Form`) """ # Extract theta parameter and conductivities theta = self._parameters.theta Mi = self._intracellular_conductivity Me = self._extracellular_conductivity # Define variational formulation if self._parameters.linear_solver_type == "direct": v, u, multiplier = df.TrialFunctions(self._VUR) v_test, u_test, multiplier_test = df.TestFunctions(self._VUR) else: v, u = df.TrialFunctions(self._VUR) v_test, u_test = df.TestFunctions(self._VUR) Dt_v = (v - self._v_prev)/dt Dt_v *= self._chi_cm # Chi is surface to volume aration. Cm is capacitance v_mid = theta*v + (1.0 - theta)*self._v_prev # Set-up measure and rhs from stimulus dOmega = df.Measure("dx", domain=self._mesh, subdomain_data=self._cell_function) dGamma = df.Measure("ds", domain=self._mesh, subdomain_data=self._interface_function) # Loop over all domains G = Dt_v*v_test*dOmega() for key in self._cell_tags - self._restrict_tags: G += df.inner(Mi[key]*df.grad(v_mid), df.grad(v_test))*dOmega(key) G += df.inner(Mi[key]*df.grad(v_mid), df.grad(u_test))*dOmega(key) for key in self._cell_tags: G += df.inner(Mi[key]*df.grad(u), df.grad(v_test))*dOmega(key) G += df.inner((Mi[key] + Me[key])*df.grad(u), df.grad(u_test))*dOmega(key) # If Lagrangian multiplier if self._parameters.linear_solver_type == "direct": G += (multiplier_test*u + multiplier*u_test)*dOmega(key) for key in set(self._interface_tags): # Default to 0 if not defined for tag G += self._neumann_bc.get(key, df.Constant(0))*u_test*dGamma(key) # Interface conditions csf_gm = 2 gm_wm = 1 csf = 3 gm = 2 wm = 1 csf_gm_interface = df.inner((Me[gm] - Me[csf])*df.grad(u), df.grad(u_test))*dGamma(csf_gm) gm_wm_interface = df.inner((Me[gm] - Me[wm])*df.grad(u), df.grad(u_test))*dGamma(gm_wm) G += csf_gm_interface G += gm_wm_interface a, L = df.system(G) return a, L
def simulate_FEM(): import dolfin as df df.parameters['allow_extrapolation'] = False # Define mesh mesh = df.Mesh(join(mesh_folder, "{}.xml".format(mesh_name))) subdomains = df.MeshFunction("size_t", mesh, join(mesh_folder, "{}_physical_region.xml".format(mesh_name))) boundaries = df.MeshFunction("size_t", mesh, join(mesh_folder, "{}_facet_region.xml".format(mesh_name))) print("Number of cells in mesh: ", mesh.num_cells()) np.save(join(out_folder, "mesh_coordinates.npy"), mesh.coordinates()) sigma_vec = df.Constant(sigma) V = df.FunctionSpace(mesh, "CG", 2) v = df.TestFunction(V) u = df.TrialFunction(V) ds = df.Measure("ds", domain=mesh, subdomain_data=boundaries) dx = df.Measure("dx", domain=mesh, subdomain_data=subdomains) a = df.inner(sigma_vec * df.grad(u), df.grad(v)) * dx(1) # This corresponds to Neumann boundary conditions zero, i.e. # all outer boundaries are insulating. L = df.Constant(0) * v * dx # Define Dirichlet boundary conditions outer cylinder boundaries (ground) bcs = [df.DirichletBC(V, 0.0, boundaries, 1)] for t_idx in range(num_tsteps): f_name = join(out_folder, "phi_xz_t_vec_{}.npy".format(t_idx)) # if os.path.isfile(f_name): # print("skipping ", f_name) # continue print("Time step {} of {}".format(t_idx, num_tsteps)) phi = df.Function(V) A = df.assemble(a) b = df.assemble(L) [bc.apply(A, b) for bc in bcs] # Adding point sources from neural simulation for s_idx, s_pos in enumerate(source_pos): point = df.Point(s_pos[0], s_pos[1], s_pos[2]) delta = df.PointSource(V, point, imem[s_idx, t_idx]) delta.apply(b) df.solve(A, phi.vector(), b, 'cg', "ilu") # df.File(join(out_folder, "phi_t_vec_{}.xml".format(t_idx))) << phi # np.save(join(out_folder, "phi_t_vec_{}.npy".format(t_idx)), phi.vector()) plot_and_save_simulation_results(phi, t_idx)
df.CellType.Type.quadrilateral, ) ''' 2. Define the traction boundary conditions ''' # here traction force is applied on the middle of the right edge class TractionBoundary(df.SubDomain): def inside(self, x, on_boundary): return ((abs(x[1] - LENGTH_Y/2) < LENGTH_Y/NUM_ELEMENTS_Y + df.DOLFIN_EPS) and (abs(x[0] - LENGTH_X ) < df.DOLFIN_EPS*1.5e15)) # Define the traction boundary sub_domains = df.MeshFunction('size_t', mesh, mesh.topology().dim() - 1) upper_edge = TractionBoundary() upper_edge.mark(sub_domains, 6) dss = df.Measure('ds')(subdomain_data=sub_domains) f = df.Constant((0, -1. / 4 )) ''' 3. Setup the PDE problem ''' # PDE problem pde_problem = PDEProblem(mesh) # Add input to the PDE problem: # name = 'density', function = density_function (function is the solution vector here) density_function_space = df.FunctionSpace(mesh, 'DG', 0) density_function = df.Function(density_function_space) pde_problem.add_input('density', density_function) # Add states to the PDE problem (line 58):
def __init__( self, time: df.Constant, mesh: df.Mesh, conductivity: Dict[int, df.Expression], conductivity_ratio: Dict[int, df.Expression], cell_function: df.MeshFunction, cell_tags: CellTags, interface_function: df.MeshFunction, interface_tags: InterfaceTags, parameters: CoupledMonodomainParameters, neumann_boundary_condition: Dict[int, df.Expression] = None, v_prev: df.Function = None ) -> None: self._time = time self._mesh = mesh self._conductivity = conductivity self._cell_function = cell_function self._cell_tags = cell_tags self._interface_function = interface_function self._interface_tags = interface_tags self._parameters = parameters if neumann_boundary_condition is None: self._neumann_boundary_condition: Dict[int, df.Expression] = dict() else: self._neumann_boundary_condition = neumann_boundary_condition if not set(conductivity.keys()) == set(conductivity_ratio.keys()): raise ValueError("intracellular conductivity and lambda does not have natching keys.") self._lambda = conductivity_ratio # Function spaces self._function_space = df.FunctionSpace(mesh, "CG", 1) # Test and trial and previous functions self._v_trial = df.TrialFunction(self._function_space) self._v_test = df.TestFunction(self._function_space) self._v = df.Function(self._function_space) if v_prev is None: self._v_prev = df.Function(self._function_space) else: # v_prev is shipped from an odesolver. self._v_prev = v_prev _cell_tags = set(self._cell_tags) _cell_function_values = set(self._cell_function.array()) if not _cell_tags <= _cell_function_values: msg = f"Cell function does not contain {_cell_tags - _cell_function_values}" raise ValueError(msg) _interface_tags = set(self._interface_tags) _interface_function_values = {*set(self._interface_function.array()), None} if not _interface_tags <= _interface_function_values: msg = f"interface function does not contain {_interface_tags - _interface_function_values}." raise ValueError(msg) # Crete integration measures -- Interfaces self._dGamma = df.Measure("ds", domain=self._mesh, subdomain_data=self._interface_function) # Crete integration measures -- Cells self._dOmega = df.Measure("dx", domain=self._mesh, subdomain_data=self._cell_function) # Create variational forms self._timestep = df.Constant(self._parameters.timestep) self._lhs, self._rhs = self._variational_forms() # Preassemble left-hand side (will be updated if time-step changes) self._lhs_matrix = df.assemble(self._lhs) self._rhs_vector = df.Vector(mesh.mpi_comm(), self._lhs_matrix.size(0)) self._lhs_matrix.init_vector(self._rhs_vector, 0) self._linear_solver = create_linear_solver(self._lhs_matrix, self._parameters)
def step(self, t0: float, t1: float) -> None: r"""Solve on the given time interval (t0, t1). *Arguments* interval (:py:class:`tuple`) The time interval (t0, t1) for the step *Invariants* Assuming that v\_ is in the correct state for t0, gives self.v in correct state at t1. """ # Extract interval and thus time-step k_n = df.Constant(t1 - t0) # Extract theta parameter and conductivities theta = self.parameters["theta"] M_i = self._M_i # Set time t = t0 + theta * (t1 - t0) self.time.assign(t) # Get physical parameters chi = self.parameters["Chi"] capacitance = self.parameters["Cm"] lam = self.parameters["lambda"] lam_frac = df.Constant(lam / (1 + lam)) # Define variational formulation v = df.TrialFunction(self.V) w = df.TestFunction(self.V) Dt_v_k_n = (v - self.v_) / k_n Dt_v_k_n *= chi * capacitance v_mid = theta * v + (1.0 - theta) * self.v_ dz = df.Measure("dx", domain=self._mesh, subdomain_data=self._cell_domains) db = df.Measure("ds", domain=self._mesh, subdomain_data=self._facet_domains) # dz, rhs = rhs_with_markerwise_field(self._I_s, self._mesh, w) cell_tags = map(int, set( self._cell_domains.array())) # np.int64 does not work facet_tags = map(int, set(self._facet_domains.array())) for key in cell_tags: G = Dt_v_k_n * w * dz(key) G += lam_frac * df.inner(M_i[key] * df.grad(v_mid), df.grad(w)) * dz(key) if self._I_s is None: G -= chi * df.Constant(0) * w * dz(key) else: G -= chi * self._I_s * w * dz(key) # Define variational problem a, L = df.system(G) pde = df.LinearVariationalProblem(a, L, self.v) # Set-up solver solver_type = self.parameters["linear_solver_type"] solver = df.LinearVariationalSolver(pde) solver.solve()
def closed_loop(parameters, advanced_parameters, CL_parameters): #################### ### Gernal setup ### #################### setup_general_parameters() df.PETScOptions.set('ksp_type', 'preonly') df.PETScOptions.set('pc_factor_mat_solver_package', 'mumps') df.PETScOptions.set("mat_mumps_icntl_7", 6) ############ ### MESH ### ############ patient = parameters['patient'] meshname = parameters['mesh_name'] mesh = parameters['mesh'] mesh = patient.mesh X = df.SpatialCoordinate(mesh) N = df.FacetNormal(mesh) # Cycle lenght BCL = CL_parameters['BCL'] t = CL_parameters['t'] # Time increment dt = CL_parameters['dt'] # End-Diastolic volume ED_vol = CL_parameters['ED_vol'] ##################################### # Parameters for Windkessel model ### ##################################### # Aorta compliance (reduce) Cao = CL_parameters['Cao'] # Venous compliace Cven = CL_parameters['Cven'] # Dead volume Vart0 = CL_parameters['Vart0'] Vven0 = CL_parameters['Vven0'] # Aortic resistance Rao = CL_parameters['Rao'] Rven = CL_parameters['Rven'] # Peripheral resistance (increase) Rper = CL_parameters['Rper'] V_ven = CL_parameters['V_ven'] V_art = CL_parameters['V_art'] # scale geometry to match hemodynamics parameters mesh.coordinates()[:] *= CL_parameters['mesh_scaler'] ###################### ### Material model ### ###################### material_model = advanced_parameters['material_model'] #################### ### Active model ### #################### active_model = advanced_parameters['active_model'] T_ref = advanced_parameters['T_ref'] # These can be used to adjust the contractility gamma_base = parameters['gamma']['gamma_base'] gamma_mid = parameters['gamma']['gamma_mid'] gamma_apical = parameters['gamma']['gamma_apical'] gamma_apex = parameters['gamma']['gamma_apex'] gamma_arr = np.array(gamma_base + gamma_mid + gamma_apical + gamma_apex) # gamma_arr = np.ones(17) ############## ### OUTPUT ### ############## dir_results = "results" if not os.path.exists(dir_results): os.makedirs(dir_results) disp_file = df.XDMFFile(df.mpi_comm_world(), "{}/displacement.xdmf".format(dir_results)) pv_data = {"pressure":[], "volume":[]} output = "/".join([dir_results, "output_{}_ed{}.h5".format(meshname, ED_vol)]) G = RegionalParameter(patient.sfun) G.vector()[:] = gamma_arr G_ = df.project(G.get_function(), G.get_ind_space()) f_gamma = df.XDMFFile(df.mpi_comm_world(), "{}/activation.xdmf".format(dir_results)) f_gamma.write(G_) ######################## ### Setup Parameters ### ######################## params = setup_application_parameters(material_model) params.remove("Material_parameters") matparams = df.Parameters("Material_parameters") for k, v in advanced_parameters['mat_params'].iteritems(): matparams.add(k,v) params.add(matparams) params["base_bc"] = parameters['BC_type'] params["base_spring_k"] = advanced_parameters['spring_constant'] # params["base_bc"] = "fixed" params["active_model"] = active_model params["T_ref"] = T_ref params["gamma_space"] = "regional" ###################### ### Initialization ### ###################### # Solver paramters check_patient_attributes(patient) solver_parameters, _, _ = make_solver_params(params, patient) # Cavity volume V0 = df.Expression("vol",vol = 0, name = "Vtarget", degree=1) solver_parameters["volume"] = V0 # Solver solver = LVSolver3Field(solver_parameters, use_snes=True) df.set_log_active(True) solver.parameters["solve"]["snes_solver"]["report"] =True solver.parameters["solve"]["snes_solver"]['maximum_iterations'] = 50 # Surface measure ds = df.Measure("exterior_facet", domain = solver.parameters["mesh"], subdomain_data = solver.parameters["facet_function"]) dsendo = ds(solver.parameters["markers"]["ENDO"][0]) # Set cavity volume V0.vol = df.assemble(solver._V_u*dsendo) print V0.vol # Initial solve solver.solve() # Save initial state w = solver.get_state() u, p, pinn = w.split(deepcopy=True) U_save = df.Function(u.function_space(), name = "displacement") U_save.assign(u) disp_file.write(U_save) file_format = "a" if os.path.isfile('pv_data_plot.txt') else "w" pv_data_plot = open('pv_data_plot.txt', file_format) pv_data_plot.write('{},'.format(float(pinn)/1000.0)) pv_data_plot.write('{}\n'.format(V0.vol)) pv_data["pressure"].append(float(pinn)/1000.0) pv_data["volume"].append(V0.vol) # Active contraction from force import ca_transient V_real = df.FunctionSpace(mesh, "R", 0) gamma = solver.parameters["material"].get_gamma() # times = np.linspace(0,200,200) # target_gamma = ca_transient(times) # plt.plot(target_gamma) # plt.show() # exit()g ####################### ### Inflation Phase ### ####################### inflate = True # Check if inflation allready exist if os.path.isfile(output): with df.HDF5File(df.mpi_comm_world(), output, "r") as h5file: if h5file.has_dataset("inflation"): h5file.read(solver.get_state(), "inflation") print ("\nInflation phase fetched from output file.") inflate = False if inflate: print ("\nInflate geometry to volume : {}\n".format(ED_vol)) initial_step = int((ED_vol - V0.vol) / 10.0) +1 control_values, prev_states = iterate("expression", solver, V0, "vol", ED_vol, continuation=False, initial_number_of_steps=initial_step, log_level=10) # Store outout for i, wi in enumerate(prev_states): ui, pi, pinni = wi.split(deepcopy=True) U_save.assign(ui) disp_file.write(U_save) print ("V = {}".format(control_values[i])) print ("P = {}".format(float(pinni)/1000.0)) pv_data_plot.write('{},'.format(float(pinni)/1000.0)) pv_data_plot.write('{}\n'.format(control_values[i])) pv_data["pressure"].append(float(pinni)/1000.0) pv_data["volume"].append(control_values[i]) with df.HDF5File(df.mpi_comm_world(), output, "w") as h5file: h5file.write(solver.get_state(), "inflation") # Store ED solution w = solver.get_state() u, p, pinn = w.split(deepcopy=True) U_save.assign(u) disp_file.write(U_save) pv_data_plot.write('{},'.format(float(pinn)/1000.0)) pv_data_plot.write('{}\n'.format(ED_vol)) pv_data["pressure"].append(float(pinn)/1000.0) pv_data["volume"].append(ED_vol) print ("\nInflation succeded! Current pressure: {} kPa\n\n".format(float(pinn)/1000.0)) pv_data_plot.close() ######################### ### Closed loop cycle ### ######################### while (t < BCL): w = solver.get_state() u, p, pinn = w.split(deepcopy=True) p_cav = float(pinn) V_cav = df.assemble(solver._V_u*dsendo) if t + dt > BCL: dt = BCL - t t = t + dt target_gamma = ca_transient(t) # Update windkessel model Part = 1.0/Cao*(V_art - Vart0); Pven = 1.0/Cven*(V_ven - Vven0); PLV = float(p_cav); print ("PLV = {}".format(PLV)) print ("Part = {}".format(Part)) # Flux trough aortic valve if(PLV <= Part): Qao = 0.0; else: Qao = 1.0/Rao*(PLV - Part); # Flux trough mitral valve if(PLV >= Pven): Qmv = 0.0; else: Qmv = 1.0/Rven*(Pven - PLV); Qper = 1.0/Rper*(Part - Pven); V_cav = V_cav + dt*(Qmv - Qao); V_art = V_art + dt*(Qao - Qper); V_ven = V_ven + dt*(Qper - Qmv); # Update cavity volume V0.vol = V_cav # Iterate active contraction if t <= 150: target_gamma_ = target_gamma * gamma_arr _, states = iterate("gamma", solver, target_gamma_, gamma, initial_number_of_steps = 1) else: solver.solve() # Adapt time step if len(states) == 1: dt *= 1.7 else: dt *= 0.5 dt = min(dt, 10) # Store data ui, pi, pinni = solver.get_state().split(deepcopy=True) U_save.assign(ui) disp_file.write(U_save) Pcav = float(pinni)/1000.0 pv_data_plot = open('pv_data_plot.txt', 'a') pv_data_plot.write('{},'.format(Pcav)) pv_data_plot.write('{}\n'.format(V_cav)) pv_data_plot.close() pv_data["pressure"].append(Pcav) pv_data["volume"].append(V_cav) msg = ("\n\nTime:\t{}".format(t) + \ "\ndt:\t{}".format(dt) +\ "\ngamma:\t{}".format(target_gamma) +\ "\nV_cav:\t{}".format(V_cav) + \ "\nV_art:\t{}".format(V_art) + \ "\nV_ven:\t{}".format(V_ven) + \ "\nPart:\t{}".format(Part) + \ "\nPven:\t{}".format(Pven) + \ "\nPLV:\t{}".format(Pcav) + \ "\nQper:\t{}".format(Qper) + \ "\nQao:\t{}".format(Qao) + \ "\nQmv:\t{}\n\n".format(Qmv)) print ((msg)) #============================================================================== # fig = plt.figure() # ax = fig.gca() # ax.plot(pv_data["volume"], pv_data["pressure"]) # ax.set_ylabel("Pressure (kPa)") # ax.set_xlabel("Volume (ml)") # # # fig.savefig("/".join([dir_results, "pv_loop.png"])) # plt.show() #============================================================================== return #import threading #thread1 = threading.Thread(target = closed_loop) #thread1.start()
def inside(self, x, on_boundary): return df.between(x[0]**2 + x[1]**2, (0, 1)) and df.between(x[1], (0, 1)) quantumDot = QuantumDot() domains = df.CellFunction("size_t", mesh) domains.set_all(0) quantumDot.mark(domains, 1) V = df.FunctionSpace(mesh, "CG", 1) u = df.TrialFunction(V) v = df.TestFunction(V) drdz = df.Measure("dx")[domains] r = df.Expression("x[0]") # Confining potential potential = df.Constant(100) # Partial derivatives of trial and test functions u_r = u.dx(0) v_r = v.dx(0) u_z = u.dx(1) v_z = v.dx(1) # Initial guess of ground state is 1 inside dot, 0 outside dot psi0 = v * r * drdz(1) Psi0 = df.PETScVector() df.assemble(psi0, tensor=Psi0)
boundary_markers = df.MeshFunction("size_t", mesh, dim=1, value=0) left_bnd.mark(boundary_markers, 1) right_bnd.mark(boundary_markers, 2) # Define boundary conditions bcL = df.DirichletBC(Uh, df.Constant((0.0, 0.0)), boundary_markers, 1) ty = -0.01 traction = df.Constant((0.0, ty)) # Trial and test functions uh = df.TrialFunction(Uh) vh = df.TestFunction(Uh) # Define measures dx = df.dx ds = df.Measure("ds", domain=mesh, subdomain_data=boundary_markers) # ~~~ PART I: single scale constitutive law ~~~ # # Define single scale constitutive parameters fac_avg = 4.0 # roughly to approximate single scale to mulsticale results lamb = fac_avg * 1.0 mu = fac_avg * 0.5 # Define single scale constitutive law def sigma(u): return lamb * ufl.nabla_div(u) * df.Identity(2) + 2 * mu * symgrad(u) # Define single scale variational problem
def calculate_fiber_strain(fib, e_circ, e_rad, e_long, strain_markers, mesh, strains): import dolfin from dolfin import ( Measure, Function, TensorFunctionSpace, VectorFunctionSpace, TrialFunction, TestFunction, inner, assemble_system, solve, ) dX = dolfin.Measure("dx", subdomain_data=strain_markers, domain=mesh) fiber_space = fib.function_space() strain_space = dolfin.VectorFunctionSpace(mesh, "R", 0, dim=3) full_strain_space = dolfin.TensorFunctionSpace(mesh, "R", 0) fib1 = dolfin.Function(strain_space) e_c1 = dolfin.Function(strain_space) e_r1 = dolfin.Function(strain_space) e_l1 = dolfin.Function(strain_space) mean_coords, coords = get_regional_midpoints(strain_markers, mesh) # ax = plt.subplot(111, projection='3d') region = 1 fiber_strain = [] for region in range(1, 18): # For each region # Find the average unit normal in the fiber direction u = dolfin.TrialFunction(strain_space) v = TestFunction(strain_space) a = inner(u, v) * dX(region) L_fib = inner(fib, v) * dX(region) A, b = assemble_system(a, L_fib) solve(A, fib1.vector(), b) fib1_norm = np.linalg.norm(fib1.vector().array()) # Unit normal fib1_arr = fib1.vector().array() / fib1_norm # Find the average unit normal in Circumferential direction u = TrialFunction(strain_space) v = TestFunction(strain_space) a = inner(u, v) * dX(region) L_c = inner(e_circ, v) * dX(region) A, b = assemble_system(a, L_c) solve(A, e_c1.vector(), b) e_c1_norm = np.linalg.norm(e_c1.vector().array()) # Unit normal e_c1_arr = e_c1.vector().array() / e_c1_norm # Find the averag unit normal in Radial direction u = TrialFunction(strain_space) v = TestFunction(strain_space) a = inner(u, v) * dX(region) L_r = inner(e_rad, v) * dX(region) A, b = assemble_system(a, L_r) solve(A, e_r1.vector(), b) e_r1_norm = np.linalg.norm(e_r1.vector().array()) # Unit normal e_r1_arr = e_r1.vector().array() / e_r1_norm # Find the average unit normal in Longitudinal direction u = TrialFunction(strain_space) v = TestFunction(strain_space) a = inner(u, v) * dX(region) L_l = inner(e_long, v) * dX(region) A, b = assemble_system(a, L_l) solve(A, e_l1.vector(), b) e_l1_norm = np.linalg.norm(e_l1.vector().array()) # Unit normal e_l1_arr = e_l1.vector().array() / e_l1_norm # ax.plot([mean_coords[region][0], mean_coords[region][0]+e_c1_arr[0]],[mean_coords[region][1], mean_coords[region][1]+e_c1_arr[1]], [mean_coords[region][2],mean_coords[region][2]+e_c1_arr[2]], 'b', label = "circ") # ax.plot([mean_coords[region][0],mean_coords[region][0]+e_r1_arr[0]],[mean_coords[region][1], mean_coords[region][1]+e_r1_arr[1]], [mean_coords[region][2],mean_coords[region][2]+e_r1_arr[2]] , 'r',label = "rad") # ax.plot([mean_coords[region][0],mean_coords[region][0]+e_l1_arr[0]],[mean_coords[region][1], mean_coords[region][1]+e_l1_arr[1]], [mean_coords[region][2],mean_coords[region][2]+e_l1_arr[2]] , 'g',label = "long") # ax.plot([mean_coords[region][0],mean_coords[region][0]+fib1_arr[0]],[mean_coords[region][1], mean_coords[region][1]+fib1_arr[1]], [mean_coords[region][2],mean_coords[region][2]+fib1_arr[2]] , 'y', label = "fib") fiber_strain_region = [] for strain in strains[region]: mat = np.array([ strain[0] * e_c1_arr, strain[1] * e_r1_arr, strain[2] * e_l1_arr ]).T fiber_strain_region.append(np.linalg.norm(np.dot(mat, fib1_arr))) fiber_strain.append(fiber_strain_region) # for i in range(18): # ax.scatter3D(coords[i][0], coords[i][1], coords[i][2], s = 0.1) # plt.show() return fiber_strain
if args.onlyflow: exit("Only flow!") #calculate normal vector of boundary n = df.FacetNormal(mesh) #calculate Peclet number Pe = df.Constant(1.0) #define trial and test functions using mesh for B-field (S) chi = df.TrialFunction(S) chi_ = df.Function(S) psi = df.TestFunction(S) #define surface integral ds = df.Measure("ds", domain=mesh, subdomain_data=subd) #variational problem for Brenner field, where the Neumann BCs are included F_chi = (n[0] * psi * ds(1) + df.inner(df.grad(chi), df.grad(psi)) * df.dx + Pe * psi * df.dot(U_, df.grad(chi)) * df.dx + Pe * (U_[0] - df.Constant(1.)) * psi * df.dx) #define left and right hand side a_chi, L_chi = df.lhs(F_chi), df.rhs(F_chi) #define problem and solver problem_chi2 = df.LinearVariationalProblem(a_chi, L_chi, chi_, bcs=[]) solver_chi2 = df.LinearVariationalSolver(problem_chi2) solver_chi2.parameters["krylov_solver"]["absolute_tolerance"] = 1e-15 #array of Peclet numbers to investigate
def numerical_test(user_parameters): time_data = [] time_data_pd = [] spacetime = [] lmbda_min_prev = 1e-6 bifurcated = False bifurcation_loads = [] save_current_bifurcation = False bifurc_i = 0 bifurcation_loads = [] # Create mesh and define function space # Define Dirichlet boundaries comm = MPI.comm_world default_parameters = getDefaultParameters() default_parameters.update(user_parameters) # FIXME: Not nice parameters = default_parameters parameters['code']['script'] = __file__ # import pdb; pdb.set_trace() signature = hashlib.md5(str(parameters).encode('utf-8')).hexdigest() outdir = '../output/traction/{}-{}CPU'.format(signature, size) Path(outdir).mkdir(parents=True, exist_ok=True) log(LogLevel.INFO, 'INFO: Outdir is: ' + outdir) BASE_DIR = os.path.dirname(os.path.realpath(__file__)) print(parameters['geometry']) d = { 'Lx': parameters['geometry']['Lx'], 'Ly': parameters['geometry']['Ly'], 'h': parameters['material']['ell'] / parameters['geometry']['n'] } geom_signature = hashlib.md5(str(d).encode('utf-8')).hexdigest() # -------------------------------------------------------- # Mesh creation with gmsh Lx = parameters['geometry']['Lx'] Ly = parameters['geometry']['Ly'] n = parameters['geometry']['n'] ell = parameters['material']['ell'] fname = os.path.join('../meshes', 'strip-{}'.format(geom_signature)) resolution = max(parameters['geometry']['n'] * Lx / ell, 5 / (Ly * 10)) resolution = 3 geom = mshr.Rectangle(dolfin.Point(-Lx / 2., -Ly / 2.), dolfin.Point(Lx / 2., Ly / 2.)) # mesh = mshr.generate_mesh(geom, n * int(float(Lx / ell))) mesh = mshr.generate_mesh(geom, resolution) log( LogLevel.INFO, 'Number of dofs: {}'.format( mesh.num_vertices() * (1 + parameters['general']['dim']))) if size == 1: meshf = dolfin.File(os.path.join(outdir, "mesh.xml")) plot(mesh) plt.savefig(os.path.join(outdir, "mesh.pdf"), bbox_inches='tight') with open(os.path.join(outdir, 'parameters.yaml'), "w") as f: yaml.dump(parameters, f, default_flow_style=False) Lx = parameters['geometry']['Lx'] ell = parameters['material']['ell'] savelag = 1 # mf = dolfin.MeshFunction("size_t", mesh, 1, 0) # Function Spaces V_u = dolfin.VectorFunctionSpace(mesh, "CG", 1) V_alpha = dolfin.FunctionSpace(mesh, "CG", 1) L2 = dolfin.FunctionSpace(mesh, "DG", 0) u = dolfin.Function(V_u, name="Total displacement") u.rename('u', 'u') alpha = Function(V_alpha) alpha_old = dolfin.Function(alpha.function_space()) alpha.rename('alpha', 'alpha') dalpha = TrialFunction(V_alpha) alpha_bif = dolfin.Function(V_alpha) alpha_bif_old = dolfin.Function(V_alpha) state = {'u': u, 'alpha': alpha} Z = dolfin.FunctionSpace( mesh, dolfin.MixedElement([u.ufl_element(), alpha.ufl_element()])) z = dolfin.Function(Z) v, beta = dolfin.split(z) left = dolfin.CompiledSubDomain("near(x[0], -Lx/2.)", Lx=Lx) right = dolfin.CompiledSubDomain("near(x[0], Lx/2.)", Lx=Lx) bottom = dolfin.CompiledSubDomain("near(x[1],-Ly/2.)", Ly=Ly) top = dolfin.CompiledSubDomain("near(x[1],Ly/2.)", Ly=Ly) left_bottom_pt = dolfin.CompiledSubDomain( "near(x[0],-Lx/2.) && near(x[1],-Ly/2.)", Lx=Lx, Ly=Ly) mf = dolfin.MeshFunction("size_t", mesh, 1, 0) right.mark(mf, 1) left.mark(mf, 2) bottom.mark(mf, 3) ut = dolfin.Expression("t", t=0.0, degree=0) bcs_u = [ dolfin.DirichletBC(V_u.sub(0), dolfin.Constant(0), left), dolfin.DirichletBC(V_u.sub(0), ut, right), dolfin.DirichletBC(V_u, (0, 0), left_bottom_pt, method="pointwise") ] bcs_alpha = [] bcs = {"damage": bcs_alpha, "elastic": bcs_u} ds = dolfin.Measure("ds", subdomain_data=mf) dx = dolfin.Measure("dx", metadata=parameters['compiler'], domain=mesh) ell = parameters['material']['ell'] # ----------------------- # Problem definition k_res = parameters['material']['k_res'] a = (1 - alpha)**2. + k_res w_1 = parameters['material']['sigma_D0']**2 / parameters['material']['E'] w = w_1 * alpha eps = sym(grad(u)) eps0t = Expression([['t', 0.], [0., 't']], t=0., degree=0) lmbda0 = parameters['material']['E'] * parameters['material']['nu'] / ( 1. - parameters['material']['nu'])**2. mu0 = parameters['material']['E'] / 2. / (1.0 + parameters['material']['nu']) nu = parameters['material']['nu'] sigma0 = lmbda0 * tr(eps) * dolfin.Identity( parameters['general']['dim']) + 2 * mu0 * eps e1 = Constant((1., 0)) _sigma = ((1 - alpha)**2. + k_res) * sigma0 _snn = dolfin.dot(dolfin.dot(_sigma, e1), e1) # ------------------- ell = parameters['material']['ell'] E = parameters['material']['E'] def elastic_energy(u, alpha, E=E, nu=nu, eps0t=eps0t, k_res=k_res): a = (1 - alpha)**2. + k_res eps = sym(grad(u)) Wt = a*E*nu/(2*(1-nu**2.)) * tr(eps)**2. \ + a*E/(2.*(1+nu))*(inner(eps, eps)) return Wt * dx def dissipated_energy(alpha, w_1=w_1, ell=ell): return w_1 * (alpha + ell**2. * inner(grad(alpha), grad(alpha))) * dx def total_energy(u, alpha, k_res=k_res, w_1=w_1, E=E, nu=nu, ell=ell, eps0t=eps0t): elastic_energy_ = elastic_energy(u, alpha, E=E, nu=nu, eps0t=eps0t, k_res=k_res) dissipated_energy_ = dissipated_energy(alpha, w_1=w_1, ell=ell) return elastic_energy_ + dissipated_energy_ energy = total_energy(u, alpha) # Hessian = derivative(derivative(Wppt*dx, z, TestFunction(Z)), z, TrialFunction(Z)) def create_output(outdir): file_out = dolfin.XDMFFile(os.path.join(outdir, "output.xdmf")) file_out.parameters["functions_share_mesh"] = True file_out.parameters["flush_output"] = True file_postproc = dolfin.XDMFFile( os.path.join(outdir, "postprocess.xdmf")) file_postproc.parameters["functions_share_mesh"] = True file_postproc.parameters["flush_output"] = True file_eig = dolfin.XDMFFile(os.path.join(outdir, "perturbations.xdmf")) file_eig.parameters["functions_share_mesh"] = True file_eig.parameters["flush_output"] = True file_bif = dolfin.XDMFFile(os.path.join(outdir, "bifurcation.xdmf")) file_bif.parameters["functions_share_mesh"] = True file_bif.parameters["flush_output"] = True file_bif_postproc = dolfin.XDMFFile( os.path.join(outdir, "bifurcation_postproc.xdmf")) file_bif_postproc.parameters["functions_share_mesh"] = True file_bif_postproc.parameters["flush_output"] = True file_ealpha = dolfin.XDMFFile(os.path.join(outdir, "elapha.xdmf")) file_ealpha.parameters["functions_share_mesh"] = True file_ealpha.parameters["flush_output"] = True files = { 'output': file_out, 'postproc': file_postproc, 'eigen': file_eig, 'bifurcation': file_bif, 'ealpha': file_ealpha } return files files = create_output(outdir) solver = EquilibriumAM(energy, state, bcs, parameters=parameters) stability = StabilitySolver(energy, state, bcs, parameters=parameters) linesearch = LineSearch(energy, state) load_steps = np.linspace(parameters['loading']['load_min'], parameters['loading']['load_max'], parameters['loading']['n_steps']) time_data = [] time_data_pd = [] spacetime = [] lmbda_min_prev = 1e-6 bifurcated = False bifurcation_loads = [] save_current_bifurcation = False bifurc_i = 0 alpha_bif = dolfin.Function(V_alpha) alpha_bif_old = dolfin.Function(V_alpha) bifurcation_loads = [] to_remove = [] perturb = False from matplotlib import cm log(LogLevel.INFO, '{}'.format(parameters)) for step, load in enumerate(load_steps): plt.clf() mineigs = [] exhaust_modes = [] log(LogLevel.CRITICAL, '====================== STEPPING ==========================') log(LogLevel.CRITICAL, 'CRITICAL: Solving load t = {:.2f}'.format(load)) alpha_old.assign(alpha) ut.t = load # (time_data_i, am_iter) = solver.solve(outdir) (time_data_i, am_iter) = solver.solve() # Second order stability conditions (stable, negev) = stability.solve(solver.damage.problem.lb) log(LogLevel.CRITICAL, 'Current state is{}stable'.format(' ' if stable else ' un')) mineig = stability.mineig if hasattr(stability, 'mineig') else 0.0 # log(LogLevel.INFO, 'INFO: lmbda min {}'.format(lmbda_min_prev)) log(LogLevel.INFO, 'INFO: mineig {:.5e}'.format(mineig)) Deltav = (mineig - lmbda_min_prev) if hasattr(stability, 'eigs') else 0 if (mineig + Deltav) * (lmbda_min_prev + dolfin.DOLFIN_EPS) < 0 and not bifurcated: bifurcated = True # save 3 bif modes log( LogLevel.INFO, 'INFO: About to bifurcate load {:.3f} step {}'.format( load, step)) bifurcation_loads.append(load) modes = np.where(stability.eigs < 0)[0] bifurc_i += 1 lmbda_min_prev = mineig if hasattr(stability, 'mineig') else 0. # we postpone the update after the stability check if stable: solver.update() log( LogLevel.INFO, ' Current state is{}stable'.format( ' ' if stable else ' un')) else: # Continuation iteration = 1 mineigs.append(stability.mineig) while stable == False: log(LogLevel.INFO, 'Continuation iteration {}'.format(iteration)) plt.close('all') pert = [(_v, _b) for _v, _b in zip( stability.perturbations_v, stability.perturbations_beta)] _nmodes = len(pert) en_vars = [] h_opts = [] hbounds = [] en_perts = [] for i, mode in enumerate(pert): h_opt, bounds, enpert, en_var = linesearch.search( { 'u': u, 'alpha': alpha, 'alpha_old': alpha_old }, mode[0], mode[1]) h_opts.append(h_opt) en_vars.append(en_var) hbounds.append(bounds) en_perts.append(enpert) if rank == 0: # fig = plt.figure(dpi=80, facecolor='w', edgecolor='k') # plt.subplot(1, 4, 1) # plt.set_cmap('binary') # # dolfin.plot(mesh, alpha = 1.) # dolfin.plot( # project(stability.inactivemarker1, L2), alpha = 1., vmin=0., vmax=1.) # plt.title('derivative zero') # plt.subplot(1, 4, 2) # # dolfin.plot(mesh, alpha = .5) # dolfin.plot( # project(stability.inactivemarker2, L2), alpha = 1., vmin=0., vmax=1.) # plt.title('ub tolerance') # plt.subplot(1, 4, 3) # # dolfin.plot(mesh, alpha = .5) # dolfin.plot( # project(stability.inactivemarker3, L2), alpha = 1., vmin=0., vmax=1.) # plt.title('alpha-alpha_old') # plt.subplot(1, 4, 4) # # dolfin.plot(mesh, alpha = .5) # dolfin.plot( # project(stability.inactivemarker4, L2), alpha = 1., vmin=0., vmax=1.) # plt.title('intersec deriv, ub') # plt.savefig(os.path.join(outdir, "inactivesets-{:.3f}-{:d}.pdf".format(load, iteration))) # plt.set_cmap('hot') fig = plt.figure(dpi=80, facecolor='w', edgecolor='k') for i, mode in enumerate(pert): plt.subplot(2, _nmodes + 1, i + 2) plt.axis('off') plot(mode[1], cmap=cm.ocean) plt.title( 'mode {} $h^*$={:.3f}\n $\\lambda_{}$={:.3e} \n $\\Delta E$={:.3e}' .format(i, h_opts[i], i, stability.eigs[i], en_vars[i]), fontsize=15) # plt.title('mode {}' # .format(i), fontsize= 15) plt.subplot(2, _nmodes + 1, _nmodes + 2 + 1 + i) plt.axis('off') _pert_beta = mode[1] _pert_v = mode[0] if hbounds[i][0] == hbounds[i][1] == 0: plt.plot(hbounds[i][0], 0) else: hs = np.linspace(hbounds[i][0], hbounds[i][1], 100) z = np.polyfit( np.linspace(hbounds[i][0], hbounds[i][1], len(en_perts[i])), en_perts[i], parameters['stability']['order']) p = np.poly1d(z) plt.plot(hs, p(hs), c='k') plt.plot(np.linspace(hbounds[i][0], hbounds[i][1], len(en_perts[i])), en_perts[i], marker='o', markersize=10, c='k') # import pdb; pdb.set_trace() plt.plot(hs, stability.eigs[i] * hs**2, c='r', lw=.3) plt.axvline(h_opts[i], lw=.3, c='k') plt.axvline(0, lw=2, c='k') # plt.title('{}'.format(i)) plt.tight_layout(h_pad=1.5, pad=1.5) # plt.legend() plt.savefig( os.path.join( outdir, "modes-{:.3f}-{}.pdf".format(load, iteration))) plt.close(fig) plt.clf() log(LogLevel.INFO, 'plotted modes') cont_data_pre = compile_continuation_data(state, energy) log(LogLevel.INFO, 'Estimated energy variation {:.3e}'.format(en_var)) Ealpha = Function(V_alpha) Ealpha.vector()[:] = assemble(stability.inactiveEalpha)[:] Ealpha.rename('Ealpha-{}'.format(iteration), 'Ealpha-{}'.format(iteration)) with files['ealpha'] as file: file.write(Ealpha, load) save_current_bifurcation = True # pick the first of the non exhausted modes- non_zero_h = np.where(abs(np.array(h_opts)) > DOLFIN_EPS)[0] log(LogLevel.INFO, 'Nonzero h {}'.format(non_zero_h)) avail_modes = set(non_zero_h) - set(exhaust_modes) opt_mode = 0 # opt_mode = np.argmin(en_vars) log(LogLevel.INFO, 'Energy vars {}'.format(en_vars)) log( LogLevel.INFO, 'Pick bifurcation mode {} out of {}'.format( opt_mode, len(en_vars))) # h_opt = min(h_opts[opt_mode],1.e-2) h_opt = h_opts[opt_mode] perturbation_v = stability.perturbations_v[opt_mode] perturbation_beta = stability.perturbations_beta[opt_mode] minmode = stability.minmode (perturbation_v, perturbation_beta) = minmode.split(deepcopy=True) # (perturbation_v, perturbation_beta) = stability.perturbation_v, stability.perturbation_beta def energy_1d(h): #return assemble(energy_functional(u + h * perturbation_v, alpha + h * perturbation_beta)) u_ = Function(u.function_space()) alpha_ = Function(alpha.function_space()) u_.vector( )[:] = u.vector()[:] + h * perturbation_v.vector()[:] alpha_.vector()[:] = alpha.vector( )[:] + h * perturbation_beta.vector()[:] u_.vector().vec().ghostUpdate() alpha_.vector().vec().ghostUpdate() return assemble(total_energy(u_, alpha_)) (hmin, hmax) = linesearch.admissible_interval( alpha, alpha_old, perturbation_beta) hs = np.linspace(hmin, hmax, 20) energy_vals = np.array([energy_1d(h) for h in hs]) stability.solve(solver.damage.problem.lb) Hzz = assemble(stability.H * minmode * minmode) Gz = assemble(stability.J * minmode) mineig_z = Hzz / assemble(dot(minmode, minmode) * dx) energy_vals_quad = energy_1d(0) + hs * Gz + hs**2 * Hzz / 2 # h_opt = hs[np.argmin(energy_vals)] print('computed h_opt {}'.format(hs[np.argmin(energy_vals)])) print("%%%%%%%%% ", mineig_z, "-", mineig) if rank == 0: plt.figure() # plt.plot(hs,energy_vals, marker = 'o') plt.plot(hs, energy_vals, marker='o', label="exact") plt.plot(hs, energy_vals_quad, label="quadratic approximation") plt.legend() plt.title("eig {:.4f} vs {:.4f} expected".format( mineig_z, mineig)) plt.axvline(h_opt) # import pdb; pdb.set_trace() plt.savefig( os.path.join(outdir, "energy1d-{:.3f}.pdf".format(load))) iteration += 1 log(LogLevel.CRITICAL, 'Bifurcating') save_current_bifurcation = True alpha_bif.assign(alpha) alpha_bif_old.assign(alpha_old) # admissible perturbation uval = u.vector()[:] + h_opt * perturbation_v.vector()[:] aval = alpha.vector( )[:] + h_opt * perturbation_beta.vector()[:] u.vector()[:] = uval alpha.vector()[:] = aval u.vector().vec().ghostUpdate() alpha.vector().vec().ghostUpdate() log(LogLevel.INFO, 'min a+h_opt beta_{} = {}'.format(opt_mode, min(aval))) log(LogLevel.INFO, 'max a+h_opt beta_{} = {}'.format(opt_mode, max(aval))) log(LogLevel.INFO, 'Solving equilibrium from perturbed state') (time_data_i, am_iter) = solver.solve(outdir) # (time_data_i, am_iter) = solver.solve() log(LogLevel.INFO, 'Checking stability of new state') (stable, negev) = stability.solve(solver.damage.problem.lb) mineigs.append(stability.mineig) log( LogLevel.INFO, 'Continuation iteration {}, current state is{}stable'. format(iteration, ' ' if stable else ' un')) cont_data_post = compile_continuation_data(state, energy) DeltaE = (cont_data_post['energy'] - cont_data_pre['energy']) relDeltaE = (cont_data_post['energy'] - cont_data_pre['energy']) / cont_data_pre['energy'] release = DeltaE < 0 and np.abs( DeltaE) > parameters['stability']['cont_rtol'] log( LogLevel.INFO, 'Continuation: post energy {} - pre energy {}'.format( cont_data_post['energy'], cont_data_pre['energy'])) log( LogLevel.INFO, 'Actual absolute energy variation Delta E = {:.7e}'.format( DeltaE)) log( LogLevel.INFO, 'Actual relative energy variation relDelta E = {:.7e}'. format(relDeltaE)) log(LogLevel.INFO, 'Iter {} mineigs = {}'.format(iteration, mineigs)) if rank == 0: plt.figure() plt.plot(mineigs, marker='o') plt.axhline(0.) plt.savefig( os.path.join(outdir, "mineigs-{:.3f}.pdf".format(load))) # continuation criterion if abs(np.diff(mineigs)[-1]) > 1e-10: log(LogLevel.INFO, 'Min eig change = {:.3e}'.format(np.diff(mineigs)[-1])) log(LogLevel.INFO, 'Continuing perturbations') else: log(LogLevel.INFO, 'Min eig change = {:.3e}'.format(np.diff(mineigs)[-1])) log(LogLevel.CRITICAL, 'We are stuck in the matrix') log(LogLevel.WARNING, 'Exploring next mode') exhaust_modes.append(opt_mode) # import pdb; pdb.set_trace() log(LogLevel.WARNING, 'Continuing load program') break # # if not release: # log(LogLevel.CRITICAL, 'Small nergy release , we are stuck in the matrix') # log(LogLevel.CRITICAL, 'No decrease in energy, we are stuck in the matrix') # log(LogLevel.WARNING, 'Continuing load program') # import pdb; pdb.set_trace() # break # else: # # warn # log(LogLevel.CRITICAL, 'Found zero increment, we are stuck in the matrix') # log(LogLevel.WARNING, 'Exploring next mode') # exhaust_modes.append(opt_mode) # import pdb; pdb.set_trace() # # log(LogLevel.WARNING, 'Continuing load program') # # break solver.update() log(LogLevel.INFO, 'bifurcation loads : {}'.format(bifurcation_loads)) np.save(os.path.join(outdir, 'bifurcation_loads'), bifurcation_loads, allow_pickle=True, fix_imports=True) if save_current_bifurcation: time_data_i['h_opt'] = h_opt time_data_i['max_h'] = hbounds[opt_mode][1] time_data_i['min_h'] = hbounds[opt_mode][0] modes = np.where(stability.eigs < 0)[0] leneigs = len(modes) maxmodes = min(3, leneigs) with files['bifurcation'] as file: for n in range(len(pert)): mode = dolfin.project(stability.perturbations_beta[n], V_alpha) modename = 'beta-%d' % n mode.rename(modename, modename) log(LogLevel.INFO, 'Saved mode {}'.format(modename)) file.write(mode, load) # with files['file_bif_postproc'] as file: # leneigs = len(modes) # maxmodes = min(3, leneigs) # beta0v = dolfin.project(stability.perturbation_beta, V_alpha) # log(LogLevel.DEBUG, 'DEBUG: irrev {}'.format(alpha.vector()-alpha_old.vector())) # file.write_checkpoint(beta0v, 'beta0', 0, append = True) # file.write_checkpoint(alpha_bif_old, 'alpha-old', 0, append=True) # file.write_checkpoint(alpha_bif, 'alpha-bif', 0, append=True) # file.write_checkpoint(alpha, 'alpha', 0, append=True) np.save(os.path.join(outdir, 'energy_perturbations'), en_perts, allow_pickle=True, fix_imports=True) with files['eigen'] as file: _v = dolfin.project( dolfin.Constant(h_opt) * perturbation_v, V_u) _beta = dolfin.project( dolfin.Constant(h_opt) * perturbation_beta, V_alpha) _v.rename('perturbation displacement', 'perturbation displacement') _beta.rename('perturbation damage', 'perturbation damage') file.write(_v, load) file.write(_beta, load) # save_current_bifurcation = False time_data_i["load"] = load time_data_i["alpha_max"] = max(alpha.vector()[:]) time_data_i["elastic_energy"] = dolfin.assemble( elastic_energy(u, alpha, E=E, nu=nu, eps0t=eps0t, k_res=k_res)) time_data_i["dissipated_energy"] = dolfin.assemble( (w + w_1 * parameters['material']['ell']**2. * inner(grad(alpha), grad(alpha))) * dx) time_data_i["stable"] = stability.stable time_data_i["# neg ev"] = stability.negev time_data_i["eigs"] = stability.eigs if hasattr(stability, 'eigs') else np.inf time_data_i["sigma"] = 1 / Ly * dolfin.assemble(_snn * ds(1)) # import pdb; pdb.set_trace() log( LogLevel.INFO, "Load/time step {:.4g}: converged in iterations: {:3d}, err_alpha={:.4e}" .format(time_data_i["load"], time_data_i["iterations"][0], time_data_i["alpha_error"][0])) time_data.append(time_data_i) time_data_pd = pd.DataFrame(time_data) with files['output'] as file: file.write(alpha, load) file.write(u, load) with files['postproc'] as file: file.write_checkpoint(alpha, "alpha-{}".format(step), step, append=True) file.write_checkpoint(u, "u-{}".format(step), step, append=True) log(LogLevel.INFO, 'INFO: written postprocessing step {}'.format(step)) time_data_pd.to_json(os.path.join(outdir, "time_data.json")) if rank == 0: # plt.clf() # if load>1.1: # import pdb; pdb.set_trace() # plt.plot(time_data_i["alpha_error"], marker='o') # plt.title('error, criterion: {}'.format(parameters['equilibrium']['criterion'])) # plt.axhline(parameters['equilibrium']['tol']) # plt.savefig(os.path.join(outdir, 'errors-{}.pdf'.format(step))) # plt.clf() # plt.colorbar(plot(alpha)) # fig = plt.figure() # plot(alpha) # plt.savefig(os.path.join(outdir, 'alpha.pdf')) # log(LogLevel.INFO, "Saved figure: {}".format(os.path.join(outdir, 'alpha.pdf'))) plt.close('all') fig = plt.figure() for i, d in enumerate(time_data_pd['eigs']): # if d is not (np.inf or np.nan or float('inf')): if np.isfinite(d).all(): lend = len(d) if isinstance(d, np.ndarray) else 1 plt.scatter([(time_data_pd['load'].values)[i]] * lend, d, c=np.where(np.array(d) < 0., 'red', 'black')) plt.axhline(0, c='k', lw=2.) plt.xlabel('t') # [plt.axvline(b) for b in bifurcation_loads] # import pdb; pdb.set_trace() log(LogLevel.INFO, 'Spectrum bifurcation loads : {}'.format(bifurcation_loads)) plt.xticks(list(plt.xticks()[0]) + bifurcation_loads) [plt.axvline(bif, lw=2, c='k') for bif in bifurcation_loads] plt.savefig(os.path.join(outdir, "spectrum.pdf"), bbox_inches='tight') # plt.plot() return time_data_pd, outdir
def traction_test( ell=0.1, degree=1, n=3, nu=0.0, load_min=0, load_max=2, loads=None, nsteps=20, Lx=1, Ly=0.1, outdir="outdir", savelag=1, ): # constants ell = ell Lx = Lx Ly = Ly load_min = load_min load_max = load_max nsteps = nsteps loads=loads savelag = 1 nu = dolfin.Constant(nu) ell = dolfin.Constant(ell) E0 = dolfin.Constant(1.0) sigma_D0 = E0 n = n params = { 'material': { "ell": ell.values()[0], "E": E0.values()[0], "nu": nu.values()[0], "sigma_D0": sigma_D0.values()[0]}, 'geometry': { 'Lx': Lx, 'Ly': Ly, 'n': n, }, 'load':{ 'min': load_min, 'max': load_max, 'nsteps': nsteps } } print(params) geom = mshr.Rectangle(dolfin.Point(-Lx/2., -Ly/2.), dolfin.Point(Lx/2., Ly/2.)) nel = max(int(n * float(Lx / ell)), int(Ly/3.)) mesh = mshr.generate_mesh(geom, nel) left = dolfin.CompiledSubDomain("near(x[0], -Lx/2.)", Lx=Lx) right = dolfin.CompiledSubDomain("near(x[0], Lx/2.)", Lx=Lx) right_bottom_pt = dolfin.CompiledSubDomain("near(x[1], Lx/2.) && near(x[0],-Ly/2.)", Lx=Lx, Ly=Ly) mf = dolfin.MeshFunction("size_t", mesh, 1, 0) right.mark(mf, 1) left.mark(mf, 2) ds = dolfin.Measure("ds", subdomain_data=mf) dx = dolfin.Measure("dx", metadata=form_compiler_parameters, domain=mesh) V_u = dolfin.VectorFunctionSpace(mesh, "CG", 1) V_alpha = dolfin.FunctionSpace(mesh, "CG", 1) u = dolfin.Function(V_u, name="Total displacement") alpha = dolfin.Function(V_alpha, name="Damage") state = [u, alpha] Z = dolfin.FunctionSpace(mesh, dolfin.MixedElement([u.ufl_element(),alpha.ufl_element()])) z = dolfin.Function(Z) v, beta = dolfin.split(z) ut = dolfin.Expression("t", t=0.0, degree=0) bcs_u = [dolfin.DirichletBC(V_u.sub(0), dolfin.Constant(0), left), dolfin.DirichletBC(V_u.sub(0), ut, right), dolfin.DirichletBC(V_u, (0, 0), right_bottom_pt, method="pointwise")] bcs_alpha = [] # Problem definition model = DamageElasticityModel(state, E0, nu, ell, sigma_D0) energy = model.total_energy_density(u, alpha)*dx # Alternate minimization solver solver = solvers.AlternateMinimizationSolver( energy, [u, alpha], [bcs_u, bcs_alpha], parameters = alt_min_parameters) rP = model.rP(u, alpha, v, beta)*dx rN = model.rN(u, alpha, beta)*dx stability = StabilitySolver(mesh, energy, [u, alpha], [bcs_u, bcs_alpha], z, rayleigh=[rP, rN], parameters = stability_parameters) # Time iterations time_data = [] load_steps = np.linspace(load_min, load_max, nsteps) alpha_old = dolfin.Function(V_alpha) for it, load in enumerate(load_steps): stable = None; negev = 0; mineig = np.inf; iteration = 0 ut.t = load ColorPrint.print_pass('load: {:4f} step {:d} ell {:f}'.format(load, it, ell.values()[0])) alpha_old.assign(alpha) time_data_i, am_iter = solver.solve() solver.update() (stable, negev) = stability.solve(alpha_old) time_data_i["load"] = load time_data_i["stable"] = stable time_data_i["# neg ev"] = negev time_data_i["elastic_energy"] = dolfin.assemble( model.elastic_energy_density(model.eps(u), alpha)*dx) time_data_i["dissipated_energy"] = dolfin.assemble( model.damage_dissipation_density(alpha)*dx) time_data_i["eigs"] = stability.eigs if hasattr(stability, 'eigs') else np.inf time_data_i["max alpha"] = np.max(alpha.vector()[:]) time_data.append(time_data_i) time_data_pd = pd.DataFrame(time_data) if stable == False: break return time_data_pd
def __init__(self, mesh, Vh, t_init, t_final, t_1, dt, wind_velocity, gls_stab, Prior): self.mesh = mesh self.Vh = Vh self.t_init = t_init self.t_final = t_final self.t_1 = t_1 self.dt = dt self.sim_times = np.arange(self.t_init, self.t_final + .5 * self.dt, self.dt) u = dl.TrialFunction(Vh[STATE]) v = dl.TestFunction(Vh[STATE]) kappa = dl.Constant(.001) dt_expr = dl.Constant(self.dt) r_trial = u + dt_expr * (-dl.div(kappa * dl.nabla_grad(u)) + dl.inner(wind_velocity, dl.nabla_grad(u))) r_test = v + dt_expr * (-dl.div(kappa * dl.nabla_grad(v)) + dl.inner(wind_velocity, dl.nabla_grad(v))) h = dl.CellSize(mesh) vnorm = dl.sqrt(dl.inner(wind_velocity, wind_velocity)) if gls_stab: tau = dl.Min((h * h) / (dl.Constant(2.) * kappa), h / vnorm) else: tau = dl.Constant(0.) self.M = dl.assemble(dl.inner(u, v) * dl.dx) self.M_stab = dl.assemble(dl.inner(u, v + tau * r_test) * dl.dx) self.Mt_stab = dl.assemble(dl.inner(u + tau * r_trial, v) * dl.dx) Nvarf = (dl.inner(kappa * dl.nabla_grad(u), dl.nabla_grad(v)) + dl.inner(wind_velocity, dl.nabla_grad(u)) * v) * dl.dx Ntvarf = (dl.inner(kappa * dl.nabla_grad(v), dl.nabla_grad(u)) + dl.inner(wind_velocity, dl.nabla_grad(v)) * u) * dl.dx self.N = dl.assemble(Nvarf) self.Nt = dl.assemble(Ntvarf) stab = dl.assemble(tau * dl.inner(r_trial, r_test) * dl.dx) self.L = self.M + dt * self.N + stab self.Lt = self.M + dt * self.Nt + stab boundaries = dl.FacetFunction("size_t", mesh) boundaries.set_all(0) class InsideBoundary(dl.SubDomain): def inside(self, x, on_boundary): x_in = x[0] > dl.DOLFIN_EPS and x[0] < 1 - dl.DOLFIN_EPS y_in = x[1] > dl.DOLFIN_EPS and x[1] < 1 - dl.DOLFIN_EPS return on_boundary and x_in and y_in Gamma_M = InsideBoundary() Gamma_M.mark(boundaries, 1) ds_marked = dl.Measure("ds", subdomain_data=boundaries) self.Q = dl.assemble(self.dt * dl.inner(u, v) * ds_marked(1)) self.Prior = Prior if dlversion() <= (1, 6, 0): self.solver = dl.PETScLUSolver() else: self.solver = dl.PETScLUSolver(self.mesh.mpi_comm()) self.solver.set_operator(self.L) if dlversion() <= (1, 6, 0): self.solvert = dl.PETScLUSolver() else: self.solvert = dl.PETScLUSolver(self.mesh.mpi_comm()) self.solvert.set_operator(self.Lt) self.ud = self.generate_vector(STATE) self.noise_variance = 0 # Part of model public API self.gauss_newton_approx = False
def run_model(kappa, forcing, function_space, boundary_conditions=None): """ Solve complex valued Helmholtz equation by solving coupled system, one for the real part of the solution one for the imaginary part. """ mesh = function_space.mesh() kappa_sq = kappa**2 if boundary_conditions == None: bndry_obj = dl.CompiledSubDomain("on_boundary") boundary_conditions = [['dirichlet', bndry_obj, [0, 0]]] num_bndrys = len(boundary_conditions) boundaries = mark_boundaries(mesh, boundary_conditions) dirichlet_bcs = collect_dirichlet_boundaries(function_space, boundary_conditions, boundaries) # To express integrals over the boundary parts using ds(i), we must first # redefine the measure ds in terms of our boundary markers: ds = dl.Measure('ds', domain=mesh, subdomain_data=boundaries) #dx = dl.Measure('dx', domain=mesh) dx = dl.dx (pr, pi) = dl.TrialFunction(function_space) (vr, vi) = dl.TestFunction(function_space) # real part bilinear_form = kappa_sq * (pr * vr - pi * vi) * dx bilinear_form += (-dl.inner(dl.nabla_grad(pr), dl.nabla_grad(vr)) + dl.inner(dl.nabla_grad(pi), dl.nabla_grad(vi))) * dx # imaginary part bilinear_form += kappa_sq * (pr * vi + pi * vr) * dx bilinear_form += -(dl.inner(dl.nabla_grad(pr), dl.nabla_grad(vi)) + dl.inner(dl.nabla_grad(pi), dl.nabla_grad(vr))) * dx for ii in range(num_bndrys): if (boundary_conditions[ii][0] == 'robin'): alpha_real, alpha_imag = boundary_conditions[ii][3] bilinear_form -= alpha_real * (pr * vr - pi * vi) * ds(ii) bilinear_form -= alpha_imag * (pr * vi + pi * vr) * ds(ii) forcing_real, forcing_imag = forcing rhs = (forcing_real * vr + forcing_real * vi + forcing_imag * vr - forcing_imag * vi) * dx for ii in range(num_bndrys): if ((boundary_conditions[ii][0] == 'robin') or (boundary_conditions[ii][0] == 'neumann')): beta_real, beta_imag = boundary_conditions[ii][2] # real part of robin boundary conditions rhs += (beta_real * vr - beta_imag * vi) * ds(ii) # imag part of robin boundary conditions rhs += (beta_real * vi + beta_imag * vr) * ds(ii) # compute solution p = dl.Function(function_space) #solve(a == L, p) dl.solve(bilinear_form == rhs, p, bcs=dirichlet_bcs) return p
import dolfin import ufl import numpy as np import matplotlib.pyplot as plt dolfin.parameters["use_petsc_signal_handler"] = True dolfin.parameters["form_compiler"]["cpp_optimize"] = True dolfin.parameters["form_compiler"]["representation"] = "uflacs" n = 100 mesh = dolfin.UnitSquareMesh(n, n) V = dolfin.FunctionSpace(mesh, 'CG', 1) u = dolfin.Function(V) ut = dolfin.TestFunction(V) v = dolfin.TrialFunction(V) dx = dolfin.Measure("dx", domain=mesh) bc = dolfin.DirichletBC(V, 0, "on_boundary") a_k = ufl.dot(ufl.grad(ut), ufl.grad(v)) * dx a_m = ut * v * dx eig_solver = EigenSolver(a_k, u, a_m, [bc]) #eig_solver = EigenSolver(a_k, u, bcs=[bc]) plt.savefig("operators.png") ncv, it = eig_solver.solve(10) eigs = eig_solver.get_eigenvalues(ncv) plt.figure() plt.plot(eigs, 'o') plt.title("Eigenvalues") plt.savefig("eigenvalues.png") eig_solver.save_eigenvectors(ncv) for i in range(ncv):
def solve_nonlinear(self, inputs, outputs): pde_problem = self.options['pde_problem'] state_name = self.options['state_name'] problem_type = self.options['problem_type'] visualization = self.options['visualization'] state_function = pde_problem.states_dict[state_name]['function'] for argument_name, argument_function in iteritems(self.argument_functions_dict): density_func = argument_function mesh = state_function.function_space().mesh() sub_domains = df.MeshFunction('size_t', mesh, mesh.topology().dim() - 1) upper_edge = TractionBoundary() upper_edge.mark(sub_domains, 6) dss = df.Measure('ds')(subdomain_data=sub_domains) tractionBC = dss(6) self.itr = self.itr + 1 state_function = pde_problem.states_dict[state_name]['function'] residual_form = get_residual_form( state_function, df.TestFunction(state_function.function_space()), density_func, density_func.function_space(), tractionBC, # df.Constant((0.0, -9.e-1)) df.Constant((0.0, -9.e-1)), int(self.itr) ) self._set_values(inputs, outputs) self.derivative_form = df.derivative(residual_form, state_function) df.set_log_level(df.LogLevel.ERROR) df.set_log_active(True) # df.solve(residual_form==0, state_function, bcs=pde_problem.bcs_list, J=self.derivative_form) if problem_type == 'linear_problem': df.solve(residual_form==0, state_function, bcs=pde_problem.bcs_list, J=self.derivative_form, solver_parameters={"newton_solver":{"maximum_iterations":60, "error_on_nonconvergence":False}}) elif problem_type == 'nonlinear_problem': problem = df.NonlinearVariationalProblem(residual_form, state_function, pde_problem.bcs_list, self.derivative_form) solver = df.NonlinearVariationalSolver(problem) solver.parameters['nonlinear_solver_']='snes' solver.parameters["snes_solver"]["line_search"] = 'bt' solver.parameters["snes_solver"]["linear_solver_"]='mumps' # "cg" "gmres" solver.parameters["snes_solver"]["maximum_iterations"]=500 solver.parameters["snes_solver"]["relative_tolerance"]=5e-13 solver.parameters["snes_solver"]["absolute_tolerance"]=5e-13 # solver.parameters["snes_solver"]["linear_solver_"]["maximum_iterations"]=1000 solver.parameters["snes_solver"]["error_on_nonconvergence"] = False solver.solve() elif problem_type == 'nonlinear_problem_load_stepping': num_steps = 3 state_function.vector().set_local(np.zeros((state_function.function_space().dim()))) for i in range(num_steps): v = df.TestFunction(state_function.function_space()) if i < (num_steps-1): residual_form = get_residual_form( state_function, v, density_func, density_func.function_space(), tractionBC, # df.Constant((0.0, -9.e-1)) df.Constant((0.0, -9.e-1/num_steps*(i+1))), int(self.itr) ) else: residual_form = get_residual_form( state_function, v, density_func, density_func.function_space(), tractionBC, # df.Constant((0.0, -9.e-1)) df.Constant((0.0, -9.e-1/num_steps*(i+1))), int(self.itr) ) problem = df.NonlinearVariationalProblem(residual_form, state_function, pde_problem.bcs_list, self.derivative_form) solver = df.NonlinearVariationalSolver(problem) solver.parameters['nonlinear_solver_']='snes' solver.parameters["snes_solver"]["line_search"] = 'bt' solver.parameters["snes_solver"]["linear_solver_"]='mumps' # "cg" "gmres" solver.parameters["snes_solver"]["maximum_iterations"]=500 solver.parameters["snes_solver"]["relative_tolerance"]=1e-15 solver.parameters["snes_solver"]["absolute_tolerance"]=1e-15 # solver.parameters["snes_solver"]["linear_solver_"]["maximum_iterations"]=1000 solver.parameters["snes_solver"]["error_on_nonconvergence"] = False solver.solve() # option to store the visualization results if visualization == 'True': for argument_name, argument_function in iteritems(self.argument_functions_dict): df.File('solutions_iterations_3d/{}_{}.pvd'.format(argument_name, self.itr)) << argument_function self.L = -residual_form self.itr = self.itr+1 outputs[state_name] = state_function.vector().get_local()
pde.solver = dl.PETScKrylovSolver(mesh.mpi_comm(), "cg", amg_method()) pde.solver_fwd_inc = dl.PETScKrylovSolver(mesh.mpi_comm(), "cg", amg_method()) pde.solver_adj_inc = dl.PETScKrylovSolver(mesh.mpi_comm(), "cg", amg_method()) pde.solver.parameters["relative_tolerance"] = 1e-15 pde.solver.parameters["absolute_tolerance"] = 1e-20 pde.solver_fwd_inc.parameters = pde.solver.parameters pde.solver_adj_inc.parameters = pde.solver.parameters # define the QOI GC = GammaBottom() marker = dl.FacetFunction("size_t", mesh) marker.set_all(0) GC.mark(marker, 1) dss = dl.Measure("ds", subdomain_data=marker) qoi = FluxQOI(Vh, dss(1)) # qoi = QoI(Vh) # define the misfit n1d = 7 ntargets = n1d**2 targets = np.zeros((ntargets, 2)) x1d = np.array(range(n1d)) / float(n1d + 1) + 1 / float(n1d + 1) for i in range(n1d): for j in range(n1d): targets[i * n1d + j, 0] = x1d[i] targets[i * n1d + j, 1] = x1d[j] if rank == 0: print("Number of observation points: {0}".format(ntargets))
def solve_linear(self, d_outputs, d_residuals, mode): linear_solver_ = self.options['linear_solver_'] pde_problem = self.options['pde_problem'] state_name = self.options['state_name'] state_function = pde_problem.states_dict[state_name]['function'] for argument_name, argument_function in iteritems(self.argument_functions_dict): density_func = argument_function mesh = state_function.function_space().mesh() sub_domains = df.MeshFunction('size_t', mesh, mesh.topology().dim() - 1) upper_edge = TractionBoundary() upper_edge.mark(sub_domains, 6) dss = df.Measure('ds')(subdomain_data=sub_domains) tractionBC = dss(6) residual_form = get_residual_form( state_function, df.TestFunction(state_function.function_space()), density_func, density_func.function_space(), tractionBC, # df.Constant((0.0, -9.e-1)) df.Constant((0.0, -9.e-1)), int(self.itr) ) A, _ = df.assemble_system(self.derivative_form, - residual_form, pde_problem.bcs_list) if linear_solver_=='fenics_direct': rhs_ = df.Function(state_function.function_space()) dR = df.Function(state_function.function_space()) rhs_.vector().set_local(d_outputs[state_name]) for bc in pde_problem.bcs_list: bc.apply(A) Am = df.as_backend_type(A).mat() ATm = Am.transpose() AT = df.PETScMatrix(ATm) df.solve(AT,dR.vector(),rhs_.vector()) d_residuals[state_name] = dR.vector().get_local() elif linear_solver_=='scipy_splu': for bc in pde_problem.bcs_list: bc.apply(A) Am = df.as_backend_type(A).mat() ATm = Am.transpose() ATm_csr = csr_matrix(ATm.getValuesCSR()[::-1], shape=Am.size) lu = splu(ATm_csr.tocsc()) d_residuals[state_name] = lu.solve(d_outputs[state_name],trans='T') elif linear_solver_=='fenics_Krylov': rhs_ = df.Function(state_function.function_space()) dR = df.Function(state_function.function_space()) rhs_.vector().set_local(d_outputs[state_name]) for bc in pde_problem.bcs_list: bc.apply(A) Am = df.as_backend_type(A).mat() ATm = Am.transpose() AT = df.PETScMatrix(ATm) solver = df.KrylovSolver('gmres', 'ilu') prm = solver.parameters prm["maximum_iterations"]=1000000 prm["divergence_limit"] = 1e2 solver.solve(AT,dR.vector(),rhs_.vector()) d_residuals[state_name] = dR.vector().get_local() elif linear_solver_=='petsc_gmres_ilu': ksp = PETSc.KSP().create() ksp.setType(PETSc.KSP.Type.GMRES) ksp.setTolerances(rtol=5e-11) for bc in pde_problem.bcs_list: bc.apply(A) Am = df.as_backend_type(A).mat() ksp.setOperators(Am) ksp.setFromOptions() pc = ksp.getPC() pc.setType("ilu") size = state_function.function_space().dim() dR = PETSc.Vec().create() dR.setSizes(size) dR.setType('seq') dR.setValues(range(size), d_residuals[state_name]) dR.setUp() du = PETSc.Vec().create() du.setSizes(size) du.setType('seq') du.setValues(range(size), d_outputs[state_name]) du.setUp() if mode == 'fwd': ksp.solve(dR,du) d_outputs[state_name] = du.getValues(range(size)) else: ksp.solveTranspose(du,dR) d_residuals[state_name] = dR.getValues(range(size))
def numerical_test( user_parameters, ell=0.05, nu=0., ): time_data = [] time_data_pd = [] spacetime = [] lmbda_min_prev = 1e-6 bifurcated = False bifurcation_loads = [] save_current_bifurcation = False bifurc_i = 0 bifurcation_loads = [] # Create mesh and define function space geometry_parameters = {'Lx': 1., 'Ly': .1, 'n': 5} # Define Dirichlet boundaries outdir = '../test/output/test_secondorderevo' Path(outdir).mkdir(parents=True, exist_ok=True) with open('../parameters/form_compiler.yml') as f: form_compiler_parameters = yaml.load(f, Loader=yaml.FullLoader) with open('../parameters/solvers_default.yml') as f: solver_parameters = yaml.load(f, Loader=yaml.FullLoader) with open('../parameters/model1d.yaml') as f: material_parameters = yaml.load(f, Loader=yaml.FullLoader)['material'] with open('../parameters/loading.yaml') as f: loading_parameters = yaml.load(f, Loader=yaml.FullLoader)['loading'] with open('../parameters/stability.yaml') as f: stability_parameters = yaml.load(f, Loader=yaml.FullLoader)['stability'] Path(outdir).mkdir(parents=True, exist_ok=True) print('Outdir is: ' + outdir) default_parameters = { 'code': { **code_parameters }, 'compiler': { **form_compiler_parameters }, 'geometry': { **geometry_parameters }, 'loading': { **loading_parameters }, 'material': { **material_parameters }, 'solver': { **solver_parameters }, 'stability': { **stability_parameters }, } default_parameters.update(user_parameters) # FIXME: Not nice parameters = default_parameters with open(os.path.join(outdir, 'parameters.yaml'), "w") as f: yaml.dump(parameters, f, default_flow_style=False) Lx = parameters['geometry']['Lx'] Ly = parameters['geometry']['Ly'] ell = parameters['material']['ell'] comm = MPI.comm_world geom = mshr.Rectangle(dolfin.Point(-Lx / 2., -Ly / 2.), dolfin.Point(Lx / 2., Ly / 2.)) # import pdb; pdb.set_trace() # resolution = max(geometry_parameters['n'] * Lx / ell, 1/(Ly*10)) resolution = max(geometry_parameters['n'] * Lx / ell, 5 / (Ly * 10)) resolution = 50 mesh = mshr.generate_mesh(geom, resolution) meshf = dolfin.File(os.path.join(outdir, "mesh.xml")) meshf << mesh plot(mesh) plt.savefig(os.path.join(outdir, "mesh.pdf"), bbox_inches='tight') savelag = 1 left = dolfin.CompiledSubDomain("near(x[0], -Lx/2.)", Lx=Lx) right = dolfin.CompiledSubDomain("near(x[0], Lx/2.)", Lx=Lx) left_bottom_pt = dolfin.CompiledSubDomain( "near(x[0],-Lx/2.) && near(x[1],-Ly/2.)", Lx=Lx, Ly=Ly) mf = dolfin.MeshFunction("size_t", mesh, 1, 0) right.mark(mf, 1) left.mark(mf, 2) ds = dolfin.Measure("ds", subdomain_data=mf) dx = dolfin.Measure("dx", metadata=form_compiler_parameters, domain=mesh) # Function Spaces V_u = dolfin.VectorFunctionSpace(mesh, "CG", 1) V_alpha = dolfin.FunctionSpace(mesh, "CG", 1) u = dolfin.Function(V_u, name="Total displacement") alpha = Function(V_alpha) dalpha = TrialFunction(V_alpha) alpha_bif = dolfin.Function(V_alpha) alpha_bif_old = dolfin.Function(V_alpha) state = {'u': u, 'alpha': alpha} Z = dolfin.FunctionSpace( mesh, dolfin.MixedElement([u.ufl_element(), alpha.ufl_element()])) z = dolfin.Function(Z) v, beta = dolfin.split(z) ut = dolfin.Expression("t", t=0.0, degree=0) bcs_u = [ dolfin.DirichletBC(V_u.sub(0), dolfin.Constant(0), left), dolfin.DirichletBC(V_u.sub(0), ut, right), dolfin.DirichletBC(V_u, (0, 0), left_bottom_pt, method="pointwise") ] bcs_alpha_l = DirichletBC(V_alpha, Constant(0.0), left) bcs_alpha_r = DirichletBC(V_alpha, Constant(0.0), right) # bcs_alpha =[bcs_alpha_l, bcs_alpha_r] bcs_alpha = [] bcs = {"damage": bcs_alpha, "elastic": bcs_u} # import pdb; pdb.set_trace() ell = parameters['material']['ell'] # Problem definition # Problem definition k_res = parameters['material']['k_res'] a = (1 - alpha)**2. + k_res w_1 = parameters['material']['sigma_D0']**2 / parameters['material']['E'] w = w_1 * alpha eps = sym(grad(u)) lmbda0 = parameters['material']['E'] * parameters['material']['nu'] / ( 1. - parameters['material']['nu'])**2. mu0 = parameters['material']['E'] / 2. / (1.0 + parameters['material']['nu']) Wu = 1. / 2. * lmbda0 * tr(eps)**2. + mu0 * inner(eps, eps) energy = a * Wu * dx + w_1 *( alpha + \ parameters['material']['ell']** 2.*inner(grad(alpha), grad(alpha)))*dx eps_ = variable(eps) sigma = diff(a * Wu, eps_) e1 = dolfin.Constant([1, 0]) file_out = dolfin.XDMFFile(os.path.join(outdir, "output.xdmf")) file_out.parameters["functions_share_mesh"] = True file_out.parameters["flush_output"] = True file_postproc = dolfin.XDMFFile( os.path.join(outdir, "output_postproc.xdmf")) file_postproc.parameters["functions_share_mesh"] = True file_postproc.parameters["flush_output"] = True file_eig = dolfin.XDMFFile(os.path.join(outdir, "modes.xdmf")) file_eig.parameters["functions_share_mesh"] = True file_eig.parameters["flush_output"] = True file_bif = dolfin.XDMFFile(os.path.join(outdir, "bifurcation.xdmf")) file_bif.parameters["functions_share_mesh"] = True file_bif.parameters["flush_output"] = True file_bif_postproc = dolfin.XDMFFile( os.path.join(outdir, "bifurcation_postproc.xdmf")) file_bif_postproc.parameters["functions_share_mesh"] = True file_bif_postproc.parameters["flush_output"] = True solver = EquilibriumAM(energy, state, bcs, parameters=parameters['solver']) stability = StabilitySolver(energy, state, bcs, parameters=parameters['stability']) linesearch = LineSearch(energy, state) xs = np.linspace(-parameters['geometry']['Lx'] / 2., parameters['geometry']['Lx'] / 2, 50) load_steps = np.linspace(parameters['loading']['load_min'], parameters['loading']['load_max'], parameters['loading']['n_steps']) log(LogLevel.INFO, '====================== EVO ==========================') log(LogLevel.INFO, '{}'.format(parameters)) for it, load in enumerate(load_steps): log(LogLevel.CRITICAL, '====================== STEPPING ==========================') log(LogLevel.CRITICAL, 'CRITICAL: Solving load t = {:.2f}'.format(load)) ut.t = load (time_data_i, am_iter) = solver.solve() # Second order stability conditions (stable, negev) = stability.solve(solver.damage.problem.lb) log(LogLevel.CRITICAL, 'Current state is{}stable'.format(' ' if stable else ' un')) # we postpone the update after the stability check solver.update() mineig = stability.mineig if hasattr(stability, 'mineig') else 0.0 log(LogLevel.INFO, 'INFO: lmbda min {}'.format(lmbda_min_prev)) log(LogLevel.INFO, 'INFO: mineig {}'.format(mineig)) Deltav = (mineig - lmbda_min_prev) if hasattr(stability, 'eigs') else 0 if (mineig + Deltav) * (lmbda_min_prev + dolfin.DOLFIN_EPS) < 0 and not bifurcated: bifurcated = True # save 3 bif modes print('About to bifurcate load ', load, 'step', it) bifurcation_loads.append(load) modes = np.where(stability.eigs < 0)[0] with dolfin.XDMFFile(os.path.join(outdir, "postproc.xdmf")) as file: leneigs = len(modes) maxmodes = min(3, leneigs) for n in range(maxmodes): mode = dolfin.project(stability.linsearch[n]['beta_n'], V_alpha) modename = 'beta-%d' % n print(modename) file.write_checkpoint(mode, modename, 0, append=True) bifurc_i += 1 lmbda_min_prev = mineig if hasattr(stability, 'mineig') else 0. time_data_i["load"] = load time_data_i["alpha_max"] = max(alpha.vector()[:]) time_data_i["elastic_energy"] = dolfin.assemble( 1. / 2. * material_parameters['E'] * a * eps**2. * dx) time_data_i["dissipated_energy"] = dolfin.assemble( (w + w_1 * material_parameters['ell']**2. * inner(grad(alpha), grad(alpha))) * dx) time_data_i["stable"] = stability.stable time_data_i["# neg ev"] = stability.negev time_data_i["eigs"] = stability.eigs if hasattr(stability, 'eigs') else np.inf snn = dolfin.dot(dolfin.dot(sigma, e1), e1) time_data_i["sigma"] = 1 / parameters['geometry'][ 'Ly'] * dolfin.assemble(snn * ds(1)) log( LogLevel.INFO, "Load/time step {:.4g}: iteration: {:3d}, err_alpha={:.4g}".format( time_data_i["load"], time_data_i["iterations"][0], time_data_i["alpha_error"][0])) time_data.append(time_data_i) time_data_pd = pd.DataFrame(time_data) if np.mod(it, savelag) == 0: with file_out as f: f.write(alpha, load) f.write(u, load) with dolfin.XDMFFile(os.path.join(outdir, "output_postproc.xdmf")) as f: f.write_checkpoint(alpha, "alpha-{}".format(it), 0, append=True) log(LogLevel.PROGRESS, 'PROGRESS: written step {}'.format(it)) time_data_pd.to_json(os.path.join(outdir, "time_data.json")) spacetime.append(get_trace(alpha)) if save_current_bifurcation: # modes = np.where(stability.eigs < 0)[0] time_data_i['h_opt'] = h_opt time_data_i['max_h'] = hmax time_data_i['min_h'] = hmin with file_bif_postproc as file: # leneigs = len(modes) # maxmodes = min(3, leneigs) beta0v = dolfin.project(stability.perturbation_beta, V_alpha) log( LogLevel.DEBUG, 'DEBUG: irrev {}'.format(alpha.vector() - alpha_old.vector())) file.write_checkpoint(beta0v, 'beta0', 0, append=True) file.write_checkpoint(alpha_bif_old, 'alpha-old', 0, append=True) file.write_checkpoint(alpha_bif, 'alpha-bif', 0, append=True) file.write_checkpoint(alpha, 'alpha', 0, append=True) np.save(os.path.join(outdir, 'energy_perturbations'), energy_perturbations, allow_pickle=True, fix_imports=True) with file_eig as file: _v = dolfin.project( dolfin.Constant(h_opt) * perturbation_v, V_u) _beta = dolfin.project( dolfin.Constant(h_opt) * perturbation_beta, V_alpha) _v.rename('perturbation displacement', 'perturbation displacement') _beta.rename('perturbation damage', 'perturbation damage') # import pdb; pdb.set_trace() f.write(_v, load) f.write(_beta, load) _spacetime = pd.DataFrame(spacetime) spacetime = _spacetime.fillna(0) mat = np.matrix(spacetime) plt.imshow(mat, cmap='Greys', vmin=0., vmax=1., aspect=.1) plt.colorbar() def format_space(x, pos, xresol=100): return '$%1.1f$' % ((-x + xresol / 2) / xresol) def format_time(t, pos, xresol=100): return '$%1.1f$' % ((t - parameters['loading']['load_min']) / parameters['loading']['n_steps'] * parameters['loading']['load_max']) from matplotlib.ticker import FuncFormatter, MaxNLocator ax = plt.gca() ax.yaxis.set_major_formatter(FuncFormatter(format_space)) ax.xaxis.set_major_formatter(FuncFormatter(format_time)) plt.xlabel('$x$') plt.ylabel('$t$') plt.savefig(os.path.join(outdir, "spacetime.pdf".format(load)), bbox_inches="tight") spacetime.to_json(os.path.join(outdir + "/spacetime.json")) from matplotlib.ticker import FuncFormatter, MaxNLocator plot(alpha) plt.savefig(os.path.join(outdir, 'alpha.pdf')) log(LogLevel.INFO, "Saved figure: {}".format(os.path.join(outdir, 'alpha.pdf'))) xs = np.linspace(-Lx / 2., Lx / 2., 100) profile = np.array([alpha(x, 0) for x in xs]) plt.figure() plt.plot(xs, profile, marker='o') plt.plot(xs, np.array([u(x, 0) for x in xs])) # plt.ylim(0., 1.) plt.savefig(os.path.join(outdir, 'profile.pdf')) return time_data_pd, outdir
def compute(self, t_end=Q_(10.0, 's'), num_steps=500): r"""For incompressible flow, the continuity equation is: .. math:: \nabla\cdot \mathbf{u} = 0 and the Navier-Stokes equation becomes: .. math:: \rho\left(\frac{\partial\mathbf{u}}{\partial t} + \mathbf{u}\cdot\nabla \mathbf{u}\right) = \nabla\cdot\bar{\pi} + \mathbf{F} where :math:`\mathbf{u}` is the fluid velocity, :math:`p` is the pressure and where :math:`\mathbf{F}=\rho\mathbf{g}` is the volume force due to gravity. The molecular stress tensor :math:`\bar{\pi}` is denoted by: .. math:: \bar{\pi} = \bar{\tau} - p\bar{I}, \quad \bar{I}\textrm{ is the unit tensor} where :math:`\bar{\tau}` is the viscous stress tensor defined by: .. math:: \bar{\tau} = 2\mu\bar{\epsilon} and where .. math:: \bar{\epsilon} = \frac{1}{2}\left(\nabla \mathbf{u} + (\nabla\mathbf{u})^T \right) is the strain-rate tensor. The variational formulation of the viscous term is: .. math:: \int_\Omega \left(\nabla\cdot\bar{\pi}\right)\cdot \mathbf{v}d\mathbf{x} Since the term :math:`\nabla\cdot\bar{\pi}` contains second-order derivatives of the velocity field :math:`\mathbf{u}`, we integrate this term by parts: .. math:: -\int_\Omega\left(\nabla\cdot\bar{\pi}\right)\cdot \mathbf{v}d\mathbf{x} = \int_\Omega \bar{\pi}:\nabla \mathbf{v}d\mathbf{x}-\int_{\delta\Omega}\left(\bar{\pi} \cdot\hat{\mathbf{n}}\right)\cdot\mathbf{v}ds where the colon operator is the inner product (Frobenius inner-product) between tensors, and :math:`\hat{\mathbf{n}}` is the outward unit normal at the boundary (traction, or stress vector). In cylindrical coordinates (:math:`r,~ \theta,~ z`), the gradient of the velocity field :math:`\mathbf{u}` writes .. math:: \nabla\cdot{\mathbf{u}} = \left( \begin{array}{ccc} \frac{\partial u_r}{\partial r} & \frac{\partial u_\theta}{\partial r} & \frac{\partial u_z}{\partial r}\\ \frac{1}{r}\frac{\partial u_r}{\partial \theta}- \frac{u_\theta}{r}& \frac{1}{r}\frac{\partial u_\theta}{\partial \theta}+ \frac{u_r}{r}& \frac{1}{r}\frac{\partial u_z}{\partial \theta}\\ \frac{\partial u_r}{\partial z} & \frac{\partial u_\theta}{\partial z} & \frac{\partial u_z}{\partial z} \end{array} \right) The strain-rate tensor :math:`\bar{\epsilon}` is then: .. math:: \bar{\epsilon} = \left( \begin{array}{ccc} \frac{\partial u_r}{\partial r} & \frac{1}{2}\left(\frac{\partial u_\theta}{\partial r} + \frac{1}{r}\frac{\partial u_\theta}{\partial \theta}- \frac{u_\theta}{r}\right)& \frac{1}{2}\left(\frac{\partial u_z}{\partial r}+ \frac{\partial u_r}{\partial z}\right)\\ \frac{1}{2}\left(\frac{1}{r}\frac{\partial u_r}{\partial \theta}- \frac{u_\theta}{r}+\frac{\partial u_\theta}{\partial r}\right)& \frac{1}{r}\frac{\partial u_\theta}{\partial \theta}+ \frac{u_r}{r}& \frac{1}{2}\left(\frac{1}{r}\frac{\partial u_z}{\partial \theta}+\frac{\partial u_\theta}{\partial z}\right)\\ \frac{1}{2}\left(\frac{\partial u_r}{\partial z} +\frac{\partial u_z}{\partial r}\right)& \frac{1}{2}\left(\frac{\partial u_\theta}{\partial z} +\frac{1}{r}\frac{\partial u_z}{\partial \theta}\right)& \frac{\partial u_z}{\partial z} \end{array} \right) From the definition above, the viscous stress tensor :math:`\bar{\tau}` is: .. math:: \bar{\tau} = \mu\left( \begin{array}{ccc} 2\frac{\partial u_r}{\partial r} & \frac{\partial u_\theta}{\partial r} + \frac{1}{r}\frac{\partial u_\theta}{\partial \theta}- \frac{u_\theta}{r}& \frac{\partial u_z}{\partial r}+ \frac{\partial u_r}{\partial z}\\ \frac{1}{r}\frac{\partial u_r}{\partial \theta}- \frac{u_\theta}{r}+\frac{\partial u_\theta}{\partial r}& 2\left(\frac{1}{r}\frac{\partial u_\theta}{\partial \theta}+ \frac{u_r}{r}\right)& \frac{1}{r}\frac{\partial u_z}{\partial \theta}+\frac{\partial u_\theta}{\partial z}\\ \frac{\partial u_r}{\partial z} +\frac{\partial u_z}{\partial r}& \frac{\partial u_\theta}{\partial z} +\frac{1}{r}\frac{\partial u_z}{\partial \theta}& 2\frac{\partial u_z}{\partial z} \end{array} \right) and the molecular stress tensor :math:`\bar{\pi}` is: .. math:: \bar{\pi} = \mu\left( \begin{array}{ccc} 2\frac{\partial u_r}{\partial r} -\frac{p}{\mu}& \frac{\partial u_\theta}{\partial r} + \frac{1}{r}\frac{\partial u_\theta}{\partial \theta}- \frac{u_\theta}{r}& \frac{\partial u_z}{\partial r}+ \frac{\partial u_r}{\partial z}\\ \frac{1}{r}\frac{\partial u_r}{\partial \theta}- \frac{u_\theta}{r}+\frac{\partial u_\theta}{\partial r}& 2\left(\frac{1}{r}\frac{\partial u_\theta}{\partial \theta}+ \frac{u_r}{r}\right) -\frac{p}{\mu} & \frac{1}{r}\frac{\partial u_z}{\partial \theta}+\frac{\partial u_\theta}{\partial z}\\ \frac{\partial u_r}{\partial z} +\frac{\partial u_z}{\partial r}& \frac{\partial u_\theta}{\partial z} +\frac{1}{r}\frac{\partial u_z}{\partial \theta}& 2\frac{\partial u_z}{\partial z} -\frac{p}{\mu} \end{array} \right) The scalar product (or double dot product) of two tensors is the summed pairwise product of all element of the tensors, i.e. .. math:: \bar{\pi}:\nabla\mathbf{v} = \pi_{rr}\frac{\partial v_r}{\partial r}+ \pi_{r\theta}\frac{\partial v_\theta}{\partial r}+\ldots + \pi_{zz}\frac{\partial v_z}{\partial z} and the vector product (or dot product) of a tensor with a vector is just the regular product between a matrix and a vector. .. math:: \bar{\pi}\cdot \hat{\mathbf{n}} = \left(\pi_{rr}n_r+ \pi_{r\theta}n_\theta + \pi_{rz}nz\right) \hat{\mathbf{e}}_r + \left(\pi_{\theta r}n_r + \dots\right)\hat{\mathbf{e}}_\theta + \left(\ldots + \pi_{r\theta}n_\theta\right)\hat{\mathbf{e}}_z **Axisymmetric Formulation** We consider a solid of revolution around a fixed axis (Oz), the loading, boundary conditions and material properties are invariant with respect to a rotation along the symmetry axis. The solid cross-section in a plane :math:`\Theta=` cst is represented by a two-dimensional domain :math:`\omega` for which the first spatial variable (x[0] in FEniCS) will represent the radial coordinate :math:`r` whereas the second spatial variable will denote the axial variable :math:`z`. In axisymmetric conditions, the full 3D domain :math:`\Omega` can be decomposed as :math:`\Omega=\omega\times[0;2\pi]` where the interval represents the :math:`\theta` variable. The integration measures therefore reduce to :math:`dx=d\omega\cdot(rd\theta)` and :math:`dS=ds\cdot(rd\theta)` where :math:`dS` is the surface integration measure on the 3D domain :math:`\Omega` and :math:`ds` its counterpart on the cross-section boundary :math:`\partial\omega`. Exploiting the invariance of all fields with respect to :math:`\theta`, we get the variational formulation of the viscous term as: .. math:: -\int_\Omega\left(\nabla\cdot\bar{\pi}\right)\cdot \mathbf{v}d\mathbf{x} = 2\pi\int_\omega \bar{\pi}:\nabla \mathbf{v}rd\omega-2\pi\int_{\delta\omega}\left(\bar{\pi} \cdot\hat{\mathbf{n}}\right)\cdot\mathbf{v}r ds For an axisymmetric model there is no gradient in the azimuthal direction :math:`\theta`. If we also assume that the :math:`\theta`-component of the velocity field is zero, we obtain the gradient of the velocity field: .. math:: \nabla\cdot{\mathbf{u}} = \left( \begin{array}{ccc} \frac{\partial u_r}{\partial r} & 0 & \frac{\partial u_z}{\partial r}\\ 0& \frac{u_r}{r}& 0\\ \frac{\partial u_r}{\partial z} & 0& \frac{\partial u_z}{\partial z} \end{array} \right) and the following strain-rate tensor: .. math:: \bar{\epsilon} = \left( \begin{array}{ccc} \frac{\partial u_r}{\partial r} & 0& \frac{1}{2}\left(\frac{\partial u_z}{\partial r}+ \frac{\partial u_r}{\partial z}\right)\\ 0& \frac{u_r}{r}& 0\\ \frac{1}{2}\left(\frac{\partial u_r}{\partial z} +\frac{\partial u_z}{\partial r}\right)& 0& \frac{\partial u_z}{\partial z} \end{array} \right) *Note*: The vector function space dimension is now two-dimensional. We can keep the 3D tensor notation if we perform the integrands manually before assembling the bilinear and linear forms. *Note*: The factor :math:`u_r/r` is problematic for :math:`r\approx 0`. One solution is to ... for axisymmetric flow, the velocity field is composed of two components, i.e. .. math:: \mathbf{u} = u_r\hat{\mathbf{e}}_r+u_z\hat{\mathbf{e}}_z **Splitting Method**: To overcome the saddle-point problems resulting from a direct discretization of the Navier-Stokes equations we use a splitting scheme where the velocity and pressure variables are computed in a sequence of predictor-corrector type steps. Incremental Pressure Correction Scheme (IPCS) -- see :cite:`Logg2012` for details of the algorithm. In summary, we may thus solve the incompressible Navier-Stokes equations efficiently by solving a sequence of three linear variational problems in each time step. In order to simulate steady-state use t_end = large number :param t_end: Final time, default = 10 s. :type t_end: ureg.Quantity :param num_steps: Number of time steps, default = 500. :type num_steps: int :return: The solution. """ out = None dt = t_end.to('s').magnitude / num_steps radius = self._size[0].magnitude length = self._size[1].magnitude mu = self._mu.magnitude rho = self._rho.magnitude pin = self._pin.magnitude # TODO: something is odd with this mesh, needs investigations mesh = self._mesh dom = dolfin.cpp.mesh.MeshFunctionSizet(mesh, mesh.mvc_dom()) bnd = dolfin.cpp.mesh.MeshFunctionSizet(mesh, mesh.mvc_bnd()) dx = dolfin.Measure("dx", domain=mesh, subdomain_data=dom) ds = dolfin.Measure("ds", domain=mesh, subdomain_data=bnd) return out