Traducción del original en coreano escrito por el autor. Leer el original (한국어)
Pedí σ₁₂ = 1.00 y recibí 0.78 — dónde se filtra una fase ausente en el Allen–Cahn de tres componentes
Una energía libre de N fases escrita con σᵢⱼ por pares solo significa algo al invertirla en κᵢ por componente, y el signo de κᵢ es exactamente la condición de cierre del triángulo de Neumann.
Pedí σ₁₂ = 1.00 y recibí 0.78#
Entraron tres fases en un código phase-field y en el campo de tensión superficial 1-2 quedó escrito 1.00. Después vino la integral de la energía libre a través de la interfaz relajada. El resultado fue 0.78.
La fase que no debía contar era la 3. No estaba en ninguna parte del dominio: solo había quedado sembrada en . Y sin embargo, en equilibrio su fracción de volumen alcanzaba 0.21 justo en el centro de la interfaz 1-2.
Este artículo persigue ese 21% hasta el fondo. Invierte las escritas por pares en coeficientes de gradiente por componente, muestra que el signo de es la misma desigualdad que cierra el triángulo de Neumann, y localiza el único término que mantiene una fase ausente fuera de la interfaz. Al final, cuatro cierres corren sobre la misma malla y deciden los números.
N fracciones de volumen no son N grados de libertad#
Con fluidos inmiscibles, las fracciones de volumen arrastran una restricción.
Quedan grados de libertad. Pero el código reserva arreglos, y colgar una ecuación de Allen–Cahn de cada arreglo parece lo natural. Al copiar un solucionador de dos fases y subir el número de componentes sale exactamente esa forma.
Entonces la suma se rompe. Si cada potencial químico se escribe de forma independiente y se avanza con , resulta
y nada obliga al lado derecho a anularse. En la corrida de abajo, se abre hasta 0.859, la interfaz se disuelve y la tensión superficial cae a 0.026.
La receta de libro es un multiplicador de Lagrange. Al restar ,
la suma se conserva exactamente. Conviene alternar entre los dos cierres en la simulación siguiente.
Con 3 equations, no closure, la traza de se desploma hacia abajo y las tres curvas se difuminan juntas. Al pasar a mean projection, la traza se clava en , pero un bulto rojo de se levanta en el centro de la interfaz y sigma_eff queda por debajo de 1.00. Subir el deslizador Lambda aplana ese bulto.
Invertir σᵢⱼ por pares en κᵢ por componente#
La energía libre se escribe normalmente por pares.
es la profundidad del pozo doble del par - y el coeficiente de energía de gradiente del componente . Los pozos van por pares; los coeficientes de gradiente, por componente. Esa asimetría genera todo lo que viene después.
Ni ni se eligen con libertad. El límite de dos fases los amarra a cantidades físicas. Sustituyendo ,
que coincide con la forma habitual si . Integrar una vez el equilibrio 1D da , es decir . La solución es una tangente hiperbólica, y
donde es el espesor de interfaz en celdas y la tensión superficial. Invirtiendo ambas relaciones,
sale par por par. exige resolver las tres ecuaciones a la vez. Para tres fases,
Un coeficiente por componente es una combinación de tres tensiones por pares. Esta es la identidad central del artículo. En el artículo sobre Allen–Cahn conservativo de dos fases, con la movilidad y el término antidifusivo había un solo . Con tres fases ese se parte en tres, y se parte por resta.
Con el factor vale . En la segunda fila de la tabla, da , y . Los tres coeficientes suman . El par - solo suma . La relación de dos fases con y también devuelve . Al meter en el cociente es . La fórmula continua coincide con la entrada. El caso A en la malla devuelve , y ese es lo que cuestan cuatro celdas a través de la interfaz. El mismo factor sobre da . Esa es la fila en la que el triángulo no cierra. En , sigue positivo y las cuñas son , , . El margen antes de que el signo muera es , y el ángulo de la fase 3 ya bajó a . no entra en la cuenta de . Aparece como energía de gradiente solo cuando la fase 3 ocupa la interfaz. Tensiones iguales ponen cada en y cada cuña en . La suma es . La cuña de en la fila es más estrecha que esos . El ángulo se aprieta antes de que el signo cambie.
Dónde κ₃ cruza a negativo#
Restar significa que el signo puede perderse. Si entonces y la energía de gradiente se abre hacia abajo. Afilar la interfaz ahora baja la energía, así que la solución colapsa hasta el espaciado de malla. El modelo no se degrada: el funcional no está acotado por debajo desde el principio.
La misma condición se conoce con otro nombre. En una unión triple las tres tensiones se equilibran y fijan el ángulo de cuña de cada fase.
es el ángulo que ocupa la fase 1; para los otros dos basta rotar los índices. La condición para que este coseno salga de es exactamente la condición . Es decir, que el triángulo de Neumann cierre y que el modelo esté bien planteado son la misma desigualdad. Con fijo, cuando cae por debajo de el triángulo se rompe y la cuña de la fase 3 se abre a 180°. Eso es la fase 3 mojando por completo la interfaz 1-2. En las cuñas salen 143.1° / 126.9° / 90.0°. Un triángulo rectángulo 3-4-5, así que el ángulo de la fase 3 es exactamente recto.
Cuatro cierres sobre la misma malla#
Malla 1D de 200 celdas, , . Fase 1 a la izquierda, fase 2 a la derecha, fase 3 sembrada en solo en la interfaz. Tras 8000 pasos de relajación se miden , y la integral de energía libre a través de la interfaz, que es la tensión superficial realizada.
import math
import numpy as np
D, MOB, DT, NX = 4.0, 1.0 / 3.0, 0.2, 200
def pair_to_component(s12, s13, s23):
"""Tensiones superficiales por pares -> coeficientes de gradiente kappa_i y pozos beta_ij."""
f = 0.75 * D
kap = np.array([f * (s12 + s13 - s23),
f * (s12 + s23 - s13),
f * (s13 + s23 - s12)])
bet = 12.0 / D * np.array([[0, s12, s13], [s12, 0, s23], [s13, s23, 0]])
return kap, bet
def neumann_wedges(s12, s13, s23):
"""Angulos de cuna de las tres fases en grados si el triangulo de Neumann cierra, si no None."""
args = [(s23 ** 2 - s12 ** 2 - s13 ** 2) / (2 * s12 * s13),
(s13 ** 2 - s12 ** 2 - s23 ** 2) / (2 * s12 * s23),
(s12 ** 2 - s13 ** 2 - s23 ** 2) / (2 * s13 * s23)]
if any(abs(a) > 1 for a in args):
return None
return [math.degrees(math.acos(a)) for a in args]
def _ext(a):
return np.concatenate(([a[0]], a, [a[-1]]))
def lap1d(a):
e = _ext(a)
return e[:-2] - 2 * a + e[2:]
def grad1d(a):
e = _ext(a)
return (e[2:] - e[:-2]) / 2.0
def chem_potential(c, kap, bet, lam3):
c1, c2, c3 = c
dbulk = np.array([
2 * bet[0, 1] * c1 * c2 ** 2 + 2 * bet[0, 2] * c1 * c3 ** 2 + 2 * lam3 * c1 * (c2 * c3) ** 2,
2 * bet[0, 1] * c2 * c1 ** 2 + 2 * bet[1, 2] * c2 * c3 ** 2 + 2 * lam3 * c2 * (c1 * c3) ** 2,
2 * bet[0, 2] * c3 * c1 ** 2 + 2 * bet[1, 2] * c3 * c2 ** 2 + 2 * lam3 * c3 * (c1 * c2) ** 2,
])
return np.array([dbulk[i] - kap[i] * lap1d(c[i]) for i in range(3)])
def line_tension(c, kap, bet, lam3):
"""Integral de energia libre a traves de la interfaz = tension superficial realizada."""
c1, c2, c3 = c
e = (bet[0, 1] * (c1 * c2) ** 2 + bet[0, 2] * (c1 * c3) ** 2
+ bet[1, 2] * (c2 * c3) ** 2 + lam3 * (c1 * c2 * c3) ** 2)
for i in range(3):
e = e + 0.5 * kap[i] * grad1d(c[i]) ** 2
return float(e.sum())
def initial_profile(seed):
x = np.arange(NX) - NX / 2
c3 = seed * np.exp(-(x / D) ** 2)
c1 = 0.5 * (1 - np.tanh(2 * x / D)) * (1 - c3)
c2 = 0.5 * (1 + np.tanh(2 * x / D)) * (1 - c3)
return np.array([c1, c2, c3])
def relax(kap, bet, closure, lam3=0.0, steps=8000, seed=1e-3):
c = initial_profile(0.0 if closure == 'two-phase' else seed)
for _ in range(steps):
mu = chem_potential(c, kap, bet, lam3)
if closure == 'two-phase':
m = 0.5 * (mu[0] + mu[1])
rhs = np.array([mu[0] - m, mu[1] - m, np.zeros(NX)])
elif closure == 'independent':
rhs = mu
else:
rhs = mu - mu.mean(axis=0)
c = c - MOB * DT * rhs
if not np.isfinite(c).all() or np.abs(c).max() > 1e3:
return None, None, None
return c, float(np.abs(c.sum(axis=0) - 1.0).max()), line_tension(c, kap, bet, lam3)
print("== pairwise sigma_ij -> per-component kappa_i (D = %.1f) ==" % D)
print("%-20s %-26s %-8s %s" % ("sigma_12,13,23", "kappa_1,2,3", "closes", "wedge angles [deg]"))
for s in [(1.0, 1.0, 1.0), (1.0, 0.8, 0.6), (1.0, 0.55, 0.55), (1.0, 0.4, 0.4)]:
kap, _ = pair_to_component(*s)
th = neumann_wedges(*s)
print("%-20s %-26s %-8s %s" % (
"%.2f %.2f %.2f" % s,
"%+.2f %+.2f %+.2f" % tuple(kap),
"yes" if kap.min() > 0 else "NO",
"-" if th is None else "%.1f %.1f %.1f (sum %.1f)" % (th[0], th[1], th[2], sum(th))))
kap, bet = pair_to_component(1.0, 0.8, 0.6)
print()
print("== 1-2 interface at equilibrium, phase 3 seeded at 1e-3 (input sigma_12 = 1.00) ==")
print("%-30s %-13s %-9s %s" % ("closure", "max|sum c-1|", "max c_3", "sigma_eff"))
cases = [("A two-phase (c_3 frozen)", 'two-phase', 0.0),
("B three equations, no closure", 'independent', 0.0),
("C mean projection", 'projected', 0.0),
("D mean projection + Lambda=400", 'projected', 400.0)]
for tag, closure, lam3 in cases:
c, drift, sig = relax(kap, bet, closure, lam3)
if c is None:
print("%-30s diverged" % tag)
continue
print("%-30s %-13.2e %-9.4f %.4f" % (tag, drift, c[2].max(), sig))
print()
print("== triple-penalty Lambda scan (mean projection) ==")
print("%-10s %-10s %-10s %s" % ("Lambda", "max c_3", "sigma_eff", "vs input"))
for lam3 in (0.0, 10.0, 30.0, 60.0, 150.0, 400.0):
c, drift, sig = relax(kap, bet, 'projected', lam3)
print("%-10.0f %-10.4f %-10.4f %+.1f%%" % (lam3, c[2].max(), sig, (sig - 1.0) * 100))== pairwise sigma_ij -> per-component kappa_i (D = 4.0) ==
sigma_12,13,23 kappa_1,2,3 closes wedge angles [deg]
1.00 1.00 1.00 +3.00 +3.00 +3.00 yes 120.0 120.0 120.0 (sum 360.0)
1.00 0.80 0.60 +3.60 +2.40 +1.20 yes 143.1 126.9 90.0 (sum 360.0)
1.00 0.55 0.55 +3.00 +3.00 +0.30 yes 155.4 155.4 49.2 (sum 360.0)
1.00 0.40 0.40 +3.00 +3.00 -0.60 NO -
== 1-2 interface at equilibrium, phase 3 seeded at 1e-3 (input sigma_12 = 1.00) ==
closure max|sum c-1| max c_3 sigma_eff
A two-phase (c_3 frozen) 1.78e-15 0.0000 0.9665
B three equations, no closure 8.59e-01 0.0000 0.0257
C mean projection 2.59e-13 0.2114 0.7809
D mean projection + Lambda=400 8.77e-15 0.0512 0.9715
== triple-penalty Lambda scan (mean projection) ==
Lambda max c_3 sigma_eff vs input
0 0.2114 0.7809 -21.9%
10 0.1887 0.8031 -19.7%
30 0.1448 0.8377 -16.2%
60 0.0963 0.8704 -13.0%
150 0.0515 0.9111 -8.9%
400 0.0512 0.9715 -2.9%Mover los tres deslizadores de cambia a la vez el signo de las barras de y los ángulos de cuña. Al bajarlos a , la columna closes de la tabla se da la vuelta.
Con en , al bajar y el triángulo se rompe en el instante en que la roja cruza . Esa es la fila de . En los ángulos se quedan en / / .
Σc aguanta a 1e-13 y la interfaz pierde 21.9%#
A congela la fase 3 por completo, así que es una corrida de dos fases. , un 3.3% por debajo del 1.00 de entrada. No es un defecto del modelo sino error de discretización con cuatro celdas a través de la interfaz. Confirma que la relación se cumple.
B resuelve las tres ecuaciones de forma independiente. La suma deriva 0.859 y la tensión superficial se desvanece a 0.0257. La interfaz se derritió.
C es la línea interesante. La proyección promedio clava la suma en . Pero y , un 21.9% por debajo de la entrada. La restricción se cumple y la física está mal.
Una violación de restricción se anuncia sola. Un error del 21.9% no. Por eso es el caro.
La aritmética de una fase ausente que se filtra#
Quitando el término de gradiente, la fuga se ve de inmediato. Suponiendo simetría en el centro de la interfaz 1-2 y poniendo , ,
Derivando en y evaluando en : el segundo término arranca en , así que no aporta a la pendiente. Solo sobrevive el primero.
Siempre negativo, sin importar cuánto valgan y . En un pozo cuártico por pares, añadir una tercera fase a una interfaz binaria es siempre cuesta abajo. Con la pendiente es .
Los números concuerdan. En , . Con el medido, : una caída del 45.7%. La energía de volumen recibe con gusto a la fase 3. Lo único que la frena es , y con el equilibrio solo llega en 0.21.
Hay un parecido con las corrientes parásitas, donde una gota que debería quedarse quieta empieza a fluir. Si la discretización de la tensión se desvía, la suma puede cuadrar y la interfaz equivocarse en silencio. Aquí queda en y en .
Dónde vive el penalizador triple Λ#
El remedio es un término que penalice directamente el solapamiento de tres fases en un punto.
En el barrido, subir empuja de 0.2114 a 0.0512 y devuelve de 0.7809 a 0.9715. En el déficit es −2.9%, prácticamente el mismo sitio que el error de discretización de A, −3.3%. Es indistinguible de congelar la fase 3.
Pero el término no tapa el agujero. Derivar en también da cero en . La pendiente cuesta abajo sigue intacta. Lo que hace es levantar un muro después de que el bulto ya creció, y por eso se detiene en 0.05 en lugar de ir a cero por más que se suba .
Para cerrar el agujero en sí hay que reducir a grados de libertad con , o simplemente no resolver la ecuación de una fase localmente ausente. A es ese caso, y por eso su es exactamente cero.
Si creer el 1.00 escrito o el 0.7809 integrado#
Meter la tabla por pares fija a la vez el signo de y los ángulos de cuña. Con los coeficientes son , , y los ángulos / / , con suma . Con , y el triángulo no cierra. Cinco fases dan diez ternas así. Una entrada negativa y la energía se abre hacia abajo en la celda donde esa terna se encuentra. Preguntar si los tres suman es la misma pregunta que si cada es positivo. Un ángulo se puede superponer al dibujo.
El valor de verificación no es la escrita. Es la integral de C, . La suma aguanta en y la tensión queda un por debajo. Igual que en un paso de tiempo capilar que sigue presente cuando la tensión superficial se trata de forma implícita, ese entra directo en la presión de Laplace y en la velocidad de las ondas capilares. Una comprobación que solo mira pasa. Incluso con el déficit es , o , a del de A con la fase congelada. Si el del campo de entrada queda como referencia, esa diferencia no llega al registro.
Relacionados
Comparte si te resultó útil.