Gradient Descent in FEniCSx

I have a gradient descent code that i am trying to convert from FEniCS to FEniCSx. The original post where i got it to work is available “here“. The code is reproduced below:

from dolfin import *

L = 10
mesh = IntervalMesh(100, 0, L)
element = FiniteElement(“Lagrange”, mesh.ufl_cell(), 1)
V = FunctionSpace(mesh, “CG”, 1)
gamma = float(0.1)  # Learning rate.

u = Function(V)
u_up = Function(V)

phi = (1-u)**2

# Total potential energy
Pi = phi*dx

# Defining derivative
F = derivative(Pi, u)

F_vector = assemble(F)

# Set up the non-linear problem
u_up.vector()[:] = u.vector()[:] - gamma*F_vector[:]

Any help is highly appreciated.

It seems to me that translating a stand-alone code snippet is a great exercise to acquaint yourself with the FEniCSx syntax :wink:

The new syntax for the first 10 lines can be found on the first demo (Poisson equation — DOLFINx 0.9.0 documentation). The derivative is now ufl.derivative, I believe.

1 Like

The code i shared was the MWE. I did most of the basic translation for the whole code. But i was getting enough errors that i wanted a good starting point to proceed from. Ie if this code was written in FEniCSx, I could proceed from there and figure out the modifications. I want to be clear that i am trying to figure it out by myself on the side. Was hoping for a little bit of a kick in the right direction.

Let me share a bigger (yet simpler) MWE. The idea is to have an initial guess stored in U. I perform gradient descent from this initial guess, and i update this initial guess. I know there is a tutorial that uses Scipy. But my cluster doesnt have scipy installed and ive tried to get them to install it. If i run the tutorial as is, it doesn’t work. Still waiting. Hoping that updating my old code would work.

The bigger yet simpler MWE is shared below:

import ufl                                                                                           
from ufl import *                                                                                    
import dolfinx                                                                                       
from dolfinx import *                                                                                
from mpi4py import MPI                                                                               
from petsc4py import PETSc                                                                           
from petsc4py.PETSc import ScalarType                                                                
import numpy as np                                                                                   
                                                                                                     
#Parameters                                                                                          
gamma = float(0.01)                                                                                  
NN = int(100)      #No of iterations.
kappa =float (2.0) #Material parameter.                                                                                                                             
tol = float(0.000001)                                                                                
                                                                                                     
#Create mesh and define function space                                                               
Nx = int(np.ceil(1*100/kappa))                                                                      
tol_prev = 1 # setting this to 1 randomly.                                                           
                                                                                                     
domain = dolfinx.mesh.create_unit_square(MPI.COMM_WORLD, Nx, Nx)                                     
                                                                                                     
#The trial functions are the 2d vector u and the degree 2 tensor q                                   
V = dolfinx.fem.functionspace(domain, ("Lagrange", 1))                                               
u = ufl.TrialFunction(V)                                                                             
u_up = ufl.TrialFunction(V)                                                                          
                                                                                                     
#The energy                                                                                          
Pi = ( (1-u**2)**2/2 + (u.dx(0)/kappa)**2 + (u.dx(1)/kappa)**2 )*ufl.dx                              
                                                                                                     
Fu = ufl.derivative(Pi, u)                                                                           
                                                                                                     
Fu_vec  = assemble(Fu)                                                                               
                                                                                                     
u_up.vector()[:]  = u.vector()[:]  - gamma*Fu_vec[:]                                                 
                                                                                                     
tol_test = np.linalg.norm(np.asarray(Fu_vec.get_local()))                                            
                                                                                                     
##Save solution in a .xdmf file and for paraview.                                                    
var_out = XDMFFile('/<path to output>/GL-0.xdmf')                   
var_out.write_checkpoint(u, "u", 0, XDMFFile.Encoding.HDF5, False) #false means not appending to file
pvd_file = File("/project/psharma/ssen/code/FEniCSx/Ginzburg-Landau/GL-0.pvd") # for paraview.       
pvd_file << u                                                                                        
var_out.close()                                                                                      
                                                                                                     
pie = assemble(*( (1-u**2)**2/2 + (u.dx(0)/kappa)**2 + (u.dx(1)/kappa)**2)*dx )          
                       
c = plot(u)                                                                                          
plt.title(r"$u(x)$",fontsize=26)                                                                     
cb = plt.colorbar(c)                                                                                 
plt.savefig('/<path to output>/u(x).png')
cb.remove()

MPI.finalized()

I am getting an error form the ufl.derivative line saying

ValueError: Can only create arguments automatically for non-indexed coefficients.

got it. I’m taking down the original post. Let me spend some more time on it.

1 Like

Nonlinear forms shouldn’t use TrialFunctions, but functions, as pointed out in the aforementioned tutorial.
This is not new to DOLFINx, and was also a requirement in legacy FEniCS