20#include "pism/stressbalance/blatter/Blatter.hh"
22#include "pism/basalstrength/basal_resistance.hh"
23#include "pism/rheology/FlowLaw.hh"
24#include "pism/util/node_types.hh"
26#include "pism/stressbalance/blatter/util/DataAccess.hh"
27#include "pism/stressbalance/blatter/util/grid_hierarchy.hh"
28#include "pism/util/fem/Quadrature.hh"
31namespace stressbalance {
38 const double *B_nodal,
50 element.
evaluate(u_nodal, u, u_x, u_y, u_z);
54 for (
unsigned int q = 0; q < element.
n_pts(); ++q) {
65 double gamma = (ux * ux + vy * vy + ux * vy +
66 0.25 * ((uy + vx) * (uy + vx) + uz * uz + vz * vz));
77 for (
int t = 0; t < Nk; ++t) {
78 auto psi = element.
chi(q, t);
79 for (
int s = t; s < Nk; ++s) {
80 auto phi = element.
chi(q, s);
84 gamma_u = 2.0 * ux *
phi.dx + vy *
phi.dx + 0.5 *
phi.dy * (uy + vx) + 0.5 * uz *
phi.dz,
85 gamma_v = 2.0 * vy *
phi.dy + ux *
phi.dy + 0.5 *
phi.dx * (uy + vx) + 0.5 * vz *
phi.dz;
89 eta_u = deta * gamma_u,
90 eta_v = deta * gamma_v;
95 F_u = (psi.dx * (4.0 * ux + 2.0 * vy) + psi.dy * (uy + vx) + psi.dz * uz),
96 F_v = (psi.dx * (uy + vx) + psi.dy * (4.0 * vy + 2.0 * ux) + psi.dz * vz);
100 F_uu = 4.0 * psi.dx *
phi.dx + psi.dy *
phi.dy + psi.dz *
phi.dz,
101 F_uv = 2.0 * psi.dx *
phi.dy + psi.dy *
phi.dx;
105 F_vu = 2.0 * psi.dy *
phi.dx + psi.dx *
phi.dy,
106 F_vv = 4.0 * psi.dy *
phi.dy + psi.dx *
phi.dx + psi.dz *
phi.dz;
108 K[t * 2 + 0][s * 2 + 0] += W * (eta * F_uu + eta_u * F_u);
109 K[t * 2 + 0][s * 2 + 1] += W * (eta * F_uv + eta_v * F_u);
110 K[t * 2 + 1][s * 2 + 0] += W * (eta * F_vu + eta_u * F_v);
111 K[t * 2 + 1][s * 2 + 1] += W * (eta * F_vv + eta_v * F_v);
124 const double *tauc_nodal,
125 const double *f_nodal,
140 for (
unsigned int q = 0; q < face.
n_pts(); ++q) {
143 bool grounded = floatation[q] <= 0.0;
144 double beta = 0.0, dbeta = 0.0;
150 for (
int t = 0; t < Nk; ++t) {
151 auto psi = face.
chi(q, t);
152 for (
int s = 0; s < Nk; ++s) {
153 auto phi = face.
chi(q, s);
155 double p = psi *
phi;
157 K[t * 2 + 0][s * 2 + 0] += W * p * (beta + dbeta * u[q].
u * u[q].
u);
158 K[t * 2 + 0][s * 2 + 1] += W * p * dbeta * u[q].
u * u[q].
v;
159 K[t * 2 + 1][s * 2 + 0] += W * p * dbeta * u[q].
v * u[q].
u;
160 K[t * 2 + 1][s * 2 + 1] += W * p * (beta + dbeta * u[q].
v * u[q].
v);
178 for (
int j = info.ys; j < info.ys + info.ym; j++) {
179 for (
int i = info.xs; i < info.xs + info.xm; i++) {
180 for (
int k = info.zs;
k < info.zs + info.zm;
k++) {
183 double identity[4] = {scaling.
u, 0, 0, scaling.
v};
189 ierr = MatSetValuesBlockedStencil(J, 1, &row, 1, &row, identity, ADD_VALUES);
190 PISM_CHK(ierr,
"MatSetValuesBlockedStencil");
201 const Vector2d ***X, Mat A, Mat J) {
205 PetscErrorCode ierr = MatZeroEntries(J);
208 ierr = MatSetOption(A, MAT_SUBSET_OFF_PROC_ENTRIES, PETSC_TRUE);
211 ierr = MatSetOption(J, MAT_NEW_NONZERO_LOCATION_ERR, PETSC_TRUE);
214 ierr = MatSetOption(J, MAT_SYMMETRIC, PETSC_TRUE);
217 ierr = PetscObjectSetName((PetscObject)J,
"bp_jacobian");
218 PISM_CHK(ierr,
"PetscObjectSetName");
223 assert(info.sw == 1);
234 dx, dy, x_min, y_min);
238 assert(element.
n_chi() <= Nk);
243 double floatation[Nk], bottom_elevation[Nk], ice_thickness[Nk];
244 double B_nodal[Nk], basal_yield_stress[Nk];
260 for (
int j = info.gys; j < info.gys + info.gym - 1; j++) {
261 for (
int i = info.gxs; i < info.gxs + info.gxm - 1; i++) {
276 for (
int k = info.gzs;
k < info.gzs + info.gzm - 1;
k++) {
280 double K[2*Nk][2*Nk];
281 memset(K, 0,
sizeof(K));
284 for (
int n = 0;
n < Nk; ++
n) {
287 z[
n] =
grid_z(bottom_elevation[
n], ice_thickness[
n], info.mz, I.k);
292 element.
reset(i, j,
k, z);
299 for (
int n = 0;
n < Nk; ++
n) {
315 for (
int n = 0;
n < Nk; ++
n) {
318 basal_yield_stress[
n] = P[I.j][I.i].tauc;
319 floatation[
n] = P[I.j][I.i].floatation;
331 for (
int t = 0; t < Nk; ++t) {
332 for (
int s = 0; s < t; ++s) {
333 K[t * 2 + 0][s * 2 + 0] = K[s * 2 + 0][t * 2 + 0];
334 K[t * 2 + 1][s * 2 + 0] = K[s * 2 + 0][t * 2 + 1];
335 K[t * 2 + 0][s * 2 + 1] = K[s * 2 + 1][t * 2 + 0];
336 K[t * 2 + 1][s * 2 + 1] = K[s * 2 + 1][t * 2 + 1];
347 ierr = MatAssemblyBegin(J, MAT_FINAL_ASSEMBLY);
PISM_CHK(ierr,
"MatAssemblyBegin");
348 ierr = MatAssemblyEnd(J, MAT_FINAL_ASSEMBLY);
PISM_CHK(ierr,
"MatAssemblyEnd");
350 ierr = MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY);
PISM_CHK(ierr,
"MatAssemblyBegin");
351 ierr = MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY);
PISM_CHK(ierr,
"MatAssemblyEnd");
362 MPI_Comm com = solver->
grid()->com;
364 SETERRQ(com, 1,
"A PISM callback failed");
std::shared_ptr< const Grid > grid() const
const std::shared_ptr< const Grid > m_grid
grid used by this component
virtual void drag_with_derivative(double tauc, double vx, double vy, double *drag, double *ddrag) const
Compute the drag coefficient and its derivative with respect to .
This class represents a 2D vector field (such as ice velocity) at a certain grid point.
Makes sure that we call begin_access() and end_access() for all accessed array::Arrays.
void nodal_values(T const *const *const *x_global, T *result) const
Extract nodal values for the element (i,j,k) from global array x_global into the element-local array ...
void add_contribution(const T *local, T ***y_global) const
Add the values of element-local contributions y to the global vector y_global.
GlobalIndex local_to_global(int i, int j, int k, unsigned int n) const
void evaluate(const T *x, T *vals, T *dx, T *dy, T *dz) const
Given nodal values, compute the values and partial derivatives at the quadrature points.
double weight(unsigned int q) const
Weight of the quadrature point q
const Germ & chi(unsigned int q, unsigned int k) const
unsigned int n_pts() const
Number of quadrature points.
double weight(unsigned int q) const
unsigned int n_pts() const
Number of quadrature points.
const double & chi(unsigned int q, unsigned int k) const
void evaluate(const T *x, T *result) const
void reset(int face, const double *z)
void reset(int i, int j, int k, const double *z)
void mark_row_invalid(unsigned int k)
Mark that the row corresponding to local degree of freedom k should not be updated when inserting int...
void mark_col_invalid(unsigned int k)
Mark that the column corresponding to local degree of freedom k should not be updated when inserting ...
void jacobian_dirichlet(const DMDALocalInfo &info, Parameters **P, Mat J)
virtual Vector2d u_bc(double x, double y, double z) const
fem::Q1Element3Face m_face4
double m_work[m_n_work][m_Nq]
static PetscErrorCode jacobian_callback(DMDALocalInfo *info, const Vector2d ***x, Mat A, Mat J, Blatter *solver)
fem::Q1Element3Face m_face100
static bool exterior_element(const int *node_type)
virtual void jacobian_f(const fem::Q1Element3 &element, const Vector2d *u_nodal, const double *B_nodal, double K[2 *fem::q13d::n_chi][2 *fem::q13d::n_chi])
static bool grounding_line(const double *F)
virtual void jacobian_basal(const fem::Q1Element3Face &face, const double *tauc_nodal, const double *f_nodal, const Vector2d *u_nodal, double K[2 *fem::q13d::n_chi][2 *fem::q13d::n_chi])
void compute_jacobian(DMDALocalInfo *info, const Vector2d ***x, Mat A, Mat J)
array::Array2D< Parameters > m_parameters
virtual bool dirichlet_node(const DMDALocalInfo &info, const fem::Element3::GlobalIndex &I)
Vector2d m_work2[m_n_work][m_Nq]
virtual void nodal_parameter_values(const fem::Q1Element3 &element, Parameters **P, int i, int j, int *node_type, double *bottom, double *thickness, double *surface, double *sea_level) const
const array::Vector1 & velocity() const
Get the thickness-advective 2D velocity.
std::shared_ptr< rheology::FlowLaw > m_flow_law
IceBasalResistancePlasticLaw * m_basal_sliding_law
#define PISM_CHK(errcode, name)
const int n_chi
Number of shape functions on a Q1 element.
double grid_z(double b, double H, int Mz, int k)
DMDALocalInfo grid_transpose(const DMDALocalInfo &input)
void handle_fatal_errors(MPI_Comm com)