import numpy as np
import matplotlib.pylab as plt
import math
from numpy.linalg import solve, norm
from dolfin import *
from dolfin_adjoint import *
from mshr import *
import pdb
import moola
# Form compiler options
parameters["form_compiler"]["cpp_optimize"] = True
parameters["form_compiler"]["optimize"] = True
class ode(object):
# Konstruktor
def __init__(self, l_1:int, l_2:int, k:float, r_2:float, c_1:float, u_omega:float):
self.l_1 = l_1
self.l_2 = l_2
self.k = k
self.r_2 = r_2
self.c_1 = c_1
self.u_omega = u_omega
def rhs(self,q1,p1,q2,p2,l_12):
f = [p1,
(-self.l_2/((self.l_1*self.l_2-l_12**2)*self.c_1))*q1+(l_12/((self.l_1*self.l_2-l_12**2)*self.c_1))*q2,
p2,
((l_12*self.r_2)/((self.l_1*self.l_2-l_12**2)))*p1-((self.l_1*self.r_2)/(self.l_1*self.l_2-l_12**2))*p2]
return f
def semiImpRK(self,A,q1_i,p1_i,q2_i,p2_i,i,h):
# k1
l_12 = self.k*np.sqrt(self.l_1*self.l_2)
b1 = prob.rhs(q1_i,p1_i,q2_i,p2_i,l_12)
k1 = np.linalg.solve(A,b1)
# k2
b2 = prob.rhs(q1_i+0.5*h*k1[0],p1_i+0.5*h*k1[1],q2_i+0.5*h*k1[2],p2_i+0.5*h*k1[3],l_12)
k2 = np.linalg.solve(A,b2)
# yip1
yip1 = np.zeros(4)
yip1[0] = q1_i + h*k2[0]
yip1[1] = p1_i + h*k2[1]
yip1[2] = q2_i + h*k2[2]
yip1[3] = p2_i + h*k2[3]
print("Ergebnis des " + str(i) + "ten Durchlaufs des Algorithmus\n")
print(str(yip1))
return yip1[0], yip1[1], yip1[2], yip1[3]
def problem(self):
l_12 = self.k*np.sqrt(self.l_1*self.l_2)
jac = np.array([[0, 1, 0, 0],
[-self.l_2/((self.l_1*self.l_2-l_12**2)*self.c_1), 0, l_12/((self.l_1*self.l_2-l_12**2)*self.c_1), 0],
[0, 0, 0, 1],
[0, (l_12*self.r_2)/(self.l_1*self.l_2-l_12**2), 0, -(self.l_1*self.r_2)/(self.l_1*self.l_2-l_12**2)]])
t0 = 0.0
T = 100 # Maximale SchweiĂzeit 15ms
N = 1000
h = T/float(N)
# Die Jacobimatrix muss nur einmal berechnet werden, deshalb liegt diese Berechnung auĂerhalb der Schleife
n = 4
a = 1.0/(2.0+math.sqrt(2.0))
I = np.identity(n)
A = I - a*h*jac
# Anfangswerte
z = np.zeros((4,N))
z[0,0] = self.c_1 * self.u_omega
z[1,0] = 0.0
z[2,0] = 0.0
z[3,0] = 0.0
t = np.zeros(N+1)
sol = np.zeros((4,N+1))
# t = 0
sol[0,0], sol[0,1], sol[0,2], sol[0,3] = prob.semiImpRK(A,z[0,0],z[1,0],z[2,0],z[3,0],0,h)
# t > 0
for i in range(1,N+1):
q1_i, p1_i, q2_i, p2_i = sol[0,i-1], sol[1,i-1], sol[2,i-1], sol[3,i-1]
sol[0,i], sol[1,i], sol[2,i], sol[3,i] = prob.semiImpRK(A,q1_i,p1_i,q2_i,p2_i,i,h)
t[i] = t[i-1] + h
# Plot-------------------------------------------------
fig1 = plt.figure(1)
fig1, (ax1, ax2, ax3, ax4) = plt.subplots(4, 1, sharex=True)
ax1.plot(t, sol[0,:])
ax1.set_ylabel('A*s')
ax1.set_title('Q_1')
ax1.grid(True)
ax2.plot(t, sol[1,:])
ax2.set_ylabel('A')
ax2.set_title('I_1')
ax2.grid(True)
ax3.plot(t, sol[2,:])
ax3.set_ylabel('A*s')
ax3.set_title('Q_2')
ax3.grid(True)
ax4.plot(t, sol[3,:])
ax4.set_ylabel('A')
ax4.set_xlabel('Time $t$ [s]')
ax4.set_title('I_2')
ax4.grid(True)
plt.show()
plt.savefig("Lösung_odeSol.png")
return sol
class pde(ode):
def solverIntern(self,a,v,dx,ds,leitfaehigkeit,area_gamma1,sol,f,u_h,bc2,i):
L = f*v*dx + (leitfaehigkeit*(1/area_gamma1)*(-sol[3,i]))*v*ds(4)
dolfin.solve(a == L, u_h, bc2)
return u_h
def achsenSetzen(self):
# Das Achsen-Objekt des Diagramms in einer Variablen ablegen:
ax = plt.gca()
# Die obere und rechte Achse unsichtbar machen:
ax.spines['right'].set_color('none')
ax.spines['top'].set_color('none')
# Die linke Diagrammachse auf den Bezugspunkt '0' der x-Achse legen:
ax.spines['left'].set_position(('data',0))
# Die untere Diagrammachse auf den Bezugspunkt '0' der y-Achse legen:
ax.spines['bottom'].set_position(('data',0))
# Ausrichtung der Achsen-Beschriftung festlegen:
ax.xaxis.set_ticks_position('bottom')
ax.yaxis.set_ticks_position('left')
return ax
def energyfunctional(self,phi,v,ds,leitfaehigkeit,area_gamma1,mesh,u_h,f,sol):
W = FunctionSpace(mesh, "DG", 0)
f = interpolate(Expression("x[0]+x[1]", degree=1), W)
alpha = Constant(1e-6)
J = assemble(0.5 * dolfin.dot(dolfin.grad(u_h), dolfin.grad(v))*dx - (leitfaehigkeit*(1/area_gamma1)*((-sol[3,1]))*v*ds(4)))
print("J = " + str(J))
control = Control(f)
rf = ReducedFunctional(J, control)
problem = MoolaOptimizationProblem(rf)
f_moola = moola.DolfinPrimalVector(f)
pdb.set_trace()
solver2 = moola.NewtonCG(problem, f_moola, options={'gtol': 1e-9,
'maxiter': 20,
'display': 3,
'ncg_hesstol': 0})
sol2 = solver2.dolfin_adjoint.solve()
# sol2 = solver2.solve()
f_opt = sol['control'].data
plot(f_opt, title="f_opt")
plt.savefig("f_opt.png")
# Define the expressions of the analytical solution
f_analytic = Expression("1/(1+alpha*4*pow(pi, 4))*w", w=w, alpha=alpha, degree=3)
u_analytic = Expression("1/(2*pow(pi, 2))*f", f=f_analytic, degree=3)
#We can then compute the errors between numerical and analytical solutions.
f.assign(f_opt)
solve(F == 0, u_h, bc2)
control_error = errornorm(f_analytic, f_opt)
state_error = errornorm(u_analytic, u_h)
print("h(min): %e." % mesh.hmin())
print("Error in state: %e." % state_error)
print("Error in control: %e." % control_error)
def __init__(self,l_1,l_2,k,r_2,c_1,u_omega):
super().__init__(l_1,l_2,k,r_2,c_1,u_omega)
def solver(self,f,degree,sol):
fig3 = plt.figure(3)
# Gebiet und Mesh erstellen------------------------------------------------
domain_vertices = [Point(2.25, 1.75),
Point(1.0, 3.0),
Point(-1.0, 1.0),
Point(4.0, -4.0),
Point(5.0, -3.0),
Point(2.0, 0.0),
Point(0.5, 0.0)]
domain = Polygon(domain_vertices)
mesh = generate_mesh(domain,20)
# Plot und Speicherung des nicht konvexen Gebiets---------------------------------
plt.plot([0.5, 2.25, 1.0, -1.0, 4.0, 5.0, 2.0, 0.5], [0.0, 1.75, 3.0, 1.0, -4.0, -3.0, 0.0, 0.0])
# Das Achsen-Objekt des Diagramms in einer Variablen ablegen:
ax = prob_pde.achsenSetzen()
plt.savefig("Domain.png")
# Plot und Speicherung der Triangulierung------------------------------------------
plt.figure(4)
p = plot(mesh, title = 'Finite Element Mesh')
ax = prob_pde.achsenSetzen()
plt.savefig("Mesh.png")
# Randbedingungen-----------------------------------------------------------
class Left(SubDomain):
def inside(self, x, on_boundary):
return on_boundary and (between(x[1], (-0.999, 0.999)) and between(x[0], (3.999, -3.999)))
class Right(SubDomain):
def inside(self, x, on_boundary):
return on_boundary and ((between(x[1], (2.25, 1.75)) and between(x[0], (1.001, 2.999))) and (between(x[1], (0.5, 0.0)) and between(x[0], (2.249, 1.749))) and (between(x[1], (1.999, 0.0)) and between(x[0], (0.501, 0.0))) and (between(x[1], (4.999, -2.999)) and between(x[0], (2.0, 0.0))))
class Bottom(SubDomain):
def inside(self, x, on_boundary):
return on_boundary and (between(x[1], (5.0, -3.0)) and between(x[0], (4.0, -4.0)))
class Top(SubDomain):
def inside(self, x, on_boundary):
return on_boundary and (between(x[1], (1.0, 3.0)) and between(x[0], (-1.0, 1.0)))
# Initialize sub-domain instances
left = Left()
top = Top()
right = Right()
bottom = Bottom()
# Initialize mesh function for boundary domains
boundaries = MeshFunction("size_t", mesh, mesh.topology().dim()-1, 0)
boundaries.set_all(4)
left.mark(boundaries, 1)
top.mark(boundaries, 2)
right.mark(boundaries, 3)
bottom.mark(boundaries, 4)
# Defining the function space for electric field
V_phi = FunctionSpace(mesh, "CG", degree)
#V_phi = VectorFunctionSpace(mesh, "Lagrange", degree)
# pdb.set_trace()
# Define Dirichlet boundary condition at top boundary
bc2 = DirichletBC(V_phi, 0.0, boundaries, 2)
#Take a look at the solution:
dx = Measure('dx', mesh)
ds=Measure('ds', domain=mesh, subdomain_data=boundaries)
area_gamma1 = dolfin.assemble(1*ds(4))
leitfaehigkeit = 1.43e-7
# Permeability (should be 6.3e-3)
mu = 1e-5
# Defining the trial function
phi = TrialFunction(V_phi)
# Defining the test function
v = TestFunction(V_phi)
u_h1 = Function(V_phi, name = "Displacement")
a = dot(grad(phi), grad(v))*dx
for i in range(0,10):
u_h = prob_pde.solverIntern(a,v,dx,ds,leitfaehigkeit,area_gamma1,sol,f,u_h1,bc2,i)
p = plot(u_h,title='Finite element solution at t_' + str(i))
ax = prob_pde.achsenSetzen()
plot(mesh)
cbar = plt.colorbar(p)
cbar.set_label('elektrisches Potential [V]', rotation=270)
#--------PLOT Gradienten
plot(-grad(u_h))
#------------------------
#plt.savefig('FiniteESol' + str(i)+ '.png')
plt.savefig("FiniteESol_gmres" + str(i)+ '.png')
plt.clf()
# Find the electric field by taking the negative of the
# gradient of the electric potential. Project this onto
# the function space for evaluation. (L_2 projection?)
elec_field = dolfin.project(-grad(u_h))
plt.figure(5)
p1 = plot(elec_field)
cbar = plt.colorbar(p1)
cbar.set_label('elektrisches Potential [V]', rotation=270)
plt.show()
plt.savefig('solution electric_field' + str(i) + '.png')
plt.clf()
prob_pde.energyfunctional(phi,v,ds,leitfaehigkeit,area_gamma1,mesh,u_h,f,sol)
def problem2(self, sol):
f = Constant(0.0)
u = prob_pde.solver(f,1,sol)
print("Test ENDE")
if __name__ == "__main__":
# Initialisierung einer Instanz der Klasse
prob = ode(l_1=5.0,
l_2=1000.0,
k=0.5,
r_2=20.0,
c_1=8.0,
u_omega=160)
prob_pde = pde(l_1=5.0,
l_2=1000.0,
k=0.5,
r_2=20.0,
c_1=8.0,
u_omega=160)
sol = prob.problem()
prob_pde.problem2(sol)
Maybe it isnât that bad if you can see everything.