Sorry, I forgot to include the link for the tutorial - I was looking at the 
2D coupled CH 
one, 
https://pages.nist.gov/fipy/en/latest/generated/examples.cahnHilliard.mesh2DCoupled.html#module-examples.cahnHilliard.mesh2DCoupled

Kind regards,
Irene

On Thursday, 23 October 2025 at 13:01:57 UTC+1 Irene Moreno wrote:

> Hi,
>
> I have recently been working on an application of Cahn-Hilliard to a 
> ternary system, and in the process of implementing the model, I have 
> stumbled upon two main questions.
>
> Firstly, I would like to know if the known problems of the coupled 
> implementation will prevent me from developing the model. My system of 
> equations is formed by two coupled sets of two equations each, so 4 eqs in 
> total, with two of them solving for (following the example's notation) 
> phi1, psi1, and the other set solving for phi2, psi2. However, the 
> equations for phi1 and psi1 also depend on phi2 and psi2, respectively, and 
> vice versa. 
>
> I have seen that Pysparse seems to take too much memory (is this the 
> default solver?) and Trillinos cannot solve the coupled system, so I 
> understand my best shot is PETSc (since my equations aren't in vector 
> form). How would the implementation of this method be different from the 
> code below?
>
> ############
> c=0
> while elapsed < duration:
>     res = 1.0
>     phi1.updateOld()
>     phi2.updateOld()
>     phi3.value = 1.0 - phi1 - phi2   # Unimportant variable, does not 
> appear in the equations at all
>
>     psi1.updateOld()
>     psi2.updateOld()
>
>     dt = min(100, numerix.exp(dexp))
>     elapsed += dt
>     dexp += 0.01
>
>     while res > 1.0e-3:
>         res = eq.sweep(dt=dt)
>         print(res)
> ############
>
> And secondly, about the evolution of phi in a binary system: I decided to 
> work from the tutorial (link) towards my equation, as implementing my model 
> directly led to issues. One of the first steps I took was, for the system 
> in 1D, changing the ICs from gaussian noise with the mean in 0.5 to 
> two-layered ones, with phi = 0.9999 at one side of the mesh, and phi = 0.2 
> in the other.  Full code for this described change is at the end.
>
> Since these are very close to the minima displayed by the free energy 
> density (same one as in the tutorial), I expected the system to just smooth 
> out the interface a bit, with the bulk concentrations staying mainly where 
> they were. However, what I have seen instead is, for some reason, the 
> concentrations increasing/decreasing along the interface, going into values 
> >1 before stabilising in the expected profile (see images below). If one of 
> the ICs defines phi as 0.0001, the phi in that section of the mesh goes 
> into values <0 before stabilising.
>
> [image: ICs_phi.png][image: snapshot_phi_0.006737946999085467.png][image: 
> snapshot_phi_0.19907123629213125.png][image: 
> snapshot_phi_449.7430549622601.png]
> where the three first images correspond to the ICs and the very beginning 
> of the simulation, and the last image is the final profile reached.
>
> Since the free energy density used in the tutorial is a polynomial, it 
> doesn't have any singularities, and therefore I understand that phi 
> technically can go below 0 or above 1. In this case, is there a way to 
> constrain the values the solver can accept in the solution? Would this be 
> an acceptable fix, or would it interfere with the dynamics? Would a better 
> approach be to use a log form in the free energy? 
>
> Thank you very much in advance.
>
> Kind regards,
> Irene
>
>
> #######################################################################
> from fipy import CellVariable, Grid1D, GaussianNoiseVariable, 
> DiffusionTerm, TransientTerm, ImplicitSourceTerm, Viewer
> from fipy.tools import numerix
> import numpy as np
>
> nx = 20
> mesh = Grid1D(nx=nx, dx=0.25)
> lx = 0.25 * nx
> height = mesh.cellCenters[0]
>
> D = 1.
> a = 1.
> epsilon = 0.5
>
> phi = CellVariable(name=r"$\phi$", mesh=mesh)
> psi = CellVariable(name=r"$\psi$", mesh=mesh)
>
> phi[:] = 1.0
> phi[height > lx/2] = 0.2
>
> psi.value[:] = a**2 * phi.value[:] * (1 - phi.value[:]) * (1 - 2 * 
> phi.value[:])
>
> viewer_phi = Viewer(vars=(phi,), datamin=-0.05, datamax=1.05)
> viewer_psi = Viewer(vars=(psi,), datamin=-0.05, datamax=3.0)
>
> viewer_phi.plot(f'ICs_phi.png')
> viewer_psi.plot(f'ICs_psi.png')
>
> dfdphi = a**2 * phi * (1 - phi) * (1 - 2 * phi)
> d2fdphi2 = a**2 * (1 - 6 * phi * (1 - phi))
>
> eq1 = (TransientTerm(var=phi) == DiffusionTerm(coeff=D, var=psi))
> eq2 = (ImplicitSourceTerm(coeff=1., var=psi)
>        == ImplicitSourceTerm(coeff=d2fdphi2, var=phi) - d2fdphi2 * phi + 
> dfdphi
>        - DiffusionTerm(coeff=epsilon**2, var=phi))
>
> eq = eq1 & eq2
>
> dexp = -5
> elapsed = 0.
> duration = 500.
> c=0
>
> while elapsed < duration:
>     dt = min(100, numerix.exp(dexp))
>     elapsed += dt
>     dexp += 0.01
>     eq.solve(dt=dt)
>     if c % 25 == 0:
>         viewer_phi.plot(f'snapshot_phi_{elapsed}.png')
>         viewer_psi.plot(f'snapshot_psi_{elapsed}.png')
>     c +=1
> #######################################################################

-- 
To unsubscribe from this group, send email to [email protected]

View this message at https://list.nist.gov/fipy
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].

Reply via email to