Negative rate factors with reasonable temperatures
I am having issues with negative rate factors, and thus negative fluidities and viscosities, when working with somewhat complicated temperature profiles. I can try to work out a test case if needed, but this is the gist of what I get:

Perhaps the question is just whether it is safe to do something like A = max_value(small_number, A) in the rate_factor function or whether a better fix is needed.
I think this is happening as a result of a curving temperature profile (i.e. the coldest bit is at depth, and then when the rate factor gets projected onto the function space I somehow get negative values for the fluidity at the surface. The problem is reduced by increasing the vertical order of the function space for the rate factor, but it is not eliminated even at order 8.
To update, A = max_value(small_number, A) is not sufficient to fix this--it seems like it will put a floor on nodal values, but the function overall can take negative values at intermediate points (although maybe that is less of an issue depending on the function space of the velocity).
MWE follows--in this one, the problem is solved for vertical degree greater than 4, but that is not true in the general case.
import numpy as np
import icepack
from scipy.interpolate import RegularGridInterpolator
from matplotlib import pyplot as plt
res = 250
Lx = 1000
nx = Lx // res
mesh1d = firedrake.IntervalMesh(nx, Lx)
mesh = firedrake.ExtrudedMesh(mesh1d, layers=1)
x, ζ = firedrake.SpatialCoordinate(mesh)
QT = firedrake.FunctionSpace(mesh, "CG", 2, vfamily="CG", vdegree=4)
meshT = QT.mesh()
element = QT.ufl_element()
MV = firedrake.VectorFunctionSpace(meshT, element)
coordsT = firedrake.interpolate(meshT.coordinates, MV).dat.data_ro[:]
T = firedrake.Function(QT)
z_T = np.linspace(0, 1, 101)
x_T = np.array([-1, Lx + 1])
T_z = 240.0 + (z_T - 0.66) ** 2.0 * 74.0
T_arr = np.repeat(T_z, 2).reshape((101, 2))
T.dat.data[:] = RegularGridInterpolator((x_T, z_T), T_arr.T)(coordsT)
cmT = firedrake.tripcolor(T, num_sample_points=100)
plt.colorbar(cmT, label='T')
A = firedrake.project(firedrake.max_value(icepack.rate_factor(T), 1.0e-8), QT)
cmA = firedrake.tripcolor(A, num_sample_points=100, vmin=-5, vmax=5, cmap='bwr')
plt.colorbar(cmA, label='A')
plt.show()
Thanks for catching this! I suspect the problem is happening because the temperature crosses the slope break at -10C. That could certainly cause the interpolated or projected fluidity field to do something wrong. We might be able to work around this by interpolating with Bernstein polynomials. I'll see what I can figure out and get back to you.
I've run into similar (but not as severe) problems before and it has me wondering if I should implement a 2- or multi-layer model. Clearly using a single layer and high-degree polynomials can cause problems like what you're seeing or other ringing artifacts.