def eva(self, num): # construct basis functions, Set num points corresponding to num basis functions basPoints = np.linspace(0, 1, num) dx = basPoints[1] - basPoints[0] aa, bb, cc = -dx, 0.0, dx for x_p in basPoints: self.theta.append( fe.interpolate( fe.Expression( 'x[0] < a || x[0] > c ? 0 : (x[0] >=a && x[0] <= b ? (x[0]-a)/(b-a) : 1-(x[0]-b)/(c-b))', degree=2, a=aa, b=bb, c=cc), self.Vc)) aa, bb, cc = aa + dx, bb + dx, cc + dx u_trial, u_test = fe.TrialFunction(self.Vu), fe.TestFunction(self.Vu) left = fe.inner(self.al * fe.nabla_grad(u_trial), fe.nabla_grad(u_test)) * fe.dx right = self.f * u_test * fe.dx def boundaryD(x, on_boundary): return on_boundary and fe.near(x[1], 1.0) for i in range(num): uH = fe.Function(self.Vu) bcD = fe.DirichletBC(self.Vu, self.theta[i], boundaryD) left_m, right_m = fe.assemble_system(left, right, bcD) fe.solve(left_m, uH.vector(), right_m) self.sol.append(uH)
def geneForwardMatrix(self, q_fun=fe.Constant(0.0), fR=fe.Constant(0.0), \ fI=fe.Constant(0.0)): if self.haveFunctionSpace == False: self.geneFunctionSpace() xx, yy, dPML, sig0_, p_ = self.domain.xx, self.domain.yy, self.domain.dPML,\ self.domain.sig0, self.domain.p # define the coefficents induced by PML sig1 = fe.Expression('x[0] > x1 && x[0] < x1 + dd ? sig0*pow((x[0]-x1)/dd, p) : (x[0] < 0 && x[0] > -dd ? sig0*pow((-x[0])/dd, p) : 0)', degree=3, x1=xx, dd=dPML, sig0=sig0_, p=p_) sig2 = fe.Expression('x[1] > x2 && x[1] < x2 + dd ? sig0*pow((x[1]-x2)/dd, p) : (x[1] < 0 && x[1] > -dd ? sig0*pow((-x[1])/dd, p) : 0)', degree=3, x2=yy, dd=dPML, sig0=sig0_, p=p_) sR = fe.as_matrix([[(1+sig1*sig2)/(1+sig1*sig1), 0.0], [0.0, (1+sig1*sig2)/(1+sig2*sig2)]]) sI = fe.as_matrix([[(sig2-sig1)/(1+sig1*sig1), 0.0], [0.0, (sig1-sig2)/(1+sig2*sig2)]]) cR = 1 - sig1*sig2 cI = sig1 + sig2 # define the coefficients with physical meaning angl_fre = self.kappa*np.pi angl_fre2 = fe.Constant(angl_fre*angl_fre) # define equations u_ = fe.TestFunction(self.V) du = fe.TrialFunction(self.V) u_R, u_I = fe.split(u_) duR, duI = fe.split(du) def sigR(v): return fe.dot(sR, fe.nabla_grad(v)) def sigI(v): return fe.dot(sI, fe.nabla_grad(v)) F1 = - fe.inner(sigR(duR)-sigI(duI), fe.nabla_grad(u_R))*(fe.dx) \ - fe.inner(sigR(duI)+sigI(duR), fe.nabla_grad(u_I))*(fe.dx) \ - fR*u_R*(fe.dx) - fI*u_I*(fe.dx) a2 = fe.inner(angl_fre2*q_fun*(cR*duR-cI*duI), u_R)*(fe.dx) \ + fe.inner(angl_fre2*q_fun*(cR*duI+cI*duR), u_I)*(fe.dx) \ # define boundary conditions def boundary(x, on_boundary): return on_boundary bc = [fe.DirichletBC(self.V.sub(0), fe.Constant(0.0), boundary), \ fe.DirichletBC(self.V.sub(1), fe.Constant(0.0), boundary)] a1, L1 = fe.lhs(F1), fe.rhs(F1) self.u = fe.Function(self.V) self.A1 = fe.assemble(a1) self.b1 = fe.assemble(L1) self.A2 = fe.assemble(a2) bc[0].apply(self.A1, self.b1) bc[1].apply(self.A1, self.b1) bc[0].apply(self.A2) bc[1].apply(self.A2) self.A = self.A1 + self.A2
def calTrueSol(para): nx, ny = para['mesh_N'][0], para['mesh_N'][1] mesh = fe.UnitSquareMesh(nx, ny) Vu = fe.FunctionSpace(mesh, 'P', para['P']) Vc = fe.FunctionSpace(mesh, 'P', para['P']) al = fe.Constant(para['alpha']) f = fe.Expression(para['f'], degree=5) q1 = fe.interpolate(fe.Expression(para['q1'], degree=5), Vc) q2 = fe.interpolate(fe.Expression(para['q2'], degree=5), Vc) q3 = fe.interpolate(fe.Expression(para['q3'], degree=5), Vc) theta = fe.interpolate(fe.Expression(para['q4'], degree=5), Vc) class BoundaryX0(fe.SubDomain): def inside(self, x, on_boundary): return on_boundary and fe.near(x[0], 0.0) class BoundaryX1(fe.SubDomain): def inside(self, x, on_boundary): return on_boundary and fe.near(x[0], 1.0) class BoundaryY0(fe.SubDomain): def inside(self, x, on_boundary): return on_boundary and fe.near(x[1], 0.0) class BoundaryY1(fe.SubDomain): def inside(self, x, on_boundary): return on_boundary and fe.near(x[1], 1.0) boundaries = fe.MeshFunction('size_t', mesh, mesh.topology().dim() - 1) boundaries.set_all(0) bc0, bc1, bc2, bc3 = BoundaryX0(), BoundaryX1(), BoundaryY0(), BoundaryY1() bc0.mark(boundaries, 1) bc1.mark(boundaries, 2) bc2.mark(boundaries, 3) bc3.mark(boundaries, 4) domains = fe.MeshFunction("size_t", mesh, mesh.topology().dim()) domains.set_all(0) bcD = fe.DirichletBC(Vu, theta, boundaries, 4) dx = fe.Measure('dx', domain=mesh, subdomain_data=domains) ds = fe.Measure('ds', domain=mesh, subdomain_data=boundaries) u_trial, u_test = fe.TrialFunction(Vu), fe.TestFunction(Vu) u = fe.Function(Vu) left = fe.inner(al * fe.nabla_grad(u_trial), fe.nabla_grad(u_test)) * dx right = f * u_test * dx + (q1 * u_test * ds(1) + q2 * u_test * ds(2) + q3 * u_test * ds(3)) left_m, right_m = fe.assemble_system(left, right, bcD) fe.solve(left_m, u.vector(), right_m) return u
def eva(self): # construct solutions corresponding to the basis functions class BoundaryX0(fe.SubDomain): def inside(self, x, on_boundary): return on_boundary and fe.near(x[0], 0.0) class BoundaryX1(fe.SubDomain): def inside(self, x, on_boundary): return on_boundary and fe.near(x[0], 1.0) class BoundaryY0(fe.SubDomain): def inside(self, x, on_boundary): return on_boundary and fe.near(x[1], 0.0) class BoundaryY1(fe.SubDomain): def inside(self, x, on_boundary): return on_boundary and fe.near(x[1], 1.0) boundaries = fe.MeshFunction('size_t', self.mesh, self.mesh.topology().dim() - 1) boundaries.set_all(0) bc0, bc1, bc2, bc3 = BoundaryX0(), BoundaryX1(), BoundaryY0( ), BoundaryY1() bc0.mark(boundaries, 1) bc1.mark(boundaries, 2) bc2.mark(boundaries, 3) bc3.mark(boundaries, 4) domains = fe.MeshFunction("size_t", self.mesh, self.mesh.topology().dim()) domains.set_all(0) dx = fe.Measure('dx', domain=self.mesh, subdomain_data=domains) ds = fe.Measure('ds', domain=self.mesh, subdomain_data=boundaries) u_trial, u_test = fe.TrialFunction(self.Vu), fe.TestFunction(self.Vu) left = fe.inner(fe.nabla_grad(u_trial), fe.nabla_grad(u_test)) * dx right = self.f * u_test * dx + (self.q1 * u_test * ds(1) + self.q2 * u_test * ds(2) + self.q3 * u_test * ds(3)) bcD = fe.DirichletBC(self.Vu, self.theta, boundaries, 4) left_m, right_m = fe.assemble_system(left, right, bcD) fe.solve(left_m, self.u.vector(), right_m)
f = fs.Constant((0, 0)) k = fs.Constant(dt) mu = fs.Constant(mu) rho = fs.Constant(rho) # Define strain-rate tensor def epsilon(u): return fs.sym(fs.nabla_grad(u)) # Define stress tensor def sigma(u, p): return 2*mu*epsilon(u) - p*fs.Identity(len(u)) # Define variational problem for step 1 (Tentative velocity step) F1 = rho*fs.dot((u - u_n) / k, v)*fs.dx + \ rho*fs.dot(fs.dot(u_n, fs.nabla_grad(u_n)), v)*fs.dx \ + fs.inner(sigma(U, p_n), epsilon(v))*fs.dx \ + fs.dot(p_n*n, v)*fs.ds - fs.dot(mu*fs.nabla_grad(U)*n, v)*fs.ds \ - fs.dot(f, v)*fs.dx a1 = fs.lhs(F1) L1 = fs.rhs(F1) # Define variational problem for step 2 (Pressure correction step) a2 = fs.dot(fs.nabla_grad(p), fs.nabla_grad(q))*fs.dx L2 = fs.dot(fs.nabla_grad(p_n), fs.nabla_grad(q))*fs.dx \ - (1/k)*fs.div(u_)*q*fs.dx # Define variational problem for step 3 (Velocity correction step) a3 = fs.dot(u, v)*fs.dx L3 = fs.dot(u_, v)*fs.dx - k*fs.dot(fs.nabla_grad(p_ - p_n), v)*fs.dx
def b(u, v, w): return 0.5 * (fn.inner(fn.dot(u, fn.nabla_grad(v)), w) - fn.inner(fn.dot(u, fn.nabla_grad(w)), v))
def contract(u, v): return fn.inner(fn.nabla_grad(u), fn.nabla_grad(v))
def solve(self): # TODO: when FEniCS ported to Python3, this should be exist_ok try: os.makedirs('results') except OSError: pass z, w = (self.z, self.w) u0 = d.Constant(0.0) # Define the linear and bilinear forms L = u0 * w * dx # Define useful functions cond = d.Function(self.DV) U = d.Function(self.V) # Initialize the max_e vector, that will store the cumulative max e values max_e = d.Function(self.V) max_e.vector()[:] = 0.0 max_e.rename("max_E", "Maximum energy deposition by location") max_e_file = d.File("results/%s-max_e.pvd" % input_mesh) max_e_per_step = d.Function(self.V) max_e_per_step_file = d.File("results/%s-max_e_per_step.pvd" % input_mesh) self.es = {} self.max_es = {} fi = d.File("results/%s-cond.pvd" % input_mesh) potential_file = d.File("results/%s-potential.pvd" % input_mesh) # Loop through the voltages and electrode combinations for i, (anode, cathode, voltage) in enumerate(v.electrode_triples): print("Electrodes %d (%lf) -> %d (0)" % (anode, voltage, cathode)) cond = d.project(self.sigma_start, V=self.DV) # Define the Dirichlet boundary conditions on the active needles uV = d.Constant(voltage) term1_bc = d.DirichletBC(self.V, uV, self.patches, v.needles[anode]) term2_bc = d.DirichletBC(self.V, u0, self.patches, v.needles[cathode]) e = d.Function(self.V) e.vector()[:] = max_e.vector() # Re-evaluate conductivity self.increase_conductivity(cond, e) for j in range(v.max_restarts): # Update the bilinear form a = d.inner(d.nabla_grad(z), cond * d.nabla_grad(w)) * dx # Solve again print(" [solving...") d.solve(a == L, U, bcs=[term1_bc, term2_bc]) print(" ....solved]") # Extract electric field norm for k in range(len(U.vector())): if N.isnan(U.vector()[k]): U.vector()[k] = 1e5 e_new = d.project(d.sqrt(d.dot(d.grad(U), d.grad(U))), self.V) # Take the max of the new field and the established electric field e.vector()[:] = N.array([max(*X) for X in zip(e.vector(), e_new.vector())]) # Re-evaluate conductivity fi << cond self.increase_conductivity(cond, e) potential_file << U # Save the max e function to a VTU max_e_per_step.vector()[:] = e.vector()[:] max_e_per_step_file << max_e_per_step # Store this electric field norm, for this triple, for later reference self.es[i] = e # Store the max of this electric field norm and that for all previous triples max_e_array = N.array([max(*X) for X in zip(max_e.vector(), e.vector())]) max_e.vector()[:] = max_e_array # Create a new max_e function for storage, or it will be overwritten by the next iteration max_e_new = d.Function(self.V) max_e_new.vector()[:] = max_e_array # Store this max e function for the cumulative coverage curve calculation later self.max_es[i] = max_e_new # Save the max e function to a VTU max_e_file << max_e self.max_e_count = i
def epsilon(u): return 0.5 * (fs.nabla_grad(u) + fs.nabla_grad(u).T)
def sigI(v): return fe.dot(sI, fe.nabla_grad(v))
def sigR(v): return fe.dot(sR, fe.nabla_grad(v))
def nabla_grad(self, arg): return FEN.nabla_grad(arg)
def epsilon(u): return 0.5 * (fenics.nabla_grad(u) + fenics.nabla_grad(u).T ) #return sym(nabla_grad(u))
def xest_implement_2d_myosin(self): #Parameters total_time = 1.0 number_of_time_steps = 100 delta_t = total_time / number_of_time_steps nx = ny = 100 domain_size = 1.0 lambda_ = 5.0 mu = 2.0 gamma = 1.0 eta_b = 0.0 eta_s = 1.0 k_b = 1.0 k_u = 1.0 # zeta_1 = -0.5 zeta_1 = 0.0 zeta_2 = 1.0 mu_a = 1.0 K_0 = 1.0 K_1 = 0.0 K_2 = 0.0 K_3 = 0.0 D = 0.25 alpha = 3 c = 0.1 # Sub domain for Periodic boundary condition class PeriodicBoundary(fenics.SubDomain): # Left boundary is "target domain" G def inside(self, x, on_boundary): # return True if on left or bottom boundary AND NOT on one of the two corners (0, 1) and (1, 0) return bool( (fenics.near(x[0], 0) or fenics.near(x[1], 0)) and (not ((fenics.near(x[0], 0) and fenics.near(x[1], 1)) or (fenics.near(x[0], 1) and fenics.near(x[1], 0)))) and on_boundary) def map(self, x, y): if fenics.near(x[0], 1) and fenics.near(x[1], 1): y[0] = x[0] - 1. y[1] = x[1] - 1. elif fenics.near(x[0], 1): y[0] = x[0] - 1. y[1] = x[1] else: # near(x[1], 1) y[0] = x[0] y[1] = x[1] - 1. periodic_boundary_condition = PeriodicBoundary() #Set up finite elements mesh = fenics.RectangleMesh(fenics.Point(0, 0), fenics.Point(domain_size, domain_size), nx, ny) vector_element = fenics.VectorElement('P', fenics.triangle, 2, dim=2) single_element = fenics.FiniteElement('P', fenics.triangle, 2) mixed_element = fenics.MixedElement(vector_element, single_element) V = fenics.FunctionSpace( mesh, mixed_element, constrained_domain=periodic_boundary_condition) v, r = fenics.TestFunctions(V) full_trial_function = fenics.Function(V) u, rho = fenics.split(full_trial_function) full_trial_function_n = fenics.Function(V) u_n, rho_n = fenics.split(full_trial_function_n) #Define non-linear weak formulation def epsilon(u): return 0.5 * (fenics.nabla_grad(u) + fenics.nabla_grad(u).T ) #return sym(nabla_grad(u)) def sigma_e(u): return lambda_ * ufl.nabla_div(u) * fenics.Identity( 2) + 2 * mu * epsilon(u) def sigma_d(u): return eta_b * ufl.nabla_div(u) * fenics.Identity( 2) + 2 * eta_s * epsilon(u) # def sigma_a(u,rho): # return ( -zeta_1*rho/(1+zeta_2*rho)*mu_a*fenics.Identity(2)*(K_0+K_1*ufl.nabla_div(u)+ # K_2*ufl.nabla_div(u)*ufl.nabla_div(u)+K_3*ufl.nabla_div(u)*ufl.nabla_div(u)*ufl.nabla_div(u))) def sigma_a(u, rho): return -zeta_1 * rho / ( 1 + zeta_2 * rho) * mu_a * fenics.Identity(2) * (K_0) F = (gamma * fenics.dot(u, v) * fenics.dx - gamma * fenics.dot(u_n, v) * fenics.dx + fenics.inner(sigma_d(u), fenics.nabla_grad(v)) * fenics.dx - fenics.inner(sigma_d(u_n), fenics.nabla_grad(v)) * fenics.dx - delta_t * fenics.inner(sigma_e(u) + sigma_a(u, rho), fenics.nabla_grad(v)) * fenics.dx + rho * r * fenics.dx - rho_n * r * fenics.dx + ufl.nabla_div(rho * u) * r * fenics.dx - ufl.nabla_div(rho * u_n) * r * fenics.dx - D * delta_t * fenics.dot(fenics.nabla_grad(rho), fenics.nabla_grad(r)) * fenics.dx + delta_t * (-k_u * rho * fenics.exp(alpha * ufl.nabla_div(u)) + k_b * (1 - c * ufl.nabla_div(u))) * r * fenics.dx) # F = ( gamma*fenics.dot(u,v)*fenics.dx - gamma*fenics.dot(u_n,v)*fenics.dx + fenics.inner(sigma_d(u),fenics.nabla_grad(v))*fenics.dx - # fenics.inner(sigma_d(u_n),fenics.nabla_grad(v))*fenics.dx - delta_t*fenics.inner(sigma_e(u)+sigma_a(u,rho),fenics.nabla_grad(v))*fenics.dx # +rho*r*fenics.dx-rho_n*r*fenics.dx + ufl.nabla_div(rho*u)*r*fenics.dx - ufl.nabla_div(rho*u_n)*r*fenics.dx - # D*delta_t*fenics.dot(fenics.nabla_grad(rho),fenics.nabla_grad(r))*fenics.dx +delta_t*(-k_u*rho*fenics.exp(alpha*ufl.nabla_div(u))+k_b*(1-c*ufl.nabla_div(u)))) vtkfile_rho = fenics.File( os.path.join(os.path.dirname(__file__), 'output', 'myosin_2d', 'solution_rho.pvd')) vtkfile_u = fenics.File( os.path.join(os.path.dirname(__file__), 'output', 'myosin_2d', 'solution_u.pvd')) # rho_0 = fenics.Expression(((('0.0'),('0.0'),('0.0')),('sin(x[0])')), degree=1 ) # full_trial_function_n = fenics.project(rho_0, V) time = 0.0 for time_index in range(number_of_time_steps): # Update current time time += delta_t # Compute solution fenics.solve(F == 0, full_trial_function) # Save to file and plot solution vis_u, vis_rho = full_trial_function.split() vtkfile_rho << (vis_rho, time) vtkfile_u << (vis_u, time) full_trial_function_n.assign(full_trial_function)
def epsilon(u): return fs.sym(fs.nabla_grad(u))
def sigma(u): return lambda_ * fs.nabla_grad(u) * fs.Identity(d) + 2 * mu * epsilon(u)
def epsilon(u): return 0.5 * (nabla_grad(u) + nabla_grad(u).T)
def solve(self): z, w = (self.z, self.w) u0 = d.Constant(0.0) # Define the linear and bilinear forms L = u0 * w * dx # Define useful functions cond = d.Function(self.DV) U = d.Function(self.V) # Initialize the max_e vector, that will store the cumulative max e values max_e = d.Function(self.V) max_e.vector()[:] = 0.0 max_e.rename("max_E", "Maximum energy deposition by location") max_e_file = d.File("../%s-max_e.pvd" % input_mesh) max_e_per_step = d.Function(self.V) max_e_per_step_file = d.File("../%s-max_e_per_step.pvd" % input_mesh) self.es = {} self.max_es = {} fi = d.File("../%s-cond.pvd" % input_mesh) potential_file = d.File("../%s-potential.pvd" % input_mesh) # Loop through the voltages and electrode combinations for i, (anode, cathode, voltage) in enumerate(v.electrode_triples): print("Electrodes %d (%lf) -> %d (0)" % (anode, voltage, cathode)) cond = d.project(self.sigma_start, V=self.DV) # Define the Dirichlet boundary conditions on the active needles uV = d.Constant(voltage) term1_bc = d.DirichletBC(self.V, uV, self.patches, anode) term2_bc = d.DirichletBC(self.V, u0, self.patches, cathode) e = d.Function(self.V) e.vector()[:] = max_e.vector() # Re-evaluate conductivity self.increase_conductivity(cond, e) for j in range(v.max_restarts): # Update the bilinear form a = d.inner(d.nabla_grad(z), cond * d.nabla_grad(w)) * dx # Solve again print(" [solving...") d.solve(a == L, U, bcs=[term1_bc, term2_bc]) print(" ....solved]") # Extract electric field norm for k in range(len(U.vector())): if N.isnan(U.vector()[k]): U.vector()[k] = 1e5 e_new = d.project(d.sqrt(d.dot(d.grad(U), d.grad(U))), self.V) # Take the max of the new field and the established electric field e.vector()[:] = N.array( [max(*X) for X in zip(e.vector(), e_new.vector())]) # Re-evaluate conductivity fi << cond self.increase_conductivity(cond, e) potential_file << U # Save the max e function to a VTU max_e_per_step.vector()[:] = e.vector()[:] max_e_per_step_file << max_e_per_step # Store this electric field norm, for this triple, for later reference self.es[i] = e # Store the max of this electric field norm and that for all previous triples max_e_array = N.array( [max(*X) for X in zip(max_e.vector(), e.vector())]) max_e.vector()[:] = max_e_array # Create a new max_e function for storage, or it will be overwritten by the next iteration max_e_new = d.Function(self.V) max_e_new.vector()[:] = max_e_array # Store this max e function for the cumulative coverage curve calculation later self.max_es[i] = max_e_new # Save the max e function to a VTU max_e_file << max_e self.max_e_count = i