# Create some expressions from the velocity functions
class UExpression(Expression):
  def eval(self, values, x):
    values[0] = u(x)
    
class VExpression(Expression):
  def eval(self, values, x):
    values[0] = v(x)
    
class WExpression(Expression):
  def eval(self, values, x):
    values[0] = w(x)

# Setup the model
model = model.Model()
model.set_mesh(mesh)
model.set_geometry(S, B, deform=True)

# Output the two meshes for comparison
print("Writing meshes")
File(out_dir + "full_mesh.pvd") << mesh_model.mesh
File(out_dir + "part_mesh.pvd") << model.mesh

# Apparently the smb is only used in the transient solver with free-surface  
# so adot isn't projected onto the mesh otherwise by the steady solver.
# In order to view adot in paraview, I'll just output it manually
adot_out = project(adot,model.Q)
File(out_dir + '/adot.pvd') << adot_out

print("Doing some stuff")
u_out = project(UExpression(),model.Q)
mesh = Mesh(in_dir + 'submesh.xdmf')
Q = FunctionSpace(mesh, 'CG', 1)

S = Function(Q)
B = Function(Q)

File(in_dir + 'S_s.xml') >> S
File(in_dir + 'B_s.xml') >> B

config = default_config()
config['output_path'] = out_dir
config['model_order'] = 'SSA'
config['use_dukowicz'] = False

model = model.Model(config)
model.set_mesh(mesh)
model.set_surface_and_bed(S, B)
model.initialize_variables()

model.init_beta(in_dir + 'beta_s.xml')
model.init_component_Ubar(in_dir + 'ubar_s.xml', in_dir + 'vbar_s.xml')
model.init_etabar(in_dir + 'etabar_s.xml')

T = solvers.StokesBalanceSolver(model, config)
T.solve()

Ubar = project(as_vector([model.ubar, model.vbar]))

model.save_pvd(model.eta, 'eta')
model.save_pvd(Ubar, 'Ubar')
model.save_xml(model.tau_id, 'tau_id')
# Now deform the refined mesh to match the surface and bed velocity
refined_mesh = Mesh(mesh_name + ".xml")

# Expression for the bed elevation
class BedExpression(Expression):
  def eval(self, values, x):
    # Get the z coordinate for this x value
    values[0] = bed(x[0],x[1])

# Expression for the surface elevation
class SurfaceExpression(Expression):
  def eval(self, values, x):
    # Get the surface value at a point
    #values[0] = surface(x[0],x[1])
    values[0] = surface(x[0],x[1])

model = model.Model()
# Set the mesh to the non-deformed anisotropic mesh
model.set_mesh(refined_mesh)

# Deform it to match the surface and bed geometry
model.set_geometry(SurfaceExpression(element = model.Q.ufl_element()), BedExpression(element = model.Q.ufl_element()), deform = False)
model.deform_mesh_to_geometry()

plot(model.mesh, interactive = True)
# Save the mesh
File(mesh_name + '_deformed.xml') << model.mesh
File(mesh_name + '_deformed.pvd') << model.mesh

print(len(model.mesh.coordinates()[:]))