Nonlinear diffusion equation: Periodic boundary conditions not satisfied (BUG?)

I'm in contact with Mathematica support about this. Meanwhile, I can offer a workaround. The code looks long below, but it is mostly just copied from above, with very few changes.

We need to define new functions PfemJacobian and PfemRHS to provide to FindRoot at the solution stage. These are alternatives to femJacobian and femRHS, provided in the documentation.

Needs["NDSolve`FEM`"];
PfemRHS[uV_?VectorQ] := 
  Block[{load, nonlinear, nonlinearLoad, nonlinearBCs, stiffnessDummy,
     dof}, NDSolve`SetSolutionDataComponent[sdU, "DependentVariables",
     uV];
   nonlinear = 
    DiscretizePDE[linLoadPDEC, methodData, sdU, "Nonlinear"];
   nonlinearLoad = nonlinear["LoadVector"];
   nonlinear = Null;
   load = linearLoad + nonlinearLoad;
   nonlinearLoad = Null;
   (*subtract the linear Robin boundary value*)
   load -= linearBCs["StiffnessMatrix"].uV;
   nonlinearBCs = 
    DiscretizeBoundaryConditions[initBCs, methodData, sdU, 
     "Nonlinear"];
   dof = Length[load];
   stiffnessDummy = SparseArray[{}, {dof, dof}];
   DeployPartialBoundaryConditions[{load, Null}, nonlinearBCs];
   DeployBoundaryConditions[{load, stiffnessDummy}, 
    linearBCsPartial];
   load = -load;
   Normal[Flatten[load]]];
PfemJacobian[uV_?VectorQ] := 
  Block[{stiffness, nonlinear, nonlinearStiffness, nonlinearBCs, 
    loadDummy, dof}, 
   NDSolve`SetSolutionDataComponent[sdU, "DependentVariables", uV];
   nonlinear = 
    DiscretizePDE[linStiffnessPDEC, methodData, sdU, "Nonlinear"];
   nonlinearStiffness = nonlinear["StiffnessMatrix"];
   nonlinear = Null;
   stiffness = linearStiffness + nonlinearStiffness;
   nonlinearStiffness = Null;
   nonlinearBCs = 
    DiscretizeBoundaryConditions[initBCs, methodData, sdU, 
     "Nonlinear"];
   dof = Length[stiffness];
   loadDummy = SparseArray[{}, {dof, 1}];
   DeployPartialBoundaryConditions[{Null, stiffness}, nonlinearBCs];
   DeployBoundaryConditions[{loadDummy, stiffness}, 
    linearBCsPartial];
   stiffness];

Here is an explanation. The only difference with femRHS and femJacobian is that a second call to DeployPartialBoundaryConditions is replaced with a call to DeployBoundaryConditions (traditional way to deploy BCs when solving Linear PDEs), with globally defined discretized BC data named linearBCsPartial.

By inspecting the behavior of DeployPartialBoundaryConditions I concluded that it was not implementing the expected DirichletCondition because it had already been enforced on the seed data. Each iteration of the solver produces a change to the previous solution, and this change should have a zero Dirichlet condition on the target boundary, if the new solution is going to satisfy the desired Dirichlet condition of the full problem.

With these definitions, we continue mostly as before. I repeat the code from above so it is self-contained in this post. Defining the problem as before:

c = 1/Sqrt[(1 + Grad[u[x, y], {x, y}].Grad[u[x, y], {x, y}])];
Cu = {{{{c, 0}, {0, c}}}};
mesh = ToElementMesh[FullRegion[2], {{-1, 1}, {-1, 1}}];
uA[x_, y_] = y; (* Target solution *)

Now we define several separated boundary conditions

bcs = {DirichletCondition[u[x, y] == uA[x, y], -1 < x < 1], 
   PeriodicBoundaryCondition[u[x, y], x == 1, # - {2, 0} &]};
bcsDirichlet = {DirichletCondition[u[x, y] == uA[x, y], -1 < x < 1]};
bcsPartial = {DirichletCondition[u[x, y] == 0, -1 < x < 1], 
   PeriodicBoundaryCondition[u[x, y], x == 1, # - {2, 0} &]};

Note the zero Dirichlet condition for bcsPartial. Continuing as before:

uSeed[x_, y_] = (1 - 0.8 (1 - y^2)) uA[x, y];
iSeeding = {uSeed[x, y]};
vd = NDSolve`VariableData[{"DependentVariables", 
     "Space"} -> {{u}, {x, y}}];
sd = NDSolve`SolutionData[{"DependentVariables", 
     "Space"} -> {iSeeding, ToNumericalRegion[mesh]}];
coefficients = {"DiffusionCoefficients" -> Cu};
initCoeffs = InitializePDECoefficients[vd, sd, coefficients];

Here are the new statements to initialize the separated boundary conditions.

initBCs = InitializeBoundaryConditions[vd, sd, bcs] ;
initBCsDirichlet = 
  InitializeBoundaryConditions[vd, sd, bcsDirichlet] ;
initBCsPartial = InitializeBoundaryConditions[vd, sd, bcsPartial] ;

Continuing...

methodData = 
  InitializePDEMethodData[vd, sd, Method -> {"FiniteElement"}];
linearizedPDECoeffs = LinearizePDECoefficients[initCoeffs, vd, sd];
{linLoadPDEC, linStiffnessPDEC, linDampingPDEC, linMassPDEC} = 
  SplitPDECoefficients[linearizedPDECoeffs, vd, sd];
sdU = EvaluateInitialSeeding[methodData, vd, sd];
linear = DiscretizePDE[linearizedPDECoeffs, methodData, sdU]; 
{linearLoad, linearStiffness, linearDamping, linearMass} = 
     linear["SystemMatrices"];

Here are the new statements to discretize the separated boundary conditions

linearBCs = DiscretizeBoundaryConditions[initBCs, methodData, sdU];
linearBCsDirichlet = DiscretizeBoundaryConditions[initBCsDirichlet, methodData, sdU];
linearBCsPartial = DiscretizeBoundaryConditions[initBCsPartial, methodData, sdU];

Because linearBCsDirichlet contains only the Dirichlet conditions, we can deploy this part using DeployDirichletConditions without worrying about ill effects due to PeriodicBoundaryCondition. (Although in this case it is not needed because the seed already satisfies the Dirichlet conditions.)

seed = NDSolve`SolutionDataComponent[sdU, "DependentVariables"];
DeployDirichletConditions[seed, linearBCsDirichlet];

Finally, to solve, we call FindRoot with the new functions defined above PfemRHS and PfemJacobian.

root = U /. 
   FindRoot[PfemRHS[U], {U, seed}, Jacobian -> PfemJacobian[U], 
    Method -> {"AffineCovariantNewton"}];
NDSolve`SetSolutionDataComponent[sdU, "DependentVariables", root];
{uf} = ProcessPDESolutions[methodData, sdU];
Plot3D[uf[x, y], Element[{x, y}, mesh]]

correct solution

I'm not sure how general this workaround is, but it may be helpful for some.


As alternative method we can use linear FEM to solve this problem

uSeed[x_, y_] = (1 - 0.3 (1 - x^2) (1 - y^2)) uA[x, y]; 
U[0][x_, y_] := uSeed[x, y]; n = 4;
Do[c1 = 1/
   Sqrt[(1 + 
      Grad[U[i - 1][x, y], {x, y}].Grad[U[i - 1][x, y], {x, y}])];
 Cu1 = {{{{c1, 0}, {0, c1}}}};
 eqn1 = {Inactive[Div][
     Cu1[[1, 1]].Inactive[Grad][u[x, y], {x, y}], {x, y}] == 0};
 U[i] = NDSolveValue[{eqn1, {DirichletCondition[
      u[x, y] == uA[x, y], -1 < x < 1], 
     PeriodicBoundaryCondition[u[x, y], x == 1, # - {2, 0} &]}}, u, 
   Element[{x, y}, mesh]];, {i, 1, n}]

Visualization of numerical solution and error on every step

Table[{Plot3D[U[i][x, y], Element[{x, y}, mesh], 
   AxesLabel -> Automatic, PlotRange -> All], 
  Plot3D[U[i][x, y] - uA[x, y], Element[{x, y}, mesh], 
   AxesLabel -> Automatic, PlotRange -> All, PlotLabel -> i]}, {i, n}]

Figure 1 As Figure 1 shows the error not decreasing with number of iteration increasing for i>2. Unfortunately this is the problem of compatibility of DirichletCondition[] and PeriodicBoundaryCondition[]. For instance, if we plot error=uf[x,y]-y for numerical solution from Will.Mo answer, then we got this picture with the same big error in the corner points: Figure 2 From the other side, if we exclude PeriodicBoundaryCondition[] from the code above, then we got higher precision numerical solution for n=30

Do[c1 = 1/
   Sqrt[(1 + 
      Grad[U[i - 1][x, y], {x, y}].Grad[U[i - 1][x, y], {x, y}])];
 Cu1 = {{{{c1, 0}, {0, c1}}}};
 eqn1 = {Inactive[Div][
     Cu1[[1, 1]].Inactive[Grad][u[x, y], {x, y}], {x, y}] == 0};
 U[i] = NDSolveValue[{eqn1, 
    DirichletCondition[
     u[x, y] == uA[x, y], (y == -1 || y == 1) && -1 <= x <= 1]}, u, 
   Element[{x, y}, mesh]];, {i, 1, 30}]

Table[Plot3D[U[i][x, y] - uA[x, y], Element[{x, y}, mesh], 
  AxesLabel -> Automatic, PlotRange -> All, PlotLabel -> i], {i, 25, 
  30}]
 

Figure 3