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[:]
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.
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