Hello, I wonder if I correctly understantd these functions. Suppose that,

the red basis function is owned by process 1.

the green basis function is owned by process 2.

To calculate the contribution to the right hand side (rhs), we should know the informations of adjacent cells, which is stored on different processes. And these cells are called ghost cells. Fenics does not handle these automatically, we have to deal with these ghost cells manually.

**b.local_Form()** returns the local part of b, that is, a part of b that is owned by a process. By the way, can we just set **b.array = 0** ? Does the code

```
with b.localForm() as loc_b:
loc_b.set(0)
```

just reduce the computational cost ?

After we called

```
assemble_vector(b, linear_form)
```

the local part of b is calculated without considering the contributations from the ghost cells. So we need to use ghost_Update function

```
# Apply Dirichlet boundary condition to the vector
apply_lifting(b, [bilinear_form], [[bc]])
b.ghostUpdate(addv=PETSc.InsertMode.ADD_VALUES, mode=PETSc.ScatterMode.REVERSE)
set_bc(b, [bc])
```

This can be taken as a reverse operation of MPI.scatter. And we use **set_bc** because **ghost_Update** may destroy the dirichlet boundary conditionďĽźAfter we solve the linear system, we use **scatter_forward**, to let the ghost cells contain the correct values

```
# Solve linear problem
solver.solve(b, uh.vector)
uh.x.scatter_forward()
```

By the way, will the API of Fenics change a lot in the future? I tried the codes in some old tutorials and they can run, because the names of many functions or modules are changed.