Discussion:
Spline interpolation and fipy variable
Clara Maurel
2018-01-10 21:43:29 UTC
Permalink
Hello,

I asked a similar questions several months ago and someone nicely answered with some ideas, which however did not solve my problem. So I am just trying another time!

I want to model the dynamics of a system using the Cahn Hilliard equation, with a diffusion coefficient that depends on the cell variable (concentration X) and time.

The diffusion coefficient (Diff) is proportional to the second derivative of the free energy (d2G). The latter function is not continuous and I would like to interpolate it with a B-spline (scipy.interpolate.UnivariateSpline). FYI, I first started with a polynomial interpolation: the fit was not satisfactory in terms of the physics I want to capture, but the fipy code worked well.

Problems come when I want to use my spline function with the cell variable X: this always return an array where fipy would like a fipy variable, and I don’t know if there would be a way to do so. Would anyone have an idea on how I could do that?
The suggestion I had before was to set Diff as a cell variable and update the value of Diff at each time step. However, doing so the behaviour of the system was not physical.

Diff = CellVariable(mesh=mesh)
Diff.setValue(d2G(Xf))


Any other idea would be greatly appreciated! I would be happy to send my code if necessary.

Thank you in advance,
Clara





Here is the part of my code in question:

## Mesh
L = 200.
nx = 1000
dx = L/nx

mesh = PeriodicGrid1D(nx=nx, dx=dx)

## Variable
X_var = CellVariable(name=r"$X_{at}$", mesh=mesh, hasOld=True)


## Mean initial concentration
X_mean = float(comp)/100.0
X_mean_txt = str(comp)
id_mean = Get_closest_id(X,X_mean)
id_mean_spino = Get_closest_id(X_spino_low,X_mean)


## Initial temperature corresponding to X_mean on spinodal boundary
T0 = T_spino[id_mean_spino]

## Initial thermal fluctuations
noise = GaussianNoiseVariable(mesh=mesh, mean=X_mean, variance=0.00001).value
X_var[:] = noise
X_var.updateOld()
Xf = X_var.arithmeticFaceValue

## Initial mobility
Mob = M[id_mean_spino][id_mean]

## This interpolate the second derivative of the free energy with a B-spline and return Spline(Xf) WHICH IS AN ARRAY...
d2G = Get_spline_Chebnodes(Xf,100,T0,R,RefFe,RefNi,L0ex,L1ex,L2ex,Tmag,Bmag,p_fcc,A_fcc,Nv,Na)

## Initial diffusion coefficient
Diff = Mob*d2G

## Initial gradient energy (depending on the interfacial energy we want)
K = 2.0*kappa[id_mean_spino]

## Initial equation
eq = TransientTerm(coeff=1.) == DiffusionTerm(Diff) - DiffusionTerm(coeff=(Mob, K))

## Time and integration parameters
time = (T0-T_spino[id_mean_spino])/Cr
duration = (T0-T_spino[-2])/Cr # in s
dt = 3.154e7 # 1 year in s
dt_max = 3.154e13 # 1,000,000 years in s
total_sweeps = 4
tolerance = 1.0e-3
step_T = id_mean_spino

solver = Solver()

## Start looping
while time < duration:

res0 = eq.sweep(X_var, dt=dt, solver=solver)

next_time_T = (T0-T_spino[step_T+1])/Cr
print "Next temperature step is at: " + str(next_time_T/Myr_in_s) + " Myr"
print "Temperature: "+str(T_spino[step_T]-273)

while time < next_time_T:

for sweeps in range(total_sweeps):
res = eq.sweep(X_var, dt=dt, solver=solver)

if res < res0 * tolerance:
time += dt
dt *= 1.1
dt = min(dt_max, dt)
X_var.updateOld()
Xf = X_var.arithmeticFaceValue

else:
dt *= 0.8
X_var[:] = X_var.old
Xf = X_var.arithmeticFaceValue

print "Arrived at a temperature step!"
step_T += 1
id_mean_T = Get_closest_id(X,np.mean(X_var))

Mob = M[step_T][id_mean_T]

d2G = Get_spline_Chebnodes(Xf,100,T_spino[step_T],R,RefFe,RefNi,L0ex,L1ex,L2ex,Tmag,Bmag,p_fcc,A_fcc,Nv,Na)

Diff = Mob*d2G

K = 2.0*kappa[step_T]

eq = TransientTerm(coeff=1.) == DiffusionTerm(Diff) - DiffusionTerm(coeff=(Mob, K))
Daniel Wheeler
2018-01-11 18:13:16 UTC
Permalink
Hi Clara,

Can you post the entire working code so I can try and debug?

Cheers,

Daniel
Post by Clara Maurel
Hello,
I asked a similar questions several months ago and someone nicely answered
with some ideas, which however did not solve my problem. So I am just trying
another time!
I want to model the dynamics of a system using the Cahn Hilliard equation,
with a diffusion coefficient that depends on the cell variable
(concentration X) and time.
The diffusion coefficient (Diff) is proportional to the second derivative of
the free energy (d2G). The latter function is not continuous and I would
like to interpolate it with a B-spline (scipy.interpolate.UnivariateSpline).
FYI, I first started with a polynomial interpolation: the fit was not
satisfactory in terms of the physics I want to capture, but the fipy code
worked well.
Problems come when I want to use my spline function with the cell variable
X: this always return an array where fipy would like a fipy variable, and I
don’t know if there would be a way to do so. Would anyone have an idea on
how I could do that?
The suggestion I had before was to set Diff as a cell variable and update
the value of Diff at each time step. However, doing so the behaviour of the
system was not physical.
Diff = CellVariable(mesh=mesh)
Diff.setValue(d2G(Xf))
Any other idea would be greatly appreciated! I would be happy to send my code if necessary.
Thank you in advance,
Clara
## Mesh
L = 200.
nx = 1000
dx = L/nx
mesh = PeriodicGrid1D(nx=nx, dx=dx)
## Variable
X_var = CellVariable(name=r"$X_{at}$", mesh=mesh, hasOld=True)
## Mean initial concentration
X_mean = float(comp)/100.0
X_mean_txt = str(comp)
id_mean = Get_closest_id(X,X_mean)
id_mean_spino = Get_closest_id(X_spino_low,X_mean)
## Initial temperature corresponding to X_mean on spinodal boundary
T0 = T_spino[id_mean_spino]
## Initial thermal fluctuations
noise = GaussianNoiseVariable(mesh=mesh, mean=X_mean,
variance=0.00001).value
X_var[:] = noise
X_var.updateOld()
Xf = X_var.arithmeticFaceValue
## Initial mobility
Mob = M[id_mean_spino][id_mean]
## This interpolate the second derivative of the free energy with a B-spline
and return Spline(Xf) WHICH IS AN ARRAY...
d2G =
Get_spline_Chebnodes(Xf,100,T0,R,RefFe,RefNi,L0ex,L1ex,L2ex,Tmag,Bmag,p_fcc,A_fcc,Nv,Na)
## Initial diffusion coefficient
Diff = Mob*d2G
## Initial gradient energy (depending on the interfacial energy we want)
K = 2.0*kappa[id_mean_spino]
## Initial equation
eq = TransientTerm(coeff=1.) == DiffusionTerm(Diff) -
DiffusionTerm(coeff=(Mob, K))
## Time and integration parameters
time = (T0-T_spino[id_mean_spino])/Cr
duration = (T0-T_spino[-2])/Cr # in s
dt = 3.154e7 # 1 year in s
dt_max = 3.154e13 # 1,000,000 years in s
total_sweeps = 4
tolerance = 1.0e-3
step_T = id_mean_spino
solver = Solver()
## Start looping
res0 = eq.sweep(X_var, dt=dt, solver=solver)
next_time_T = (T0-T_spino[step_T+1])/Cr
print "Next temperature step is at: " + str(next_time_T/Myr_in_s) + " Myr"
print "Temperature: "+str(T_spino[step_T]-273)
res = eq.sweep(X_var, dt=dt, solver=solver)
time += dt
dt *= 1.1
dt = min(dt_max, dt)
X_var.updateOld()
Xf = X_var.arithmeticFaceValue
dt *= 0.8
X_var[:] = X_var.old
Xf = X_var.arithmeticFaceValue
print "Arrived at a temperature step!"
step_T += 1
id_mean_T = Get_closest_id(X,np.mean(X_var))
Mob = M[step_T][id_mean_T]
d2G =
Get_spline_Chebnodes(Xf,100,T_spino[step_T],R,RefFe,RefNi,L0ex,L1ex,L2ex,Tmag,Bmag,p_fcc,A_fcc,Nv,Na)
Diff = Mob*d2G
K = 2.0*kappa[step_T]
eq = TransientTerm(coeff=1.) == DiffusionTerm(Diff) -
DiffusionTerm(coeff=(Mob, K))
_______________________________________________
fipy mailing list
http://www.ctcms.nist.gov/fipy
[ NIST internal ONLY: https://email.nist.gov/mailman/listinfo/fipy ]
--
Daniel Wheeler
Clara Maurel
2018-01-11 19:35:12 UTC
Permalink
Hi Daniel,

Thank you for taking the time to look at this! My main code calls several text files and subroutine. I attach everything that is needed to run the code:

Spinodal_fipy_FeNi_varT_runs_DEBUG.py





Let me know if anything is unclear.
Thank you!

Clara
Post by Daniel Wheeler
Can you post the entire working code so I can try and debug?
Cheers,
Daniel
Post by Clara Maurel
Hello,
I asked a similar questions several months ago and someone nicely answered
with some ideas, which however did not solve my problem. So I am just trying
another time!
I want to model the dynamics of a system using the Cahn Hilliard equation,
with a diffusion coefficient that depends on the cell variable
(concentration X) and time.
The diffusion coefficient (Diff) is proportional to the second derivative of
the free energy (d2G). The latter function is not continuous and I would
like to interpolate it with a B-spline (scipy.interpolate.UnivariateSpline).
FYI, I first started with a polynomial interpolation: the fit was not
satisfactory in terms of the physics I want to capture, but the fipy code
worked well.
Problems come when I want to use my spline function with the cell variable
X: this always return an array where fipy would like a fipy variable, and I
don’t know if there would be a way to do so. Would anyone have an idea on
how I could do that?
The suggestion I had before was to set Diff as a cell variable and update
the value of Diff at each time step. However, doing so the behaviour of the
system was not physical.
Diff = CellVariable(mesh=mesh)
Diff.setValue(d2G(Xf))
Any other idea would be greatly appreciated! I would be happy to send my
code if necessary.
Thank you in advance,
Clara
## Mesh
L = 200.
nx = 1000
dx = L/nx
mesh = PeriodicGrid1D(nx=nx, dx=dx)
## Variable
X_var = CellVariable(name=r"$X_{at}$", mesh=mesh, hasOld=True)
## Mean initial concentration
X_mean = float(comp)/100.0
X_mean_txt = str(comp)
id_mean = Get_closest_id(X,X_mean)
id_mean_spino = Get_closest_id(X_spino_low,X_mean)
## Initial temperature corresponding to X_mean on spinodal boundary
T0 = T_spino[id_mean_spino]
## Initial thermal fluctuations
noise = GaussianNoiseVariable(mesh=mesh, mean=X_mean,
variance=0.00001).value
X_var[:] = noise
X_var.updateOld()
Xf = X_var.arithmeticFaceValue
## Initial mobility
Mob = M[id_mean_spino][id_mean]
## This interpolate the second derivative of the free energy with a B-spline
and return Spline(Xf) WHICH IS AN ARRAY...
d2G =
Get_spline_Chebnodes(Xf,100,T0,R,RefFe,RefNi,L0ex,L1ex,L2ex,Tmag,Bmag,p_fcc,A_fcc,Nv,Na)
## Initial diffusion coefficient
Diff = Mob*d2G
## Initial gradient energy (depending on the interfacial energy we want)
K = 2.0*kappa[id_mean_spino]
## Initial equation
eq = TransientTerm(coeff=1.) == DiffusionTerm(Diff) -
DiffusionTerm(coeff=(Mob, K))
## Time and integration parameters
time = (T0-T_spino[id_mean_spino])/Cr
duration = (T0-T_spino[-2])/Cr # in s
dt = 3.154e7 # 1 year in s
dt_max = 3.154e13 # 1,000,000 years in s
total_sweeps = 4
tolerance = 1.0e-3
step_T = id_mean_spino
solver = Solver()
## Start looping
res0 = eq.sweep(X_var, dt=dt, solver=solver)
next_time_T = (T0-T_spino[step_T+1])/Cr
print "Next temperature step is at: " + str(next_time_T/Myr_in_s) + " Myr"
print "Temperature: "+str(T_spino[step_T]-273)
res = eq.sweep(X_var, dt=dt, solver=solver)
time += dt
dt *= 1.1
dt = min(dt_max, dt)
X_var.updateOld()
Xf = X_var.arithmeticFaceValue
dt *= 0.8
X_var[:] = X_var.old
Xf = X_var.arithmeticFaceValue
print "Arrived at a temperature step!"
step_T += 1
id_mean_T = Get_closest_id(X,np.mean(X_var))
Mob = M[step_T][id_mean_T]
d2G =
Get_spline_Chebnodes(Xf,100,T_spino[step_T],R,RefFe,RefNi,L0ex,L1ex,L2ex,Tmag,Bmag,p_fcc,A_fcc,Nv,Na)
Diff = Mob*d2G
K = 2.0*kappa[step_T]
eq = TransientTerm(coeff=1.) == DiffusionTerm(Diff) -
DiffusionTerm(coeff=(Mob, K))
_______________________________________________
fipy mailing list
http://www.ctcms.nist.gov/fipy
[ NIST internal ONLY: https://email.nist.gov/mailman/listinfo/fipy ]
--
Daniel Wheeler
_______________________________________________
fipy mailing list
http://www.ctcms.nist.gov/fipy
[ NIST internal ONLY: https://email.nist.gov/mailman/listinfo/fipy ]
Daniel Wheeler
2018-01-12 17:04:58 UTC
Permalink
Hi Clara,

The following changes made it run for me. I turned d2G into a face
variable and K into a variable that is updated in the sweep loop. I
also removed redefining the equation. FiPy's designed so you only need
to to create the equation once. I'm not sure what the values of d2G
correspond to. Which spatial location do they correspond to? Faces or
Cells. I'm assuming faces since there are 1001 of them. Also, this
might need to be adjusted for higher dimensions.

Cheers,

Daniel

~~~~
$ git diff
diff --git a/Spinodal_fipy_FeNi_varT_runs_DEBUG.py
b/Spinodal_fipy_FeNi_varT_runs_DEBUG.py
index 715e79b..a82387e 100644
--- a/Spinodal_fipy_FeNi_varT_runs_DEBUG.py
+++ b/Spinodal_fipy_FeNi_varT_runs_DEBUG.py
@@ -289,20 +289,21 @@ def
Get_spline_Chebnodes(X,N,T0,R,RefFe,RefNi,L0ex,L1ex,L2ex,Tmag,Bmag,p_fcc,A_f
return d2G


+
## THIS IS WHERE I WOULD LIKE TO HAVE A FIPY VARIABLE TYPE FOR d2G.
d2G = Get_spline_Chebnodes(Xf,100,T0,R,RefFe,RefNi,L0ex,L1ex,L2ex,Tmag,Bmag,p_fcc,A_fcc,Nv,Na)*1.0e-9
-
+d2G_var = FaceVariable(mesh=mesh, value=d2G)

## Initial diffusion coefficient
-Diff = Mob*d2G
+Diff = Mob*d2G_var


## Initial gradient energy (depending on the interfacial energy we want)
K = 2.0*kappa[id_mean_spino]
-
+K_var = Variable(K)

## Initial equation
-eq = TransientTerm(coeff=1.) == DiffusionTerm(Diff) -
DiffusionTerm(coeff=(Mob, K))
+eq = TransientTerm(coeff=1.) == DiffusionTerm(Diff) -
DiffusionTerm(coeff=(Mob, K_var))


plt.figure(figsize=(8,6))
@@ -390,16 +391,16 @@ while time < duration:
Mob = M[step_T][id_mean_T]

d2G = Get_spline_Chebnodes(Xf,100,T_spino[step_T],R,RefFe,RefNi,L0ex,L1ex,L2ex,Tmag,Bmag,p_fcc,A_fcc,Nv,Na)*1.0e-9
-
- Diff = Mob*d2G
+ d2G_var[:] = d2G

K = 2.0*kappa[step_T]
+ K_var.setValue(K)
print 'Mob, Diff, K'
print Mob, Diff, K
print 'MAX CONCENTRATION'
print max(X_var)

- eq = TransientTerm(coeff=1.) == DiffusionTerm(Diff) -
DiffusionTerm(coeff=(Mob, K))
+


print datetime.now() - startTime
(END)
~~~~
Post by Clara Maurel
Hi Daniel,
Thank you for taking the time to look at this! My main code calls several
text files and subroutine. I attach everything that is needed to run the
--
Daniel Wheeler
Clara Maurel
2018-01-12 17:42:14 UTC
Permalink
Hi Daniel,

Thank you very much! The code runs for me as well: fantastic!

I have to admit that the distinction between cell and face variables remains a bit obscure to me
 The cell variable X_var is the composition of the system I am modelling. Then "G" in d2G is the Gibbs free energy (called f here https://www.ctcms.nist.gov/fipy/examples/cahnHilliard/generated/examples.cahnHilliard.mesh2DCoupled.html#module-examples.cahnHilliard.mesh2DCoupled <https://www.ctcms.nist.gov/fipy/examples/cahnHilliard/generated/examples.cahnHilliard.mesh2DCoupled.html#module-examples.cahnHilliard.mesh2DCoupled>), which is itself a function of the composition X_var (the spline function).
I don’t know if these info are more useful to figure out if d2G should be cell or face variable? As I understood it, because I want to solve for X_var, this should be a cell variable and nothing else.

By higher dimension do you also mean 2D? I know 2D requires a lot of changes, but I thought 2D required only a change of grid. In any case, 2D is not my top priority at the moment.

Thank you again very much for your help!
Clara
Post by Daniel Wheeler
Hi Clara,
The following changes made it run for me. I turned d2G into a face
variable and K into a variable that is updated in the sweep loop. I
also removed redefining the equation. FiPy's designed so you only need
to to create the equation once. I'm not sure what the values of d2G
correspond to. Which spatial location do they correspond to? Faces or
Cells. I'm assuming faces since there are 1001 of them. Also, this
might need to be adjusted for higher dimensions.
Cheers,
Daniel
~~~~
$ git diff
diff --git a/Spinodal_fipy_FeNi_varT_runs_DEBUG.py
b/Spinodal_fipy_FeNi_varT_runs_DEBUG.py
index 715e79b..a82387e 100644
--- a/Spinodal_fipy_FeNi_varT_runs_DEBUG.py
+++ b/Spinodal_fipy_FeNi_varT_runs_DEBUG.py
@@ -289,20 +289,21 @@ def
Get_spline_Chebnodes(X,N,T0,R,RefFe,RefNi,L0ex,L1ex,L2ex,Tmag,Bmag,p_fcc,A_f
return d2G
+
## THIS IS WHERE I WOULD LIKE TO HAVE A FIPY VARIABLE TYPE FOR d2G.
d2G = Get_spline_Chebnodes(Xf,100,T0,R,RefFe,RefNi,L0ex,L1ex,L2ex,Tmag,Bmag,p_fcc,A_fcc,Nv,Na)*1.0e-9
-
+d2G_var = FaceVariable(mesh=mesh, value=d2G)
## Initial diffusion coefficient
-Diff = Mob*d2G
+Diff = Mob*d2G_var
## Initial gradient energy (depending on the interfacial energy we want)
K = 2.0*kappa[id_mean_spino]
-
+K_var = Variable(K)
## Initial equation
-eq = TransientTerm(coeff=1.) == DiffusionTerm(Diff) -
DiffusionTerm(coeff=(Mob, K))
+eq = TransientTerm(coeff=1.) == DiffusionTerm(Diff) -
DiffusionTerm(coeff=(Mob, K_var))
plt.figure(figsize=(8,6))
Mob = M[step_T][id_mean_T]
d2G = Get_spline_Chebnodes(Xf,100,T_spino[step_T],R,RefFe,RefNi,L0ex,L1ex,L2ex,Tmag,Bmag,p_fcc,A_fcc,Nv,Na)*1.0e-9
-
- Diff = Mob*d2G
+ d2G_var[:] = d2G
K = 2.0*kappa[step_T]
+ K_var.setValue(K)
print 'Mob, Diff, K'
print Mob, Diff, K
print 'MAX CONCENTRATION'
print max(X_var)
- eq = TransientTerm(coeff=1.) == DiffusionTerm(Diff) -
DiffusionTerm(coeff=(Mob, K))
+
print datetime.now() - startTime
(END)
~~~~
Post by Clara Maurel
Hi Daniel,
Thank you for taking the time to look at this! My main code calls several
text files and subroutine. I attach everything that is needed to run the
--
Daniel Wheeler
_______________________________________________
fipy mailing list
http://www.ctcms.nist.gov/fipy
[ NIST internal ONLY: https://email.nist.gov/mailman/listinfo/fipy ]
Daniel Wheeler
2018-01-12 17:58:08 UTC
Permalink
Post by Clara Maurel
Hi Daniel,
Thank you very much! The code runs for me as well: fantastic!
I have to admit that the distinction between cell and face variables remains
a bit obscure to me…
The domain is divided into cells or boxes in 2D. The faces are where
the boxes meet and the cell centers are located at the center of the
boxes. FiPy calculates/resolves fluxes between the boxes.
Post by Clara Maurel
The cell variable X_var is the composition of the
system I am modelling. Then "G" in d2G is the Gibbs free energy (called f
here
https://www.ctcms.nist.gov/fipy/examples/cahnHilliard/generated/examples.cahnHilliard.mesh2DCoupled.html#module-examples.cahnHilliard.mesh2DCoupled),
which is itself a function of the composition X_var (the spline function).
I don’t know if these info are more useful to figure out if d2G should be
cell or face variable? As I understood it, because I want to solve for
X_var, this should be a cell variable and nothing else.
X_var is a cell variable but the diffusion coefficient can either be a
cell variable or a face variable in FiPy. FiPy converts the diffusion
coefficient to a face variable if it's defined as a cell variable in
the input file. FiPy calculates the flux between cells so the
diffusion coefficient is only used at the faces where the flux is
calculated. d2G has values which are defined over the domain. How do
those values correspond to a location in that domain? Why does d2G
have a shape of (1001,) when there are only 1000 cells?
Post by Clara Maurel
By higher dimension do you also mean 2D? I know 2D requires a lot of
changes, but I thought 2D required only a change of grid. In any case, 2D is
not my top priority at the moment.
Ok, this is only being used for 1D right now so you're fine.
Post by Clara Maurel
Thank you again very much for your help!
Good luck with it.
--
Daniel Wheeler
Clara Maurel
2018-02-01 19:47:02 UTC
Permalink
Hello Daniel and Others,

We recently exchanged a couple of emails about a piece of code I have, where I wanted to express my diffusion coefficient as a function (d2G) of my cell variable using a spline interpolation, but couldn’t because the output of the spline function was not a type variable.

Diff_coeff = d2G(X_var)

Daniel suggested to declare d2G(X_var) as a face variable, and update it in my main loop. However, for some reason, this does not give me the results I expect. On the script attached, I tried two possibilities:
1) F is a polynomial function, therefore d2G(Xf) still gives me a type fipy variable, that I update in my loop
2) F is a face variable that I created from this polynomial function d2G(Xf) and that I update in my loop

Ideally, I would expect to find the same result. However, case 1) works, and case 2) goes crazy at some point, and I can’t really see what is wrong.

I attach my script (MAIN.py; the other files are just needed to run the main). To switch from case 2 to case 1, just replace "d2G_var" by "d2G" in the expression of "Diff" (four times total).


So, to summarize, my question is: why do I get a different result when my diffusion coefficient is a polynomial function of my cell variable (i.e., just a multiplication of my unique cell variable), and when it is a face variable whose value is that of the polynomial function? Is there a way to make it equivalent while keeping the face variable idea?


I hope it is somewhat Clear... Thank you in advance for your insights!
Clara

Loading...