In [2]:
def gradVec2(u_vec, x, y):
return sp.Matrix([[diff(u_vec[0], x), diff(u_vec[1],x)], [diff(u_vec[0], y), diff(u_vec[1], y)]])
def divTen2(tensor, x, y):
return sp.Matrix([diff(tensor[0,0], x) + diff(tensor[1,0], y), diff(tensor[0, 1], x) + diff(tensor[1,1], y)])
def divVec2(u_vec, x, y):
return diff(u_vec[0], x) + diff(u_vec[1], y)
FEProblemBase::reinitMaterials
only calls property computation for Material objects currently active on the given subdomain so that's good. However, it's possible that material objects "active" on the subdomain aren't actually being used in any computing objects like kernels, etc. So we would like to do some additional checking.
Alright, let's say we're computing the residual thread. Then assuming we cannot compute properties in a material in isolation, we would like to do the next best thing: only call computeQpProperties
for materials that have actually been asked to supply properties to kernels, dg_kernels, boundary_conditions, and interface_kernels.
So what am I doing as of commit d7dbfe5? I am determining the needed_mat_props
through ComputeResidualThread::subdomainChanged()
-> FEProblemBase::prepareMaterials
. In the latter method, we first ask all materials--if there are any materials active on the block--to update their material property dependencies and then we ask materials on the boundaries of the subdomain to also update their dependencies. Note that this could lead to a boundary material object getting asked to update their material property dependencies twice because we first pass to MaterialWarehouse::updateMatPropDependenceyHelper
all material objects as long as there is any one material object active in a block sense on the subdomain, and then we pass active material boundary objects. But this overlap doesn't matter so much because our needed_mat_props
is a set, so if we try to insert the same material properties multiple times, it will silently and correctly fail. Note, however, that this could also pass needed_mat_props
from material objects not on the current block, so that needs to be changed.
So what happens in MaterialWarehouse::updateMatPropDependencyHelper
? We add mp_deps
from MaterialPropertyInterface::getMatPropDependencies
. However, it should be noted that this is only done for material objects. Is this fine? Well let's figure it out. It returns _material_property_dependencies
which is a set added to by calling addMatPropDependency
. Now this gets called when the object that inherits from MaterialPropertyInterface
calls its own getMaterialProperty
method. So I hypothesize that in my simple test, if I ask to have a material property in my kernel object with getMaterialProperty
that will not register in any material objects list of _material_property_dependencies
and consequently computeQpProperties
will never get called. I will test that the next time I sit down at my comp.
Three tests:
computeQpProperties
does not get called. Expected to Pass. With devel MOOSE: expected to Fail (expected change)computeQpProperties
does not get called for the material not supplying properties while the other one does. Expected behavior: both materials compute methods get called. Fail. With devel MOOSE: expected to Fail (expected to not change)computeQpProperties
should get called through the residual and jacobian threads but not through the aux kernel thread. Expected to Pass. With devel MOOSEE: expected to Fail (expected change)Calls to computeProperties:
Number of calls: 8
Failed tests:
Failed but now passing:
Ok my new test is failing with threads and I don't really know why. It seems like the number of calls to computing threads should be the same...
Calls to computeProperties:
Yep so thread computing pattern is the exact same. How about whether the material is the same location in memory every time?
In [2]:
import sympy as sp
sxx, sxy, syx, syy, nx, ny = sp.var('sxx sxy syx syy nx ny')
In [5]:
s = sp.Matrix([[sxx, sxy],[syx, syy]])
n = sp.Matrix([nx, ny])
In [6]:
s*n
Out[6]:
In [14]:
prod = n.transpose()*s*n
prod2 = n.transpose()*(s*n)
In [15]:
print(prod)
print(prod2)
print(prod==prod2)
In [13]:
prod.shape
Out[13]:
In [18]:
sp.expand(prod) == sp.expand(prod2)
Out[18]:
In [20]:
lhs = n.transpose()*s
print(lhs.shape)
In [21]:
rhs = (n.transpose() * s * n) * n.transpose()
print(rhs.shape)
In [62]:
rhs2 = (n.transpose()*s) * (n*n.transpose())
print(rhs2)
rhs3 = n.transpose() * (s*n*n.transpose())
print(sp.expand(rhs) == sp.expand(rhs2) == sp.expand(rhs3))
In [58]:
print(n*n.transpose())
In [59]:
print(n.transpose()*n)
In [48]:
print(sp.simplify(lhs))
print(sp.simplify(rhs))
In [27]:
elml = lhs[0,0]
elmr = rhs[0,0]
In [29]:
print(elml.expand())
print(elmr.expand())
In [43]:
elmr.expand()
Out[43]:
In [42]:
elmr.expand().subs(nx, sp.sqrt(1 - ny**2))
Out[42]:
In [44]:
elmr.expand().subs(nx, sp.sqrt(1 - ny**2)).simplify()
Out[44]:
In [36]:
help(expr.replace)
In [49]:
t = lhs - rhs
print(t)
In [51]:
t1 = t[0,0]
t2 = t[0,1]
In [52]:
print(t1)
print(t2)
In [53]:
t1.simplify()
Out[53]:
In [63]:
ddx, ddy, ux, uy = sp.var('ddx ddy ux uy')
grad = sp.Matrix([ddx,ddy])
u = sp.Matrix([ux,uy])
print(grad.shape)
phij,mu = sp.var('phij mu')
uDuxj = sp.Matrix([phij,0])
uDuyj = sp.Matrix([0,phij])
In [65]:
grad*u.transpose()
Out[65]:
In [78]:
jacx = n.transpose() * (mu * (grad*uDuxj.transpose() + (grad*uDuxj.transpose()).transpose())) * n
print(jacx)
In [79]:
sp.expand(jacx[0,0])*nx
Out[79]:
In [81]:
jacy = n.transpose() * (mu * (grad*uDuyj.transpose() + (grad*uDuyj.transpose()).transpose())) * n
print(jacy)
In [82]:
sp.expand(jacy[0,0])*ny
Out[82]:
In [83]:
sp.factor(jacy[0,0])
Out[83]:
In [87]:
print(sp.factor((jacx[0,0]*n.transpose())[0,0]))
print(sp.factor((jacy[0,0]*n.transpose())[0,1]))
In [88]:
sJacX = mu * (grad*uDuxj.transpose() + (grad*uDuxj.transpose()).transpose())
sJacY = mu * (grad*uDuyj.transpose() + (grad*uDuyj.transpose()).transpose())
print(sJacX)
print(sJacY)
In [90]:
print(sp.factor((n.transpose()*sJacX)[0,0]))
print(sp.factor((n.transpose()*sJacY)[0,1]))
In [85]:
jacx.shape
Out[85]:
Note that the total stress tensor ($\hat{\sigma}$) is equal to the sum of the deviatoric stress tensor ($\hat{\tau}$) and the stress induced by pressure ($-p\hat{I}$), e.g.
\begin{equation} \hat{\sigma} = \hat{\tau} - p\hat{I} \end{equation}
In [5]:
import sympy as sp
sxx, sxy, syx, syy, nx, ny, mu = sp.var('sxx sxy syx syy nx ny mu')
ddx, ddy, ux, uy = sp.var('ddx ddy ux uy')
grad = sp.Matrix([ddx,ddy])
u = sp.Matrix([ux,uy])
phij,mu = sp.var('phij mu')
uDuxj = sp.Matrix([phij,0])
uDuyj = sp.Matrix([0,phij])
rateOfStrain = (grad*u.transpose() + (grad*u.transpose()).transpose()) * 1 / 2
d_rateOfStrain_d_uxj = (grad*uDuxj.transpose() + (grad*uDuxj.transpose()).transpose()) * 1 / 2
d_rateOfStrain_d_uyj = (grad*uDuyj.transpose() + (grad*uDuyj.transpose()).transpose()) * 1 / 2
print(rateOfStrain)
print(d_rateOfStrain_d_uxj)
print(d_rateOfStrain_d_uyj)
In [7]:
tau = rateOfStrain * 2 * mu
d_tau_d_uxj = d_rateOfStrain_d_uxj * 2 * mu
d_tau_d_uyj = d_rateOfStrain_d_uyj * 2 * mu
print(tau)
print(d_tau_d_uxj)
print(d_tau_d_uyj)
In [10]:
normals = sp.Matrix([nx,ny])
y_component_normal = sp.Matrix([0,ny])
x_component_normal = sp.Matrix([nx,0])
test = sp.var('test')
test_x = sp.Matrix([test,0])
test_y = sp.Matrix([0,test])
In [12]:
normals.transpose() * d_tau_d_uxj * test_y
Out[12]:
In [14]:
sp.factor(normals.transpose() * d_tau_d_uxj * normals * normals.transpose() * test_y)
Out[14]:
In [3]:
import sympy as sp
nx, ny, nz, mu, phij, ddx, ddy, ddz, ux, uy, uz = sp.var('nx ny nz mu phij ddx ddy ddz ux uy uz')
grad = sp.Matrix([ddx,ddy,ddz])
u = sp.Matrix([ux, uy, uz])
uDuxj = sp.Matrix([phij,0,0])
uDuyj = sp.Matrix([0,phij,0])
uDuzj = sp.Matrix([0,0,phij])
rateOfStrain = (grad*u.transpose() + (grad*u.transpose()).transpose()) * 1 / 2
d_rateOfStrain_d_uxj = (grad*uDuxj.transpose() + (grad*uDuxj.transpose()).transpose()) * 1 / 2
d_rateOfStrain_d_uyj = (grad*uDuyj.transpose() + (grad*uDuyj.transpose()).transpose()) * 1 / 2
d_rateOfStrain_d_uzj = (grad*uDuzj.transpose() + (grad*uDuzj.transpose()).transpose()) * 1 / 2
print(rateOfStrain)
print(d_rateOfStrain_d_uxj)
print(d_rateOfStrain_d_uyj)
print(d_rateOfStrain_d_uzj)
In [4]:
tau = rateOfStrain * 2 * mu
d_tau_d_uxj = d_rateOfStrain_d_uxj * 2 * mu
d_tau_d_uyj = d_rateOfStrain_d_uyj * 2 * mu
d_tau_d_uzj = d_rateOfStrain_d_uzj * 2 * mu
print(tau)
print(d_tau_d_uxj)
print(d_tau_d_uyj)
print(d_tau_d_uzj)
In [5]:
normals = sp.Matrix([nx,ny,nz])
test = sp.var('test')
test_x = sp.Matrix([test,0,0])
test_y = sp.Matrix([0,test,0])
test_z = sp.Matrix([0,0,test])
In [21]:
sp.factor(normals.transpose() * d_tau_d_uxj * normals * normals.transpose() * test_y)
Out[21]:
In [22]:
sp.factor(normals.transpose() * d_tau_d_uxj * normals * normals.transpose() * test_z)
Out[22]:
In [23]:
sp.factor(normals.transpose() * d_tau_d_uyj * normals * normals.transpose() * test_x)
Out[23]:
In [7]:
(normals.transpose() * tau)[0]
Out[7]:
In [9]:
sp.factor(_)
Out[9]:
In [30]:
from scipy.special import erf
from numpy import exp, sqrt, pi
import numpy as np
def u(x, y, u1, u2, sigma):
return (u1 + u2) / 2. - (u1 - u2) / 2. * erf(sigma * y / x)
def v(x, y, u1, u2, sigma):
return (u1 - u2) / (2. * sigma * sqrt(pi)) * exp(-(sigma * y / x)**2)
def p():
return 0
def k(x, y, k0, sigma):
return k0 * exp(-(sigma * y / x)**2)
def epsilon(x, y, epsilon0, sigma):
return epsilon0 / x * exp(-(sigma * y / x)**2)
def muT(x, y, muT0, sigma):
return muT0 * x * exp(-(sigma * y / x)**2)
def k0(u1, u2, sigma):
return 343. / 75000. * u1 * (u1 - u2) * sigma / sqrt(pi)
def epsilon0(u1, u2, sigma, Cmu):
return 343. / 22500. * Cmu * u1 * (u1 - u2)**2 * sigma**2 / pi
def muT0(u1, rho):
return 343. / 250000. * rho * u1
def Re(rho, u1, L, mu):
return rho * u1 * L / mu
u1 = 1
u2 = 0
sigma = 13.5
Cmu = 0.9
x = np.arange(10, 100.5, .5)
y = np.arange(-30, 30.5, .5)
x,y = np.meshgrid(x, y)
uplot = u(x, y, u1, u2, sigma)
vplot = v(x, y, u1, u2, sigma)
kplot = k(x, y, k0(u1, u2, sigma), sigma)
epsPlot = epsilon(x, y, epsilon0(u1, u2, sigma, Cmu), sigma)
muTplot = muT(x, y, muT0(u1, 1), sigma)
In [25]:
import matplotlib.pyplot as plt
plt.pcolor(x, y, uplot)
plt.colorbar()
plt.show()
In [27]:
plt.pcolor(x, y, vplot)
plt.colorbar()
plt.show()
In [28]:
plt.pcolor(x, y, kplot)
plt.colorbar()
plt.show()
In [29]:
plt.pcolor(x, y, epsPlot)
plt.colorbar()
plt.show()
In [31]:
plt.pcolor(x, y, muTplot)
plt.colorbar()
plt.show()
In [1]:
import sympy as sp
from sympy import diff
x, y, sigma, Cmu, rho, mu, k0, eps0 = sp.var('x y sigma Cmu rho mu k0 eps0')
In [2]:
def gradVec2(u_vec, x, y):
return sp.Matrix([[diff(u_vec[0], x), diff(u_vec[1],x)], [diff(u_vec[0], y), diff(u_vec[1], y)]])
def divTen2(tensor, x, y):
return sp.Matrix([diff(tensor[0,0], x) + diff(tensor[1,0], y), diff(tensor[0, 1], x) + diff(tensor[1,1], y)])
def divVec2(u_vec, x, y):
return diff(u_vec[0], x) + diff(u_vec[1], y)
In [4]:
u = (1 - sp.erf(sigma * y / x)) / 2
v = sp.exp(-(sigma * y / x)**2) / 2 / sigma / sp.sqrt(sp.pi)
k = k0 * sp.exp(-(sigma * y / x)**2)
eps = eps0 / x * sp.exp(-(sigma * y / x)**2)
muT = rho * Cmu * k**2 / eps
u_vec = sp.Matrix([u, v])
grad_u_vec = gradVec2(u_vec, x, y)
visc_term = divTen2((mu + muT) * (grad_u_vec + grad_u_vec.transpose()), x, y)
In [5]:
print(sp.simplify(divVec2(u_vec, x, y)))
In [6]:
visc_term
Out[6]:
In [61]:
visc_term.shape
Out[61]:
In [7]:
momentum_equations = rho * u_vec.transpose() * grad_u_vec - visc_term.transpose()
In [12]:
u_eq = momentum_equations[0]
v_eq = momentum_equations[1]
In [16]:
sp.simplify(v_eq)
Out[16]:
In [13]:
sp.simplify(u_eq)
Out[13]:
In [14]:
sp.collect(u_eq, x)
Out[14]:
In [10]:
u_eq = u_eq.subs(k0, sigma / sp.sqrt(sp.pi) * 343 / 75000)
print(u_eq)
u_eq = u_eq.subs(eps0, Cmu * sigma**2 / sp.pi * 343 / 22500)
print(u_eq)
In [11]:
sp.simplify(u_eq)
Out[11]:
In [52]:
grad_u_vec = sp.Matrix([[diff(u, x), diff(v, x)], [diff(u, y), diff(v, y)]])
In [57]:
grad_u_vec
Out[57]:
In [40]:
clear(pi)
In [49]:
from sympy.physics.vector import ReferenceFrame
R = ReferenceFrame('R')
u = (1 - sp.erf(sigma * R[1] / R[0])) / 2
v = sp.exp(sigma * R[1] / R[0]) / 2 / sigma / sp.sqrt(pi)
k = k0 * sp.exp(-(sigma * R[1] / R[0])**2)
eps = eps0 / R[0] * sp.exp(-(sigma * R[1] / R[0])**2)
muT = rho * Cmu * k**2 / eps
In [50]:
u_vec[0]
Out[50]:
In [ ]:
grad_u_vec = gradVec2(u_vec)
In [18]:
from scipy.special import erf
erf(2)
Out[18]:
In [19]:
erf(-1)
Out[19]:
In [20]:
erf(.99)
Out[20]:
In [47]:
from numpy import pi, sqrt, exp
def d_erf(x):
return 2. / sqrt(pi) * exp(-x**2)
def d_half_erf(x):
return 2. / sqrt(pi) * exp(-(0.5*x)**2) * 0.5
In [48]:
d_half_erf(-2)
Out[48]:
In [22]:
d_erf(-1)
Out[22]:
In [23]:
print(pi)
In [24]:
d_erf(0)
Out[24]:
In [25]:
d_erf(1)
Out[25]:
In [27]:
import numpy as np
In [28]:
libmesh = np.loadtxt("/home/lindsayad/projects/moose/libmesh/contrib/fparser/examples/first_orig.dat")
In [30]:
libmesh.shape
Out[30]:
In [42]:
xl = libmesh[:,0]
ypl = libmesh[:,1]
In [45]:
xt = np.arange(-1,1,.01)
yt = d_erf(xt)
In [33]:
import matplotlib.pyplot as plt
In [43]:
plt.close()
plt.plot(xl, ypl, label="libmesh")
plt.plot(xt, yt, label='true')
plt.legend()
plt.show()
In [46]:
plt.close()
plt.plot(xl, yt / ypl)
plt.show()
Ok, the analytic_turbulence problem sucks. Even if I start with Dirichlet boundary conditions on all boundaries and initial conditions representing the supposed analytic solution, and then run a transient simulation, the solution evolves away from the supposed analytic solution. backwards_step_adaptive.i
runs to completion, but that's for a relatively low inlet velocity.
Getting some pretty good results now also with backwards_step_adaptive_inlet_v_100.i
which I wasn't a few days before. This could perhaps be due to the introduction of the SUPG terms. Convergence becomes a little slow at longer time steps, perhaps because of incomplete Jacobian implementation? Or poor relative scaling of the variables? Results for kin
actually don't look too far off from the results in the Kuzmin paper. This simulation uses a Reynolds number of 100, which is still pretty small! Next effort will be with the Reynolds number in the Kuzmin paper of 47,625.
It's something I've observed over the years that decreasing element size can lead to decreasing solver convergence. Note that I'm not talking about convergence to the true solution. I wish I could find a good piece of literature discussing this phenomenon. There are just so many things to consider about a finite element solve; it can be fun at times and frustrating at others.
In [1]:
from sympy import *
In [8]:
x, y, L = var('x y L')
In [10]:
from random import randint, random, uniform
for i in range(30):
print('%.2f' % uniform(.1, .99))
In [64]:
from random import randint, random, uniform
def sym_func(x, y, L):
return round(uniform(.1, .99),1) + round(uniform(.1, .99),1) * sin(round(uniform(.1, .99),1) * pi * x / L) \
+ round(uniform(.1, .99),1) * sin(round(uniform(.1, .99),1) * pi * y / L) \
+ round(uniform(.1, .99),1) * sin(round(uniform(.1, .99),1) * pi * x * y / L)
In [65]:
u = sym_func(x, y, 1)
v = sym_func(x, y, 1)
p = sym_func(x, y, 1)
k = sym_func(x, y, 1)
eps = sym_func(x, y, 1)
print(u, v, p, k, eps, sep="\n")
In [113]:
import sympy as sp
def gradVec2(u_vec, x, y):
return sp.Matrix([[diff(u_vec[0], x), diff(u_vec[1],x)], [diff(u_vec[0], y), diff(u_vec[1], y)]])
def divTen2(tensor, x, y):
return sp.Matrix([diff(tensor[0,0], x) + diff(tensor[1,0], y), diff(tensor[0, 1], x) + diff(tensor[1,1], y)])
def divVec2(u_vec, x, y):
return diff(u_vec[0], x) + diff(u_vec[1], y)
def gradScalar2(u, x, y):
return sp.Matrix([diff(u, x), diff(u,y)])
def strain_rate(u_vec, x, y):
return gradVec2(u_vec, x, y) + gradVec2(u_vec, x, y).transpose()
def strain_rate_squared_2(u_vec, x, y):
tensor = gradVec2(u_vec, x, y) + gradVec2(u_vec, x, y).transpose()
rv = 0
for i in range(2):
for j in range(2):
rv += tensor[i, j] * tensor[i, j]
return rv
def laplace2(u, x, y):
return diff(diff(u, x), x) + diff(diff(u, y), y)
In [94]:
pnew = Integer(0)
type(pnew)
Out[94]:
In [104]:
cmu = 0.09
uvec = sp.Matrix([u, v])
mu, rho = var('mu rho')
visc_term = (-mu * divTen2(gradVec2(uvec, x, y) + gradVec2(uvec, x, y).transpose(), x, y)).transpose()
conv_term = rho * uvec.transpose() * gradVec2(uvec, x, y)
pressure_term = gradScalar2(p, x, y).transpose()
turbulent_visc_term = -(divTen2(rho * cmu * k**2 / eps * (gradVec2(uvec, x, y) + gradVec2(uvec, x, y).transpose()), x, y)).transpose()
# print(visc_term.shape, conv_term.shape, pressure_term.shape, sep="\n")
source = conv_term + visc_term + pressure_term + turbulent_visc_term
print(source[0])
print(source[1])
In [105]:
cmu = 0.09
uvec = sp.Matrix([u, v])
mu, rho = var('mu rho')
visc_term = (-mu * divTen2(gradVec2(uvec, x, y), x, y)).transpose()
conv_term = rho * uvec.transpose() * gradVec2(uvec, x, y)
pressure_term = gradScalar2(p, x, y).transpose()
turbulent_visc_term = -(divTen2(rho * cmu * k**2 / eps * (gradVec2(uvec, x, y)), x, y)).transpose()
# print(visc_term.shape, conv_term.shape, pressure_term.shape, sep="\n")
source = conv_term + visc_term + pressure_term + turbulent_visc_term
print(source[0])
print(source[1])
In [73]:
-divVec2(uvec, x, y)
Out[73]:
In [96]:
diff_term = -laplace2(p, x, y)
print(diff_term)
In [99]:
cmu = 0.09
sigk = 1.
sigeps = 1.3
c1eps = 1.44
c2eps = 1.92
conv_term = rho * uvec.transpose() * gradScalar2(k, x, y)
diff_term = - divVec2((mu + rho * cmu * k**2 / eps / sigk) * gradScalar2(k, x, y), x, y)
creation_term = - rho * cmu * k**2 / eps / 2 * strain_rate_squared_2(uvec, x, y)
destruction_term = rho * eps
terms = [conv_term[0,0], diff_term, creation_term, destruction_term]
L = 0
for term in terms:
L += term
print(L)
In [100]:
cmu = 0.09
sigk = 1.
sigeps = 1.3
c1eps = 1.44
c2eps = 1.92
conv_term = rho * uvec.transpose() * gradScalar2(eps, x, y)
diff_term = - divVec2((mu + rho * cmu * k**2 / eps / sigeps) * gradScalar2(eps, x, y), x, y)
creation_term = - rho * c1eps * cmu * k / 2 * strain_rate_squared_2(uvec, x, y)
destruction_term = rho * c2eps * eps**2 / k
terms = [conv_term[0,0], diff_term, creation_term, destruction_term]
L = 0
for term in terms:
L += term
print(L)
In [93]:
diff_term = -laplace2(u, x, y)
print(diff_term)
In [69]:
def z(func, xh, yh):
u = np.zeros(xh.shape)
for i in range(0,xh.shape[0]):
for j in range(0,xh.shape[1]):
u[i][j] = func.subs({x:xh[i][j], y:yh[i][j]}).evalf()
# print(func.subs({x:xh[i][j], y:yh[i][j]}).evalf())
return u
xnum = np.arange(0, 1.01, .05)
ynum = np.arange(0, 1.01, .05)
xgrid, ygrid = np.meshgrid(xnum, ynum)
uh = z(u, xgrid, ygrid)
vh = z(v, xgrid, ygrid)
ph = z(p, xgrid, ygrid)
kh = z(k, xgrid, ygrid)
epsh = z(eps, xgrid, ygrid)
In [72]:
import matplotlib.pyplot as plt
plot_funcs = [uh, vh, ph, kh, epsh]
for func in plot_funcs:
plt.pcolor(xgrid, ygrid, func, cmap='coolwarm')
cbar = plt.colorbar()
plt.show()
In [112]:
f, g = symbols('f g', cls=Function)
f(x,y).diff(x)
Out[112]:
In [123]:
vx, vy = symbols('v_x v_y', cls=Function)
mu, x, y = var('mu x y')
nx, ny = var('n_x n_y')
n = sp.Matrix([nx, ny])
v_vec = sp.Matrix([vx(x, y), vy(x, y)])
sigma = strain_rate(v_vec, x, y)
tw = n.transpose() * sigma - n.transpose() * sigma * n * n.transpose()
tw[0]
Out[123]:
In [124]:
tw[1]
Out[124]:
In [129]:
vx, vy = symbols('v_x v_y', cls=Function)
mu, x, y = var('mu x y')
nx, ny = var('n_x n_y')
n = sp.Matrix([Integer(0), Integer(1)])
v_vec = sp.Matrix([vx(x, y), 0])
sigma = strain_rate(v_vec, x, y)
tw = n.transpose() * sigma - n.transpose() * sigma * n * n.transpose()
tw[0]
Out[129]:
In [130]:
u
Out[130]:
In [113]:
import sympy as sp
def gradVec2(u_vec, x, y):
return sp.Matrix([[diff(u_vec[0], x), diff(u_vec[1],x)], [diff(u_vec[0], y), diff(u_vec[1], y)]])
def divTen2(tensor, x, y):
return sp.Matrix([diff(tensor[0,0], x) + diff(tensor[1,0], y), diff(tensor[0, 1], x) + diff(tensor[1,1], y)])
def divVec2(u_vec, x, y):
return diff(u_vec[0], x) + diff(u_vec[1], y)
def gradScalar2(u, x, y):
return sp.Matrix([diff(u, x), diff(u,y)])
def strain_rate(u_vec, x, y):
return gradVec2(u_vec, x, y) + gradVec2(u_vec, x, y).transpose()
def strain_rate_squared_2(u_vec, x, y):
tensor = gradVec2(u_vec, x, y) + gradVec2(u_vec, x, y).transpose()
rv = 0
for i in range(2):
for j in range(2):
rv += tensor[i, j] * tensor[i, j]
return rv
def laplace2(u, x, y):
return diff(diff(u, x), x) + diff(diff(u, y), y)
In [210]:
def L_momentum_traction(uvec, k, eps, x, y):
cmu = 0.09
mu, rho = sp.var('mu rho')
visc_term = (-mu * divTen2(gradVec2(uvec, x, y) + gradVec2(uvec, x, y).transpose(), x, y)).transpose()
conv_term = rho * uvec.transpose() * gradVec2(uvec, x, y)
pressure_term = gradScalar2(p, x, y).transpose()
turbulent_visc_term = -(divTen2(rho * cmu * k**2 / eps * (gradVec2(uvec, x, y) + gradVec2(uvec, x, y).transpose()), x, y)).transpose()
# print(visc_term.shape, conv_term.shape, pressure_term.shape, sep="\n")
source = conv_term + visc_term + pressure_term + turbulent_visc_term
return source
def bc_terms_momentum_traction(uvec, nvec, k, eps, x, y):
cmu = 0.09
mu, rho = sp.var('mu rho')
visc_term = (-mu * nvec.transpose() * (gradVec2(uvec, x, y) + gradVec2(uvec, x, y).transpose(), x, y)).transpose()
turbulent_visc_term = -(nvec.transpose() * (rho * cmu * k**2 / eps * (gradVec2(uvec, x, y) + gradVec2(uvec, x, y).transpose()), x, y)).transpose()
return visc_term + turbulent_visc_term
def L_momentum_laplace(uvec, k, eps, x, y):
cmu = 0.09
mu, rho = var('mu rho')
visc_term = (-mu * divTen2(gradVec2(uvec, x, y), x, y)).transpose()
conv_term = rho * uvec.transpose() * gradVec2(uvec, x, y)
pressure_term = gradScalar2(p, x, y).transpose()
turbulent_visc_term = -(divTen2(rho * cmu * k**2 / eps * (gradVec2(uvec, x, y)), x, y)).transpose()
# print(visc_term.shape, conv_term.shape, pressure_term.shape, sep="\n")
source = conv_term + visc_term + pressure_term + turbulent_visc_term
return source
def L_pressure(uvec, x, y):
return -divVec2(uvec, x, y)
def L_kin(uvec, k, eps, x, y):
cmu = 0.09
sigk = 1.
sigeps = 1.3
c1eps = 1.44
c2eps = 1.92
conv_term = rho * uvec.transpose() * gradScalar2(k, x, y)
diff_term = - divVec2((mu + rho * cmu * k**2 / eps / sigk) * gradScalar2(k, x, y), x, y)
creation_term = - rho * cmu * k**2 / eps / 2 * strain_rate_squared_2(uvec, x, y)
destruction_term = rho * eps
terms = [conv_term[0,0], diff_term, creation_term, destruction_term]
L = 0
for term in terms:
L += term
return L
def L_eps(uvec, k, eps, x, y):
cmu = 0.09
sigk = 1.
sigeps = 1.3
c1eps = 1.44
c2eps = 1.92
conv_term = rho * uvec.transpose() * gradScalar2(eps, x, y)
diff_term = - divVec2((mu + rho * cmu * k**2 / eps / sigeps) * gradScalar2(eps, x, y), x, y)
creation_term = - rho * c1eps * cmu * k / 2 * strain_rate_squared_2(uvec, x, y)
destruction_term = rho * c2eps * eps**2 / k
terms = [conv_term[0,0], diff_term, creation_term, destruction_term]
L = 0
for term in terms:
L += term
return L
In [159]:
def prep_moose_input(sym_expr):
rep1 = re.sub(r'\*\*',r'^',str(sym_expr))
rep2 = re.sub(r'mu',r'${mu}',rep1)
rep3 = re.sub(r'rho',r'${rho}',rep2)
return rep3
def write_all_functions():
target = open('/home/lindsayad/python/mms_input.txt','w')
target.write("[Functions]" + "\n")
target.write(" [./u_source_func]" + "\n")
target.write(" type = ParsedFunction" + "\n")
target.write(" value = '" + prep_moose_input(L_momentum_traction(uVecNew, kinNew, epsilonNew, x, y)[0]) + "'" + "\n")
target.write(" [../]" + "\n")
target.write(" [./v_source_func]" + "\n")
target.write(" type = ParsedFunction" + "\n")
target.write(" value = '" + prep_moose_input(L_momentum_traction(uVecNew, kinNew, epsilonNew, x, y)[1]) + "'" + "\n")
target.write(" [../]" + "\n")
target.write(" [./p_source_func]" + "\n")
target.write(" type = ParsedFunction" + "\n")
target.write(" value = '" + prep_moose_input(L_pressure(uVecNew, x, y)) + "'" + "\n")
target.write(" [../]" + "\n")
target.write(" [./kin_source_func]" + "\n")
target.write(" type = ParsedFunction" + "\n")
target.write(" value = '" + prep_moose_input(L_kin(uVecNew, kinNew, epsilonNew, x, y)) + "'" + "\n")
target.write(" [../]" + "\n")
target.write(" [./epsilon_source_func]" + "\n")
target.write(" type = ParsedFunction" + "\n")
target.write(" value = '" + prep_moose_input(L_eps(uVecNew, kinNew, epsilonNew, x, y)) + "'" + "\n")
target.write(" [../]" + "\n")
target.write(" [./u_func]" + "\n")
target.write(" type = ParsedFunction" + "\n")
target.write(" value = '" + str(uNew) + "'" + "\n")
target.write(" [../]" + "\n")
target.write(" [./v_func]" + "\n")
target.write(" type = ParsedFunction" + "\n")
target.write(" value = '" + str(vNew) + "'" + "\n")
target.write(" [../]" + "\n")
target.write(" [./p_func]" + "\n")
target.write(" type = ParsedFunction" + "\n")
target.write(" value = '" + str(pNew) + "'" + "\n")
target.write(" [../]" + "\n")
target.write(" [./kin_func]" + "\n")
target.write(" type = ParsedFunction" + "\n")
target.write(" value = '" + str(kinNew) + "'" + "\n")
target.write(" [../]" + "\n")
target.write(" [./epsilon_func]" + "\n")
target.write(" type = ParsedFunction" + "\n")
target.write(" value = '" + str(epsilonNew) + "'" + "\n")
target.write(" [../]" + "\n")
target.write("[]" + "\n")
target.close()
def write_reduced_functions():
target = open('/home/lindsayad/python/mms_input.txt','w')
target.write("[Functions]" + "\n")
target.write(" [./u_source_func]" + "\n")
target.write(" type = ParsedFunction" + "\n")
target.write(" value = '" + prep_moose_input(L_momentum_traction(uVecNew, kinNew, epsilonNew, x, y)[0]) + "'" + "\n")
target.write(" [../]" + "\n")
target.write(" [./kin_source_func]" + "\n")
target.write(" type = ParsedFunction" + "\n")
target.write(" value = '" + prep_moose_input(L_kin(uVecNew, kinNew, epsilonNew, x, y)) + "'" + "\n")
target.write(" [../]" + "\n")
target.write(" [./epsilon_source_func]" + "\n")
target.write(" type = ParsedFunction" + "\n")
target.write(" value = '" + prep_moose_input(L_eps(uVecNew, kinNew, epsilonNew, x, y)) + "'" + "\n")
target.write(" [../]" + "\n")
target.write(" [./u_func]" + "\n")
target.write(" type = ParsedFunction" + "\n")
target.write(" value = '" + str(uNew) + "'" + "\n")
target.write(" [../]" + "\n")
target.write(" [./kin_func]" + "\n")
target.write(" type = ParsedFunction" + "\n")
target.write(" value = '" + str(kinNew) + "'" + "\n")
target.write(" [../]" + "\n")
target.write(" [./epsilon_func]" + "\n")
target.write(" type = ParsedFunction" + "\n")
target.write(" value = '" + str(epsilonNew) + "'" + "\n")
target.write(" [../]" + "\n")
target.write("[]" + "\n")
target.close()
In [205]:
yStarPlus = 11.06
# uNew = yStarPlus**2 / y + u * (y - 1.) * 200
# uNew = u * (y - 1.) * 200
# vNew = Integer(0)
# vNew = v * (y - 1.5) * 200
# pNew = Integer(0)
# # Converges
# uNew = u
# vNew = v
# pNew = p
# kinNew = k
# epsilonNew = eps
# # Does not converge
# uNew = u * 200
# vNew = v * 200
# pNew = p * 200
# kinNew = k * 200
# epsilonNew = eps * 200
# # Converges
# uNew = u * (y - 1.)
# vNew = v
# pNew = p
# kinNew = k
# epsilonNew = eps
# # Converges
# uNew = u * (y - 1.) + 1. / y
# vNew = v
# pNew = p
# kinNew = k
# epsilonNew = eps
# # Does not converge
# uNew = u * (y - 1.) + yStarPlus**2 / y
# vNew = v
# pNew = p
# kinNew = k
# epsilonNew = eps
# # Converges
# uNew = u * (y - 1.) + 1.1 / y
# vNew = 0
# pNew = 0
# kinNew = k
# epsilonNew = eps
# Want to test natural boundary condition
uNew = 0.5 + sin(pi * x / 2) + sin(pi * y / 2)
vNew = 0
pNew = 0
kinNew = k
epsilonNew = eps
uVecNew = sp.Matrix([uNew, vNew])
write_reduced_functions()
In [169]:
print(u)
print(v)
print(p)
print(k)
print(eps)
Ok, so apparently just scaling every variable's manufactured solution by 200 causes MOOSE convergence issues. Sigh
In [ ]:
vx, vy = symbols('v_x v_y', cls=Function)
mu, x, y = var('mu x y')
nx, ny = var('n_x n_y')
n = sp.Matrix([Integer(0), Integer(1)])
v_vec = sp.Matrix([vx(x, y), 0])
kinFunc, epsFunc = symbols('kinFunc epsFunc', cls=Function)
In [225]:
blah = bc_terms_momentum_traction(uVecNew, n, kinNew, epsilonNew, x, y)
In [218]:
type(blah)
Out[218]:
In [226]:
blah[0]
Out[226]:
In [207]:
sigma = mu * strain_rate(v_vec, x, y)
tw = n.transpose() * sigma - n.transpose() * sigma * n * n.transpose()
tw[0]
Out[207]:
In [204]:
(n.transpose() * sigma)[0]
Out[204]:
In [221]:
cmu = 0.09
mu, rho = sp.var('mu rho')
visc_term = (-mu * n.transpose() * (gradVec2(v_vec, x, y) + gradVec2(v_vec, x, y).transpose(), x, y)).transpose()
turbulent_visc_term = -(n.transpose() * (rho * cmu * k**2 / eps * (gradVec2(v_vec, x, y) + gradVec2(v_vec, x, y).transpose()), x, y)).transpose()
In [222]:
visc_term
Out[222]:
In [223]:
print(visc_term)
In [ ]:
yStarPlus = 11.06
# uNew = yStarPlus**2 / y + u * (y - 1.) * 200
# uNew = u * (y - 1.) * 200
# vNew = Integer(0)
# vNew = v * (y - 1.5) * 200
# pNew = Integer(0)
# # Converges
# uNew = u
# vNew = v
# pNew = p
# kinNew = k
# epsilonNew = eps
# # Does not converge
# uNew = u * 200
# vNew = v * 200
# pNew = p * 200
# kinNew = k * 200
# epsilonNew = eps * 200
# # Converges
# uNew = u * (y - 1.)
# vNew = v
# pNew = p
# kinNew = k
# epsilonNew = eps
# # Converges
# uNew = u * (y - 1.) + 1. / y
# vNew = v
# pNew = p
# kinNew = k
# epsilonNew = eps
# # Does not converge
# uNew = u * (y - 1.) + yStarPlus**2 / y
# vNew = v
# pNew = p
# kinNew = k
# epsilonNew = eps
# # Converges
# uNew = u * (y - 1.) + 1.1 / y
# vNew = 0
# pNew = 0
# kinNew = k
# epsilonNew = eps
In [1]:
from moose_calc_routines import *
from sympy import *
init_printing()
yStarPlus = 1.1
vx, vy = symbols('v_x v_y', cls=Function, positive=True, real=True)
mu, x, y = var('mu x y', real=True, positive=True)
nx, ny = var('n_x n_y')
n = sp.Matrix([Integer(0), Integer(1)])
v_vec = sp.Matrix([vx(x, y), 0])
kinFunc, epsFunc = symbols('k_f \epsilon_f', cls=Function)
u = sym_func(x, y, 1)
v = sym_func(x, y, 1)
p = sym_func(x, y, 1)
k = sym_func(x, y, 1)
eps = sym_func(x, y, 1)
# Want to test wall function bc
uNew = mu * yStarPlus**2 / y
# uNew = 0.5 + sin(pi * x / 2) + sin(pi * y / 2) + mu * yStarPlus**2 / y
vNew = 0
pNew = 0
kinNew = k
epsilonNew = eps
# # Want to test natural boundary condition
# uNew = 0.5 + sin(pi * x / 2) + sin(pi * y / 2)
# vNew = 0
# pNew = 0
# kinNew = k
# epsilonNew = eps
uVecNew = sp.Matrix([uNew, vNew])
numeric = bc_terms_momentum_traction(uVecNew, n, kinNew, epsilonNew, x, y, symbolic=False)
numeric_wall_function = wall_function_momentum_traction(uVecNew, n, kinNew, epsilonNew, x, y, "kin", symbolic=False)
symbolic = bc_terms_momentum_traction(v_vec, n, kinFunc(x, y), epsFunc(x, y), x, y, symbolic=True)
wall_function = wall_function_momentum_traction(v_vec, n, kinFunc(x, y), epsFunc(x, y), x, y, "kin", symbolic=True)
In [4]:
write_reduced_functions(uVecNew, kinNew, epsilonNew, x, y)
In [6]:
expr = numeric[0] - numeric_wall_function[0]
expr.subs(y, 1).collect('mu')
Out[6]:
In [2]:
expr = symbolic[0] - wall_function[0]
# print(expr)
# expr
newexp = expr.subs(vx(x, y), vx(y)).subs(Abs(vx(y)), vx(y))
# print(newexp)
newexp
Out[2]:
In [45]:
dsolve(newexp, vx(y))
Out[45]:
In [39]:
symbolic[0]
Out[39]:
In [40]:
wall_function[0]
Out[40]:
In [68]:
from moose_calc_routines import *
from sympy import *
import sympy as sp
from IPython.core.interactiveshell import InteractiveShell
InteractiveShell.ast_node_interactivity = "all"
init_printing()
x, y = var('x y')
# # INS turbulence
# u = 0.4*sin(0.5*pi*x) + 0.4*sin(pi*y) + 0.7*sin(0.2*pi*x*y) + 0.5
# v = 0.6*sin(0.8*pi*x) + 0.3*sin(0.3*pi*y) + 0.2*sin(0.3*pi*x*y) + 0.3
# p = 0.5*sin(0.5*pi*x) + 1.0*sin(0.3*pi*y) + 0.5*sin(0.2*pi*x*y) + 0.5
# k = 0.4*sin(0.7*pi*x) + 0.9*sin(0.7*pi*y) + 0.7*sin(0.4*pi*x*y) + 0.4
# eps = 0.6*sin(0.3*pi*x) + 0.9*sin(0.9*pi*y) + 0.8*sin(0.6*pi*x*y) + 0.5
# uvec = sp.Matrix([u, v])
# n = sp.Matrix([Integer(0), Integer(1)])
# INS only
u = 0.4*sin(0.5*pi*x) + 0.4*sin(pi*y) + 0.7*sin(0.2*pi*x*y) + 0.5
v = 0.6*sin(0.8*pi*x) + 0.3*sin(0.3*pi*y) + 0.2*sin(0.3*pi*x*y) + 0.3
p = 0.5*sin(0.5*pi*x) + 1.0*sin(0.3*pi*y) + 0.5*sin(0.2*pi*x*y) + 0.5
uvec = sp.Matrix([u, v])
nvec = sp.Matrix([Integer(0), Integer(1)])
nvecs = {'left' : sp.Matrix([-1, 0]), 'top' : sp.Matrix([0, 1]), \
'right' : sp.Matrix([1, 0]), 'bottom' : sp.Matrix([0, -1])}
source = {bnd_name :
prep_moose_input(-bc_terms_momentum_traction_no_turbulence(uvec, nvec, p, x, y, parts=True)[0])
for bnd_name, nvec in nvecs.items()}
In [75]:
source
Out[75]:
In [3]:
surface_terms = bc_terms_momentum_traction_no_turbulence(uvec, nvec, p, x, y, parts=True)
tested_bc = no_bc_bc(uvec, nvec, p, x, y, parts=True)
needed_func = tested_bc - surface_terms
print(prep_moose_input(needed_func[0]))
print(prep_moose_input(needed_func[1]))
In [1]:
surface_terms = bc_terms_momentum_traction(uvec, n, p, k, eps, x, y, symbolic=False, parts=True)
tested_bc = wall_function_momentum_traction(uvec, n, p, k, eps, x, y, "kin", symbolic=False, parts=True)
In [2]:
needed_func = tested_bc - surface_terms
needed_func
print(prep_moose_input(needed_func[0]))
Out[2]:
In [3]:
print(prep_moose_input(-surface_terms[0]))
In [3]:
wall_function_momentum_traction(uvec, n, p, k, eps, x, y, "kin", symbolic=True, parts=True)
Out[3]:
In [1]:
surface_terms = bc_terms_diffusion(u, n, x, y)
tested_bc = vacuum(u, n)
In [2]:
surface_terms
tested_bc
Out[2]:
Out[2]:
In [3]:
needed_func = tested_bc - surface_terms
In [6]:
needed_func
print(needed_func)
Out[6]:
In [1]:
from moose_calc_routines import *
from sympy import *
import sympy as sp
from IPython.core.interactiveshell import InteractiveShell
InteractiveShell.ast_node_interactivity = "all"
init_printing()
x, y = var('x y')
# INS turbulence
u = 0.4*sin(0.5*pi*x) + 0.4*sin(pi*y) + 0.7*sin(0.2*pi*x*y) + 0.5
v = 0.6*sin(0.8*pi*x) + 0.3*sin(0.3*pi*y) + 0.2*sin(0.3*pi*x*y) + 0.3
p = 0.5*sin(0.5*pi*x) + 1.0*sin(0.3*pi*y) + 0.5*sin(0.2*pi*x*y) + 0.5
k = 0.4*sin(0.7*pi*x) + 0.9*sin(0.7*pi*y) + 0.7*sin(0.4*pi*x*y) + 0.4
eps = 0.6*sin(0.3*pi*x) + 0.9*sin(0.9*pi*y) + 0.8*sin(0.6*pi*x*y) + 0.5
# # INS only
# u = 0.4*sin(0.5*pi*x) + 0.4*sin(pi*y) + 0.7*sin(0.2*pi*x*y) + 0.5
# v = 0.6*sin(0.8*pi*x) + 0.3*sin(0.3*pi*y) + 0.2*sin(0.3*pi*x*y) + 0.3
# p = 0.5*sin(0.5*pi*x) + 1.0*sin(0.3*pi*y) + 0.5*sin(0.2*pi*x*y) + 0.5
uvec = sp.Matrix([u, v])
nvecs = {'left' : sp.Matrix([-1, 0]), 'top' : sp.Matrix([0, 1]), \
'right' : sp.Matrix([1, 0]), 'bottom' : sp.Matrix([0, -1])}
source = {bnd_name :
prep_moose_input(#ins_epsilon_wall_function_bc(nvec, k, eps, x, y)
-bc_terms_eps(nvec, k, eps, x, y)[0,0])
for bnd_name, nvec in nvecs.items()}
# anti_bounds = {'left' : 'top right bottom', 'top' : 'right bottom left',
# 'right' : 'bottom left top', 'bottom' : 'left top right'}
anti_bounds = {'left' : 'top right bottom left', 'top' : 'right bottom left top',
'right' : 'bottom left top right', 'bottom' : 'left top right bottom'}
h_list = ['5', '10']
base = "k_epsilon_general_bc"
h_array = np.array([.2, .1])
volume_source = {'u' : prep_moose_input(L_momentum_traction(uvec, p, k, eps, x, y)[0]),
'v' : prep_moose_input(L_momentum_traction(uvec, p, k, eps, x, y)[1]),
'p' : prep_moose_input(L_pressure(uvec, x, y)),
'k' : prep_moose_input(L_kin(uvec, k, eps, x, y)),
'eps' : prep_moose_input(L_eps(uvec, k , eps, x, y))}
diri_func = {'u' : u, 'v' : v, 'p' : p, 'k' : k, 'eps' : eps}
In [1]:
a_string = "b"
a_string += "c"
a_string
Out[1]:
In [2]:
"a" + None
In [6]:
optional_save_string="epsilon_wall_func_natural"
plot_order_accuracy('left', h_array, base, optional_save_string=optional_save_string)
plot_order_accuracy('right', h_array, base, optional_save_string=optional_save_string)
plot_order_accuracy('top', h_array, base, optional_save_string=optional_save_string)
plot_order_accuracy('bottom', h_array, base, optional_save_string=optional_save_string)
Tasks accomplished today:
Natural results suggest the moose python calculation routine for the integrated by parts terms is wrong!
In [4]:
string = "Functions" + str('u')
string
Out[4]:
In [5]:
import numpy as np
import matplotlib.pyplot as plt
x = np.arange(0, 2.1, .1)
u = 2*x**2 + 4*x
v = 3*x**2 + 2*x + 1
plt.plot(x, u)
plt.plot(x, v)
plt.show()
In [6]:
x = np.arange(0, 2.1, .1)
u = 1 - 2*x + 2*x**2
v = x**2
plt.plot(x, u)
plt.plot(x, v)
plt.show()
In [ ]: