Hi dokken, sure here is a minimal example
import dolfinx
import ufl
import numpy as np
from mpi4py import MPI
from dolfinx import fem
from petsc4py import PETSc
from dolfinx.fem import Function, Constant, functionspace, form
from dolfinx.fem.petsc import assemble_matrix, assemble_vector
from dolfinx import mesh
mesh = mesh.create_box(MPI.COMM_WORLD, [np.array([0, 0, 0]), np.array([10, 10, 10])], [10, 10, 10])
V_scalar = fem.functionspace(mesh, ("Lagrange", 1))
V_vec = fem.functionspace(mesh, ("Lagrange", 1, (mesh.geometry.dim,)))
vel_0 = fem.Function(V_vec)
PHI = fem.Function(V_scalar )
v = ufl.TestFunction(V_scalar )
u = ufl.TrialFunction(V_scalar )
def RHS(vel_0):
H_vel = fem.Function(V_vec)
rhs = fem.form(ufl.inner(ufl.grad(v),vel_0 ) * ufl.dx)
a = fem.form(ufl.inner(ufl.grad(v), ufl.grad(u)) * ufl.dx)
A = fem.petsc.assemble_matrix(a)
A.assemble()
b = fem.petsc.create_vector(rhs)
fem.petsc.assemble_vector(b, rhs)
b.ghostUpdate(PETSc.InsertMode.ADD_VALUES, PETSc.ScatterMode.REVERSE)
solver = PETSc.KSP().create(mesh.comm)
solver.setOperators(A)
solver.solve(b, PHI.x.petsc_vec)
PHI.x.scatter_forward()
# for simplicity we use interpolate
Gradient= ufl.grad(PHI)
expr = fem.Expression(Gradient, V_vec.element.interpolation_points())
H_vel.interpolate(expr)
return H_vel
# Initial condicion:
xyz = mesh.geometry.x
dim = mesh.geometry.x.shape[0]
vel0 = np.zeros((dim,3))
for i in range(dim):
xx = xyz[i,0]
yy = xyz[i,1]
zz = xyz[i,2]
norm = np.sqrt(xx*xx+yy*yy+0.2*0.2)
vel0[i,0] = xx/norm
vel0[i,1] = yy/norm
vel0[i,2] = 0.5/norm
vel_0.x.array[:] = vel0.flatten()
# 1. The idea now is to use this function in some external time integrator like SciPy. For this, I need to use just the local part of the solution (without ghost), the first evaluation we have that:
start, end = V_vec.dofmap.index_map.local_range
rhs_initial = RHS(vel_0).x.array[start:end]
vel_0_initial = vel_0.x.array[start:end]
# 2. Now, we can suppose that obtain a new vector vel_0 from the integrator routines, we need to use this to evaluate the RHS function again. To do that, I think that is necesary to contruct a new vector function that contains also the local and the ghost part. For simplicity, suppose that
vel_0_new = vel_0 (considered concatenate and flatten).
vel_0_new = fem.Function(V_vec)
vel_0_new.x.array[start:end] = vel_0.x.array[start:end]
vel_0_new.x.scatter_forward()
# then for the second evaluation,we should use
vel_0_second = vel_0_new.x.array[start:end]
rhs_second = RHS(vel_0_new).x.array[start:end]
print("initial", mesh.comm.rank, np.sort(rhs_initial)[0:10])
print("second step", mesh.comm.rank, np.sort(rhs_second)[0:10])
# We can see that rhs_initial and rhs_second are differents.
Aditionally, I noticed that vel_0_new.x.array[start:end] is not a multiple of 3. Does this mean different ranks share different components of the vector associated with a node?. If you wanted to perform vector operations like inner or vector products, how could you do it?
thanks