MFEM  v4.2.0
Finite element discretization library
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Pages
bilininteg.cpp
Go to the documentation of this file.
1 // Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced
2 // at the Lawrence Livermore National Laboratory. All Rights reserved. See files
3 // LICENSE and NOTICE for details. LLNL-CODE-806117.
4 //
5 // This file is part of the MFEM library. For more information and source code
6 // availability visit https://mfem.org.
7 //
8 // MFEM is free software; you can redistribute it and/or modify it under the
9 // terms of the BSD-3 license. We welcome feedback and contributions, see file
10 // CONTRIBUTING.md for details.
11 
12 // Implementation of Bilinear Form Integrators
13 
14 #include "fem.hpp"
15 #include <cmath>
16 #include <algorithm>
17 
18 using namespace std;
19 
20 namespace mfem
21 {
22 
23 void BilinearFormIntegrator::AssemblePA(const FiniteElementSpace&)
24 {
25  mfem_error ("BilinearFormIntegrator::AssemblePA(...)\n"
26  " is not implemented for this class.");
27 }
28 
29 void BilinearFormIntegrator::AssemblePA(const FiniteElementSpace&,
30  const FiniteElementSpace&)
31 {
32  mfem_error ("BilinearFormIntegrator::AssemblePA(...)\n"
33  " is not implemented for this class.");
34 }
35 
36 void BilinearFormIntegrator::AssemblePAInteriorFaces(const FiniteElementSpace&)
37 {
38  mfem_error ("BilinearFormIntegrator::AssemblePAInteriorFaces(...)\n"
39  " is not implemented for this class.");
40 }
41 
42 void BilinearFormIntegrator::AssemblePABoundaryFaces(const FiniteElementSpace&)
43 {
44  mfem_error ("BilinearFormIntegrator::AssemblePABoundaryFaces(...)\n"
45  " is not implemented for this class.");
46 }
47 
48 void BilinearFormIntegrator::AssembleDiagonalPA(Vector &)
49 {
50  mfem_error ("BilinearFormIntegrator::AssembleDiagonalPA(...)\n"
51  " is not implemented for this class.");
52 }
53 
54 void BilinearFormIntegrator::AssembleEA(const FiniteElementSpace &fes,
55  Vector &emat,
56  const bool add)
57 {
58  mfem_error ("BilinearFormIntegrator::AssembleEA(...)\n"
59  " is not implemented for this class.");
60 }
61 
62 void BilinearFormIntegrator::AssembleEAInteriorFaces(const FiniteElementSpace
63  &fes,
64  Vector &ea_data_int,
65  Vector &ea_data_ext,
66  const bool add)
67 {
68  mfem_error ("BilinearFormIntegrator::AssembleEAInteriorFaces(...)\n"
69  " is not implemented for this class.");
70 }
71 
72 void BilinearFormIntegrator::AssembleEABoundaryFaces(const FiniteElementSpace
73  &fes,
74  Vector &ea_data_bdr,
75  const bool add)
76 {
77  mfem_error ("BilinearFormIntegrator::AssembleEABoundaryFaces(...)\n"
78  " is not implemented for this class.");
79 }
80 
81 void BilinearFormIntegrator::AssembleDiagonalPA_ADAt(const Vector &, Vector &)
82 {
83  MFEM_ABORT("BilinearFormIntegrator::AssembleDiagonalPA_ADAt(...)\n"
84  " is not implemented for this class.");
85 }
86 
87 void BilinearFormIntegrator::AddMultPA(const Vector &, Vector &) const
88 {
89  mfem_error ("BilinearFormIntegrator::MultAssembled(...)\n"
90  " is not implemented for this class.");
91 }
92 
93 void BilinearFormIntegrator::AddMultTransposePA(const Vector &, Vector &) const
94 {
95  mfem_error ("BilinearFormIntegrator::MultAssembledTranspose(...)\n"
96  " is not implemented for this class.");
97 }
98 
99 void BilinearFormIntegrator::AssembleMF(const FiniteElementSpace &fes)
100 {
101  mfem_error ("BilinearFormIntegrator::AssembleMF(...)\n"
102  " is not implemented for this class.");
103 }
104 
105 void BilinearFormIntegrator::AddMultMF(const Vector &, Vector &) const
106 {
107  mfem_error ("BilinearFormIntegrator::AddMultMF(...)\n"
108  " is not implemented for this class.");
109 }
110 
111 void BilinearFormIntegrator::AddMultTransposeMF(const Vector &, Vector &) const
112 {
113  mfem_error ("BilinearFormIntegrator::AddMultTransposeMF(...)\n"
114  " is not implemented for this class.");
115 }
116 
117 void BilinearFormIntegrator::AssembleDiagonalMF(Vector &)
118 {
119  mfem_error ("BilinearFormIntegrator::AssembleDiagonalMF(...)\n"
120  " is not implemented for this class.");
121 }
122 
123 void BilinearFormIntegrator::AssembleElementMatrix (
125  DenseMatrix &elmat )
126 {
127  mfem_error ("BilinearFormIntegrator::AssembleElementMatrix(...)\n"
128  " is not implemented for this class.");
129 }
130 
131 void BilinearFormIntegrator::AssembleElementMatrix2 (
132  const FiniteElement &el1, const FiniteElement &el2,
134 {
135  mfem_error ("BilinearFormIntegrator::AssembleElementMatrix2(...)\n"
136  " is not implemented for this class.");
137 }
138 
139 void BilinearFormIntegrator::AssembleFaceMatrix (
140  const FiniteElement &el1, const FiniteElement &el2,
142 {
143  mfem_error ("BilinearFormIntegrator::AssembleFaceMatrix(...)\n"
144  " is not implemented for this class.");
145 }
146 
147 void BilinearFormIntegrator::AssembleFaceMatrix(
148  const FiniteElement &trial_face_fe, const FiniteElement &test_fe1,
150  DenseMatrix &elmat)
151 {
152  MFEM_ABORT("AssembleFaceMatrix (mixed form) is not implemented for this"
153  " Integrator class.");
154 }
155 
156 void BilinearFormIntegrator::AssembleElementVector(
157  const FiniteElement &el, ElementTransformation &Tr, const Vector &elfun,
158  Vector &elvect)
159 {
160  // Note: This default implementation is general but not efficient
161  DenseMatrix elmat;
162  AssembleElementMatrix(el, Tr, elmat);
163  elvect.SetSize(elmat.Height());
164  elmat.Mult(elfun, elvect);
165 }
166 
167 void BilinearFormIntegrator::AssembleFaceVector(
168  const FiniteElement &el1, const FiniteElement &el2,
169  FaceElementTransformations &Tr, const Vector &elfun, Vector &elvect)
170 {
171  // Note: This default implementation is general but not efficient
172  DenseMatrix elmat;
173  AssembleFaceMatrix(el1, el2, Tr, elmat);
174  elvect.SetSize(elmat.Height());
175  elmat.Mult(elfun, elvect);
176 }
177 
178 
179 void TransposeIntegrator::AssembleElementMatrix (
181 {
182  bfi -> AssembleElementMatrix (el, Trans, bfi_elmat);
183  // elmat = bfi_elmat^t
184  elmat.Transpose (bfi_elmat);
185 }
186 
187 void TransposeIntegrator::AssembleElementMatrix2 (
188  const FiniteElement &trial_fe, const FiniteElement &test_fe,
190 {
191  bfi -> AssembleElementMatrix2 (test_fe, trial_fe, Trans, bfi_elmat);
192  // elmat = bfi_elmat^t
193  elmat.Transpose (bfi_elmat);
194 }
195 
196 void TransposeIntegrator::AssembleFaceMatrix (
197  const FiniteElement &el1, const FiniteElement &el2,
199 {
200  bfi -> AssembleFaceMatrix (el1, el2, Trans, bfi_elmat);
201  // elmat = bfi_elmat^t
202  elmat.Transpose (bfi_elmat);
203 }
204 
205 void LumpedIntegrator::AssembleElementMatrix (
207 {
208  bfi -> AssembleElementMatrix (el, Trans, elmat);
209  elmat.Lump();
210 }
211 
212 void InverseIntegrator::AssembleElementMatrix(
214 {
215  integrator->AssembleElementMatrix(el, Trans, elmat);
216  elmat.Invert();
217 }
218 
219 void SumIntegrator::AssembleElementMatrix(
221 {
222  MFEM_ASSERT(integrators.Size() > 0, "empty SumIntegrator.");
223 
224  integrators[0]->AssembleElementMatrix(el, Trans, elmat);
225  for (int i = 1; i < integrators.Size(); i++)
226  {
227  integrators[i]->AssembleElementMatrix(el, Trans, elem_mat);
228  elmat += elem_mat;
229  }
230 }
231 
232 SumIntegrator::~SumIntegrator()
233 {
234  if (own_integrators)
235  {
236  for (int i = 0; i < integrators.Size(); i++)
237  {
238  delete integrators[i];
239  }
240  }
241 }
242 
243 void MixedScalarIntegrator::AssembleElementMatrix2(
244  const FiniteElement &trial_fe, const FiniteElement &test_fe,
246 {
247  MFEM_ASSERT(this->VerifyFiniteElementTypes(trial_fe, test_fe),
248  this->FiniteElementTypeFailureMessage());
249 
250  int trial_nd = trial_fe.GetDof(), test_nd = test_fe.GetDof(), i;
251  bool same_shapes = same_calc_shape && (&trial_fe == &test_fe);
252 
253 #ifdef MFEM_THREAD_SAFE
254  Vector test_shape(test_nd);
255  Vector trial_shape;
256 #else
257  test_shape.SetSize(test_nd);
258 #endif
259  if (same_shapes)
260  {
261  trial_shape.NewDataAndSize(test_shape.GetData(), trial_nd);
262  }
263  else
264  {
265  trial_shape.SetSize(trial_nd);
266  }
267 
268  elmat.SetSize(test_nd, trial_nd);
269 
270  const IntegrationRule *ir = IntRule;
271  if (ir == NULL)
272  {
273  int ir_order = this->GetIntegrationOrder(trial_fe, test_fe, Trans);
274  ir = &IntRules.Get(trial_fe.GetGeomType(), ir_order);
275  }
276 
277  elmat = 0.0;
278  for (i = 0; i < ir->GetNPoints(); i++)
279  {
280  const IntegrationPoint &ip = ir->IntPoint(i);
281  Trans.SetIntPoint(&ip);
282 
283  this->CalcTestShape(test_fe, Trans, test_shape);
284  this->CalcTrialShape(trial_fe, Trans, trial_shape);
285 
286  double w = Trans.Weight() * ip.weight;
287 
288  if (Q)
289  {
290  w *= Q->Eval(Trans, ip);
291  }
292  AddMult_a_VWt(w, test_shape, trial_shape, elmat);
293  }
294 #ifndef MFEM_THREAD_SAFE
295  if (same_shapes)
296  {
297  trial_shape.SetDataAndSize(NULL, 0);
298  }
299 #endif
300 }
301 
302 void MixedVectorIntegrator::AssembleElementMatrix2(
303  const FiniteElement &trial_fe, const FiniteElement &test_fe,
305 {
306  MFEM_ASSERT(this->VerifyFiniteElementTypes(trial_fe, test_fe),
307  this->FiniteElementTypeFailureMessage());
308 
309  int trial_nd = trial_fe.GetDof(), test_nd = test_fe.GetDof(), i;
310  int spaceDim = Trans.GetSpaceDim();
311  bool same_shapes = same_calc_shape && (&trial_fe == &test_fe);
312 
313 #ifdef MFEM_THREAD_SAFE
314  Vector V(VQ ? VQ->GetVDim() : 0);
315  Vector D(DQ ? DQ->GetVDim() : 0);
316  DenseMatrix M(MQ ? MQ->GetVDim() : 0, MQ ? MQ->GetVDim() : 0);
317  DenseMatrix test_shape(test_nd, spaceDim);
318  DenseMatrix trial_shape;
319  DenseMatrix test_shape_tmp(test_nd, spaceDim);
320 #else
321  V.SetSize(VQ ? VQ->GetVDim() : 0);
322  D.SetSize(DQ ? DQ->GetVDim() : 0);
323  M.SetSize(MQ ? MQ->GetVDim() : 0, MQ ? MQ->GetVDim() : 0);
324  test_shape.SetSize(test_nd, spaceDim);
325  test_shape_tmp.SetSize(test_nd, spaceDim);
326 #endif
327  if (same_shapes)
328  {
329  trial_shape.Reset(test_shape.Data(), trial_nd, spaceDim);
330  }
331  else
332  {
333  trial_shape.SetSize(trial_nd, spaceDim);
334  }
335 
336  elmat.SetSize(test_nd, trial_nd);
337 
338  const IntegrationRule *ir = IntRule;
339  if (ir == NULL)
340  {
341  int ir_order = this->GetIntegrationOrder(trial_fe, test_fe, Trans);
342  ir = &IntRules.Get(trial_fe.GetGeomType(), ir_order);
343  }
344 
345  elmat = 0.0;
346  for (i = 0; i < ir->GetNPoints(); i++)
347  {
348  const IntegrationPoint &ip = ir->IntPoint(i);
349  Trans.SetIntPoint(&ip);
350 
351  this->CalcTestShape(test_fe, Trans, test_shape);
352  if (!same_shapes)
353  {
354  this->CalcTrialShape(trial_fe, Trans, trial_shape);
355  }
356 
357  double w = Trans.Weight() * ip.weight;
358 
359  if (MQ)
360  {
361  MQ->Eval(M, Trans, ip);
362  M *= w;
363  Mult(test_shape, M, test_shape_tmp);
364  AddMultABt(test_shape_tmp, trial_shape, elmat);
365  }
366  else if (DQ)
367  {
368  DQ->Eval(D, Trans, ip);
369  D *= w;
370  AddMultADBt(test_shape, D, trial_shape, elmat);
371  }
372  else if (VQ)
373  {
374  VQ->Eval(V, Trans, ip);
375  V *= w;
376  for (int j=0; j<test_nd; j++)
377  {
378  test_shape_tmp(j,0) = test_shape(j,1) * V(2) -
379  test_shape(j,2) * V(1);
380  test_shape_tmp(j,1) = test_shape(j,2) * V(0) -
381  test_shape(j,0) * V(2);
382  test_shape_tmp(j,2) = test_shape(j,0) * V(1) -
383  test_shape(j,1) * V(0);
384  }
385  AddMultABt(test_shape_tmp, trial_shape, elmat);
386  }
387  else
388  {
389  if (Q)
390  {
391  w *= Q -> Eval (Trans, ip);
392  }
393  if (same_shapes)
394  {
395  AddMult_a_AAt (w, test_shape, elmat);
396  }
397  else
398  {
399  AddMult_a_ABt (w, test_shape, trial_shape, elmat);
400  }
401  }
402  }
403 #ifndef MFEM_THREAD_SAFE
404  if (same_shapes)
405  {
406  trial_shape.ClearExternalData();
407  }
408 #endif
409 }
410 
411 void MixedScalarVectorIntegrator::AssembleElementMatrix2(
412  const FiniteElement &trial_fe, const FiniteElement &test_fe,
414 {
415  MFEM_ASSERT(this->VerifyFiniteElementTypes(trial_fe, test_fe),
416  this->FiniteElementTypeFailureMessage());
417 
418  const FiniteElement * vec_fe = transpose?&trial_fe:&test_fe;
419  const FiniteElement * sca_fe = transpose?&test_fe:&trial_fe;
420 
421  int trial_nd = trial_fe.GetDof(), test_nd = test_fe.GetDof(), i;
422  int sca_nd = sca_fe->GetDof();
423  int vec_nd = vec_fe->GetDof();
424  int spaceDim = Trans.GetSpaceDim();
425  double vtmp;
426 
427 #ifdef MFEM_THREAD_SAFE
428  Vector V(VQ ? VQ->GetVDim() : 0);
429  DenseMatrix vshape(vec_nd, spaceDim);
430  Vector shape(sca_nd);
431  Vector vshape_tmp(vec_nd);
432 #else
433  V.SetSize(VQ ? VQ->GetVDim() : 0);
434  vshape.SetSize(vec_nd, spaceDim);
435  shape.SetSize(sca_nd);
436  vshape_tmp.SetSize(vec_nd);
437 #endif
438 
439  Vector V_test(transpose?shape.GetData():vshape_tmp.GetData(),test_nd);
440  Vector W_trial(transpose?vshape_tmp.GetData():shape.GetData(),trial_nd);
441 
442  elmat.SetSize(test_nd, trial_nd);
443 
444  const IntegrationRule *ir = IntRule;
445  if (ir == NULL)
446  {
447  int ir_order = this->GetIntegrationOrder(trial_fe, test_fe, Trans);
448  ir = &IntRules.Get(trial_fe.GetGeomType(), ir_order);
449  }
450 
451  elmat = 0.0;
452  for (i = 0; i < ir->GetNPoints(); i++)
453  {
454  const IntegrationPoint &ip = ir->IntPoint(i);
455  Trans.SetIntPoint(&ip);
456 
457  this->CalcShape(*sca_fe, Trans, shape);
458  this->CalcVShape(*vec_fe, Trans, vshape);
459 
460  double w = Trans.Weight() * ip.weight;
461 
462  VQ->Eval(V, Trans, ip);
463  V *= w;
464 
465  if ( vec_fe->GetDim() == 2 && cross_2d )
466  {
467  vtmp = V[0];
468  V[0] = -V[1];
469  V[1] = vtmp;
470  }
471 
472  vshape.Mult(V,vshape_tmp);
473 
474  AddMultVWt(V_test, W_trial, elmat);
475  }
476 }
477 
478 
479 void GradientIntegrator::AssembleElementMatrix2(
480  const FiniteElement &trial_fe, const FiniteElement &test_fe,
482 {
483  int dim = test_fe.GetDim();
484  int trial_dof = trial_fe.GetDof();
485  int test_dof = test_fe.GetDof();
486  double c;
487  Vector d_col;
488 
489  dshape.SetSize(trial_dof, dim);
490  gshape.SetSize(trial_dof, dim);
491  Jadj.SetSize(dim);
492  shape.SetSize(test_dof);
493  elmat.SetSize(dim * test_dof, trial_dof);
494 
495  const IntegrationRule *ir = IntRule ? IntRule : &GetRule(trial_fe, test_fe,
496  Trans);
497 
498  elmat = 0.0;
499  elmat_comp.SetSize(test_dof, trial_dof);
500 
501  for (int i = 0; i < ir->GetNPoints(); i++)
502  {
503  const IntegrationPoint &ip = ir->IntPoint(i);
504 
505  trial_fe.CalcDShape(ip, dshape);
506  test_fe.CalcShape(ip, shape);
507 
508  Trans.SetIntPoint(&ip);
509  CalcAdjugate(Trans.Jacobian(), Jadj);
510 
511  Mult(dshape, Jadj, gshape);
512 
513  c = ip.weight;
514  if (Q)
515  {
516  c *= Q->Eval(Trans, ip);
517  }
518  shape *= c;
519 
520  for (int d = 0; d < dim; ++d)
521  {
522  gshape.GetColumnReference(d, d_col);
523  MultVWt(shape, d_col, elmat_comp);
524  for (int jj = 0; jj < trial_dof; ++jj)
525  {
526  for (int ii = 0; ii < test_dof; ++ii)
527  {
528  elmat(d * test_dof + ii, jj) += elmat_comp(ii, jj);
529  }
530  }
531  }
532  }
533 }
534 
535 const IntegrationRule &GradientIntegrator::GetRule(const FiniteElement
536  &trial_fe,
537  const FiniteElement &test_fe,
539 {
540  int order = Trans.OrderGrad(&trial_fe) + test_fe.GetOrder() + Trans.OrderJ();
541  return IntRules.Get(trial_fe.GetGeomType(), order);
542 }
543 
544 
545 void DiffusionIntegrator::AssembleElementMatrix
547  DenseMatrix &elmat )
548 {
549  int nd = el.GetDof();
550  int dim = el.GetDim();
551  int spaceDim = Trans.GetSpaceDim();
552  bool square = (dim == spaceDim);
553  double w;
554 
555 #ifdef MFEM_THREAD_SAFE
556  DenseMatrix dshape(nd,dim), dshapedxt(nd,spaceDim), invdfdx(dim,spaceDim);
557  Vector D(VQ ? VQ->GetVDim() : 0);
558 #else
559  dshape.SetSize(nd,dim);
560  dshapedxt.SetSize(nd,spaceDim);
561  invdfdx.SetSize(dim,spaceDim);
562  D.SetSize(VQ ? VQ->GetVDim() : 0);
563 #endif
564  elmat.SetSize(nd);
565 
566  const IntegrationRule *ir = IntRule ? IntRule : &GetRule(el, el);
567 
568  elmat = 0.0;
569  for (int i = 0; i < ir->GetNPoints(); i++)
570  {
571  const IntegrationPoint &ip = ir->IntPoint(i);
572  el.CalcDShape(ip, dshape);
573 
574  Trans.SetIntPoint(&ip);
575  w = Trans.Weight();
576  w = ip.weight / (square ? w : w*w*w);
577  // AdjugateJacobian = / adj(J), if J is square
578  // \ adj(J^t.J).J^t, otherwise
579  Mult(dshape, Trans.AdjugateJacobian(), dshapedxt);
580  if (MQ)
581  {
582  MQ->Eval(invdfdx, Trans, ip);
583  invdfdx *= w;
584  Mult(dshapedxt, invdfdx, dshape);
585  AddMultABt(dshape, dshapedxt, elmat);
586  }
587  else if (VQ)
588  {
589  VQ->Eval(D, Trans, ip);
590  D *= w;
591  AddMultADAt(dshapedxt, D, elmat);
592  }
593  else
594  {
595  if (Q)
596  {
597  w *= Q->Eval(Trans, ip);
598  }
599  AddMult_a_AAt(w, dshapedxt, elmat);
600  }
601  }
602 }
603 
604 void DiffusionIntegrator::AssembleElementMatrix2(
605  const FiniteElement &trial_fe, const FiniteElement &test_fe,
606  ElementTransformation &Trans, DenseMatrix &elmat)
607 {
608  int tr_nd = trial_fe.GetDof();
609  int te_nd = test_fe.GetDof();
610  int dim = trial_fe.GetDim();
611  int spaceDim = Trans.GetSpaceDim();
612  bool square = (dim == spaceDim);
613  double w;
614 
615 #ifdef MFEM_THREAD_SAFE
616  DenseMatrix dshape(tr_nd, dim), dshapedxt(tr_nd, spaceDim);
617  DenseMatrix te_dshape(te_nd, dim), te_dshapedxt(te_nd, spaceDim);
618  DenseMatrix invdfdx(dim, spaceDim);
619  Vector D(VQ ? VQ->GetVDim() : 0);
620 #else
621  dshape.SetSize(tr_nd, dim);
622  dshapedxt.SetSize(tr_nd, spaceDim);
623  te_dshape.SetSize(te_nd, dim);
624  te_dshapedxt.SetSize(te_nd, spaceDim);
625  invdfdx.SetSize(dim, spaceDim);
626  D.SetSize(VQ ? VQ->GetVDim() : 0);
627 #endif
628  elmat.SetSize(te_nd, tr_nd);
629 
630  const IntegrationRule *ir = IntRule ? IntRule : &GetRule(trial_fe, test_fe);
631 
632  elmat = 0.0;
633  for (int i = 0; i < ir->GetNPoints(); i++)
634  {
635  const IntegrationPoint &ip = ir->IntPoint(i);
636  trial_fe.CalcDShape(ip, dshape);
637  test_fe.CalcDShape(ip, te_dshape);
638 
639  Trans.SetIntPoint(&ip);
640  CalcAdjugate(Trans.Jacobian(), invdfdx);
641  w = Trans.Weight();
642  w = ip.weight / (square ? w : w*w*w);
643  Mult(dshape, invdfdx, dshapedxt);
644  Mult(te_dshape, invdfdx, te_dshapedxt);
645  // invdfdx, dshape, and te_dshape no longer needed
646  if (MQ)
647  {
648  MQ->Eval(invdfdx, Trans, ip);
649  invdfdx *= w;
650  Mult(te_dshapedxt, invdfdx, te_dshape);
651  AddMultABt(te_dshape, dshapedxt, elmat);
652  }
653  else if (VQ)
654  {
655  VQ->Eval(D, Trans, ip);
656  D *= w;
657  AddMultADAt(dshapedxt, D, elmat);
658  }
659  else
660  {
661  if (Q)
662  {
663  w *= Q->Eval(Trans, ip);
664  }
665  dshapedxt *= w;
666  AddMultABt(te_dshapedxt, dshapedxt, elmat);
667  }
668  }
669 }
670 
671 void DiffusionIntegrator::AssembleElementVector(
672  const FiniteElement &el, ElementTransformation &Tr, const Vector &elfun,
673  Vector &elvect)
674 {
675  int nd = el.GetDof();
676  int dim = el.GetDim();
677  double w;
678 
679  if (VQ)
680  {
681  MFEM_VERIFY(VQ->GetVDim() == dim, "Unexpected dimension for VectorCoefficient");
682  }
683 
684 #ifdef MFEM_THREAD_SAFE
685  DenseMatrix dshape(nd,dim), invdfdx(dim), mq(dim);
686  Vector D(VQ ? VQ->GetVDim() : 0);
687 #else
688  dshape.SetSize(nd,dim);
689  invdfdx.SetSize(dim);
690  mq.SetSize(dim);
691  D.SetSize(VQ ? VQ->GetVDim() : 0);
692 #endif
693  vec.SetSize(dim);
694  pointflux.SetSize(dim);
695 
696  elvect.SetSize(nd);
697 
698  const IntegrationRule *ir = IntRule ? IntRule : &GetRule(el, el);
699 
700  elvect = 0.0;
701  for (int i = 0; i < ir->GetNPoints(); i++)
702  {
703  const IntegrationPoint &ip = ir->IntPoint(i);
704  el.CalcDShape(ip, dshape);
705 
706  Tr.SetIntPoint(&ip);
707  CalcAdjugate(Tr.Jacobian(), invdfdx); // invdfdx = adj(J)
708  w = ip.weight / Tr.Weight();
709 
710  if (!MQ && !VQ)
711  {
712  dshape.MultTranspose(elfun, vec);
713  invdfdx.MultTranspose(vec, pointflux);
714  if (Q)
715  {
716  w *= Q->Eval(Tr, ip);
717  }
718  }
719  else
720  {
721  dshape.MultTranspose(elfun, pointflux);
722  invdfdx.MultTranspose(pointflux, vec);
723  if (MQ)
724  {
725  MQ->Eval(mq, Tr, ip);
726  mq.Mult(vec, pointflux);
727  }
728  else
729  {
730  VQ->Eval(D, Tr, ip);
731  for (int j=0; j<dim; ++j)
732  {
733  pointflux[j] *= D[j];
734  }
735  }
736  }
737  pointflux *= w;
738  invdfdx.Mult(pointflux, vec);
739  dshape.AddMult(vec, elvect);
740  }
741 }
742 
743 void DiffusionIntegrator::ComputeElementFlux
745  Vector &u, const FiniteElement &fluxelem, Vector &flux, bool with_coef )
746 {
747  int i, j, nd, dim, spaceDim, fnd;
748 
749  nd = el.GetDof();
750  dim = el.GetDim();
751  spaceDim = Trans.GetSpaceDim();
752 
753 #ifdef MFEM_THREAD_SAFE
754  DenseMatrix dshape(nd,dim), invdfdx(dim, spaceDim);
755 #else
756  dshape.SetSize(nd,dim);
757  invdfdx.SetSize(dim, spaceDim);
758 #endif
759  vec.SetSize(dim);
760  pointflux.SetSize(spaceDim);
761 
762  const IntegrationRule &ir = fluxelem.GetNodes();
763  fnd = ir.GetNPoints();
764  flux.SetSize( fnd * spaceDim );
765 
766  for (i = 0; i < fnd; i++)
767  {
768  const IntegrationPoint &ip = ir.IntPoint(i);
769  el.CalcDShape(ip, dshape);
770  dshape.MultTranspose(u, vec);
771 
772  Trans.SetIntPoint (&ip);
773  CalcInverse(Trans.Jacobian(), invdfdx);
774  invdfdx.MultTranspose(vec, pointflux);
775 
776  if (!MQ)
777  {
778  if (Q && with_coef)
779  {
780  pointflux *= Q->Eval(Trans,ip);
781  }
782  for (j = 0; j < spaceDim; j++)
783  {
784  flux(fnd*j+i) = pointflux(j);
785  }
786  }
787  else
788  {
789  // assuming dim == spaceDim
790  MFEM_ASSERT(dim == spaceDim, "TODO");
791  MQ->Eval(invdfdx, Trans, ip);
792  invdfdx.Mult(pointflux, vec);
793  for (j = 0; j < dim; j++)
794  {
795  flux(fnd*j+i) = vec(j);
796  }
797  }
798  }
799 }
800 
801 double DiffusionIntegrator::ComputeFluxEnergy
802 ( const FiniteElement &fluxelem, ElementTransformation &Trans,
803  Vector &flux, Vector* d_energy)
804 {
805  int nd = fluxelem.GetDof();
806  int dim = fluxelem.GetDim();
807  int spaceDim = Trans.GetSpaceDim();
808 
809 #ifdef MFEM_THREAD_SAFE
810  DenseMatrix mq;
811 #endif
812 
813  shape.SetSize(nd);
814  pointflux.SetSize(spaceDim);
815  if (d_energy) { vec.SetSize(dim); }
816  if (MQ) { mq.SetSize(dim); }
817 
818  int order = 2 * fluxelem.GetOrder(); // <--
819  const IntegrationRule *ir = &IntRules.Get(fluxelem.GetGeomType(), order);
820 
821  double energy = 0.0;
822  if (d_energy) { *d_energy = 0.0; }
823 
824  for (int i = 0; i < ir->GetNPoints(); i++)
825  {
826  const IntegrationPoint &ip = ir->IntPoint(i);
827  fluxelem.CalcShape(ip, shape);
828 
829  pointflux = 0.0;
830  for (int k = 0; k < spaceDim; k++)
831  {
832  for (int j = 0; j < nd; j++)
833  {
834  pointflux(k) += flux(k*nd+j)*shape(j);
835  }
836  }
837 
838  Trans.SetIntPoint(&ip);
839  double w = Trans.Weight() * ip.weight;
840 
841  if (!MQ)
842  {
843  double e = (pointflux * pointflux);
844  if (Q) { e *= Q->Eval(Trans, ip); }
845  energy += w * e;
846  }
847  else
848  {
849  MQ->Eval(mq, Trans, ip);
850  energy += w * mq.InnerProduct(pointflux, pointflux);
851  }
852 
853  if (d_energy)
854  {
855  // transform pointflux to the ref. domain and integrate the components
856  Trans.Jacobian().MultTranspose(pointflux, vec);
857  for (int k = 0; k < dim; k++)
858  {
859  (*d_energy)[k] += w * vec[k] * vec[k];
860  }
861  // TODO: Q, MQ
862  }
863  }
864 
865  return energy;
866 }
867 
868 const IntegrationRule &DiffusionIntegrator::GetRule(
869  const FiniteElement &trial_fe, const FiniteElement &test_fe)
870 {
871  int order;
872  if (trial_fe.Space() == FunctionSpace::Pk)
873  {
874  order = trial_fe.GetOrder() + test_fe.GetOrder() - 2;
875  }
876  else
877  {
878  // order = 2*el.GetOrder() - 2; // <-- this seems to work fine too
879  order = trial_fe.GetOrder() + test_fe.GetOrder() + trial_fe.GetDim() - 1;
880  }
881 
882  if (trial_fe.Space() == FunctionSpace::rQk)
883  {
884  return RefinedIntRules.Get(trial_fe.GetGeomType(), order);
885  }
886  return IntRules.Get(trial_fe.GetGeomType(), order);
887 }
888 
889 
890 void MassIntegrator::AssembleElementMatrix
892  DenseMatrix &elmat )
893 {
894  int nd = el.GetDof();
895  // int dim = el.GetDim();
896  double w;
897 
898 #ifdef MFEM_THREAD_SAFE
899  Vector shape;
900 #endif
901  elmat.SetSize(nd);
902  shape.SetSize(nd);
903 
904  const IntegrationRule *ir = IntRule ? IntRule : &GetRule(el, el, Trans);
905 
906  elmat = 0.0;
907  for (int i = 0; i < ir->GetNPoints(); i++)
908  {
909  const IntegrationPoint &ip = ir->IntPoint(i);
910  el.CalcShape(ip, shape);
911 
912  Trans.SetIntPoint (&ip);
913  w = Trans.Weight() * ip.weight;
914  if (Q)
915  {
916  w *= Q -> Eval(Trans, ip);
917  }
918 
919  AddMult_a_VVt(w, shape, elmat);
920  }
921 }
922 
923 void MassIntegrator::AssembleElementMatrix2(
924  const FiniteElement &trial_fe, const FiniteElement &test_fe,
925  ElementTransformation &Trans, DenseMatrix &elmat)
926 {
927  int tr_nd = trial_fe.GetDof();
928  int te_nd = test_fe.GetDof();
929  double w;
930 
931 #ifdef MFEM_THREAD_SAFE
932  Vector shape, te_shape;
933 #endif
934  elmat.SetSize(te_nd, tr_nd);
935  shape.SetSize(tr_nd);
936  te_shape.SetSize(te_nd);
937 
938  const IntegrationRule *ir = IntRule ? IntRule :
939  &GetRule(trial_fe, test_fe, Trans);
940 
941  elmat = 0.0;
942  for (int i = 0; i < ir->GetNPoints(); i++)
943  {
944  const IntegrationPoint &ip = ir->IntPoint(i);
945  trial_fe.CalcShape(ip, shape);
946  test_fe.CalcShape(ip, te_shape);
947 
948  Trans.SetIntPoint (&ip);
949  w = Trans.Weight() * ip.weight;
950  if (Q)
951  {
952  w *= Q -> Eval(Trans, ip);
953  }
954 
955  te_shape *= w;
956  AddMultVWt(te_shape, shape, elmat);
957  }
958 }
959 
960 const IntegrationRule &MassIntegrator::GetRule(const FiniteElement &trial_fe,
961  const FiniteElement &test_fe,
962  ElementTransformation &Trans)
963 {
964  // int order = trial_fe.GetOrder() + test_fe.GetOrder();
965  const int order = trial_fe.GetOrder() + test_fe.GetOrder() + Trans.OrderW();
966 
967  if (trial_fe.Space() == FunctionSpace::rQk)
968  {
969  return RefinedIntRules.Get(trial_fe.GetGeomType(), order);
970  }
971  return IntRules.Get(trial_fe.GetGeomType(), order);
972 }
973 
974 
975 void BoundaryMassIntegrator::AssembleFaceMatrix(
976  const FiniteElement &el1, const FiniteElement &el2,
978 {
979  MFEM_ASSERT(Trans.Elem2No < 0,
980  "support for interior faces is not implemented");
981 
982  int nd1 = el1.GetDof();
983  double w;
984 
985 #ifdef MFEM_THREAD_SAFE
986  Vector shape;
987 #endif
988  elmat.SetSize(nd1);
989  shape.SetSize(nd1);
990 
991  const IntegrationRule *ir = IntRule;
992  if (ir == NULL)
993  {
994  int order = 2 * el1.GetOrder();
995 
996  ir = &IntRules.Get(Trans.GetGeometryType(), order);
997  }
998 
999  elmat = 0.0;
1000  for (int i = 0; i < ir->GetNPoints(); i++)
1001  {
1002  const IntegrationPoint &ip = ir->IntPoint(i);
1003 
1004  // Set the integration point in the face and the neighboring element
1005  Trans.SetAllIntPoints(&ip);
1006 
1007  // Access the neighboring element's integration point
1008  const IntegrationPoint &eip = Trans.GetElement1IntPoint();
1009  el1.CalcShape(eip, shape);
1010 
1011  w = Trans.Weight() * ip.weight;
1012  if (Q)
1013  {
1014  w *= Q -> Eval(Trans, ip);
1015  }
1016 
1017  AddMult_a_VVt(w, shape, elmat);
1018  }
1019 }
1020 
1021 void ConvectionIntegrator::AssembleElementMatrix(
1022  const FiniteElement &el, ElementTransformation &Trans, DenseMatrix &elmat)
1023 {
1024  int nd = el.GetDof();
1025  int dim = el.GetDim();
1026 
1027 #ifdef MFEM_THREAD_SAFE
1028  DenseMatrix dshape, adjJ, Q_ir;
1029  Vector shape, vec2, BdFidxT;
1030 #endif
1031  elmat.SetSize(nd);
1032  dshape.SetSize(nd,dim);
1033  adjJ.SetSize(dim);
1034  shape.SetSize(nd);
1035  vec2.SetSize(dim);
1036  BdFidxT.SetSize(nd);
1037 
1038  Vector vec1;
1039 
1040  const IntegrationRule *ir = IntRule;
1041  if (ir == NULL)
1042  {
1043  int order = Trans.OrderGrad(&el) + Trans.Order() + el.GetOrder();
1044  ir = &IntRules.Get(el.GetGeomType(), order);
1045  }
1046 
1047  Q->Eval(Q_ir, Trans, *ir);
1048 
1049  elmat = 0.0;
1050  for (int i = 0; i < ir->GetNPoints(); i++)
1051  {
1052  const IntegrationPoint &ip = ir->IntPoint(i);
1053  el.CalcDShape(ip, dshape);
1054  el.CalcShape(ip, shape);
1055 
1056  Trans.SetIntPoint(&ip);
1057  CalcAdjugate(Trans.Jacobian(), adjJ);
1058  Q_ir.GetColumnReference(i, vec1);
1059  vec1 *= alpha * ip.weight;
1060 
1061  adjJ.Mult(vec1, vec2);
1062  dshape.Mult(vec2, BdFidxT);
1063 
1064  AddMultVWt(shape, BdFidxT, elmat);
1065  }
1066 }
1067 
1068 
1069 void GroupConvectionIntegrator::AssembleElementMatrix(
1070  const FiniteElement &el, ElementTransformation &Trans, DenseMatrix &elmat)
1071 {
1072  int nd = el.GetDof();
1073  int dim = el.GetDim();
1074 
1075  elmat.SetSize(nd);
1076  dshape.SetSize(nd,dim);
1077  adjJ.SetSize(dim);
1078  shape.SetSize(nd);
1079  grad.SetSize(nd,dim);
1080 
1081  const IntegrationRule *ir = IntRule;
1082  if (ir == NULL)
1083  {
1084  int order = Trans.OrderGrad(&el) + el.GetOrder();
1085  ir = &IntRules.Get(el.GetGeomType(), order);
1086  }
1087 
1088  Q->Eval(Q_nodal, Trans, el.GetNodes()); // sets the size of Q_nodal
1089 
1090  elmat = 0.0;
1091  for (int i = 0; i < ir->GetNPoints(); i++)
1092  {
1093  const IntegrationPoint &ip = ir->IntPoint(i);
1094  el.CalcDShape(ip, dshape);
1095  el.CalcShape(ip, shape);
1096 
1097  Trans.SetIntPoint(&ip);
1098  CalcAdjugate(Trans.Jacobian(), adjJ);
1099 
1100  Mult(dshape, adjJ, grad);
1101 
1102  double w = alpha * ip.weight;
1103 
1104  // elmat(k,l) += \sum_s w*shape(k)*Q_nodal(s,k)*grad(l,s)
1105  for (int k = 0; k < nd; k++)
1106  {
1107  double wsk = w*shape(k);
1108  for (int l = 0; l < nd; l++)
1109  {
1110  double a = 0.0;
1111  for (int s = 0; s < dim; s++)
1112  {
1113  a += Q_nodal(s,k)*grad(l,s);
1114  }
1115  elmat(k,l) += wsk*a;
1116  }
1117  }
1118  }
1119 }
1120 
1121 const IntegrationRule &ConvectionIntegrator::GetRule(const FiniteElement
1122  &trial_fe,
1123  const FiniteElement &test_fe,
1124  ElementTransformation &Trans)
1125 {
1126  int order = Trans.OrderGrad(&trial_fe) + Trans.Order() + test_fe.GetOrder();
1127 
1128  return IntRules.Get(trial_fe.GetGeomType(), order);
1129 }
1130 
1131 const IntegrationRule &ConvectionIntegrator::GetRule(
1132  const FiniteElement &el, ElementTransformation &Trans)
1133 {
1134  return GetRule(el,el,Trans);
1135 }
1136 
1137 void VectorMassIntegrator::AssembleElementMatrix
1139  DenseMatrix &elmat )
1140 {
1141  int nd = el.GetDof();
1142  int spaceDim = Trans.GetSpaceDim();
1143 
1144  double norm;
1145 
1146  // If vdim is not set, set it to the space dimension
1147  vdim = (vdim == -1) ? spaceDim : vdim;
1148 
1149  elmat.SetSize(nd*vdim);
1150  shape.SetSize(nd);
1151  partelmat.SetSize(nd);
1152  if (VQ)
1153  {
1154  vec.SetSize(vdim);
1155  }
1156  else if (MQ)
1157  {
1158  mcoeff.SetSize(vdim);
1159  }
1160 
1161  const IntegrationRule *ir = IntRule;
1162  if (ir == NULL)
1163  {
1164  int order = 2 * el.GetOrder() + Trans.OrderW() + Q_order;
1165 
1166  if (el.Space() == FunctionSpace::rQk)
1167  {
1168  ir = &RefinedIntRules.Get(el.GetGeomType(), order);
1169  }
1170  else
1171  {
1172  ir = &IntRules.Get(el.GetGeomType(), order);
1173  }
1174  }
1175 
1176  elmat = 0.0;
1177  for (int s = 0; s < ir->GetNPoints(); s++)
1178  {
1179  const IntegrationPoint &ip = ir->IntPoint(s);
1180  el.CalcShape(ip, shape);
1181 
1182  Trans.SetIntPoint (&ip);
1183  norm = ip.weight * Trans.Weight();
1184 
1185  MultVVt(shape, partelmat);
1186 
1187  if (VQ)
1188  {
1189  VQ->Eval(vec, Trans, ip);
1190  for (int k = 0; k < vdim; k++)
1191  {
1192  elmat.AddMatrix(norm*vec(k), partelmat, nd*k, nd*k);
1193  }
1194  }
1195  else if (MQ)
1196  {
1197  MQ->Eval(mcoeff, Trans, ip);
1198  for (int i = 0; i < vdim; i++)
1199  for (int j = 0; j < vdim; j++)
1200  {
1201  elmat.AddMatrix(norm*mcoeff(i,j), partelmat, nd*i, nd*j);
1202  }
1203  }
1204  else
1205  {
1206  if (Q)
1207  {
1208  norm *= Q->Eval(Trans, ip);
1209  }
1210  partelmat *= norm;
1211  for (int k = 0; k < vdim; k++)
1212  {
1213  elmat.AddMatrix(partelmat, nd*k, nd*k);
1214  }
1215  }
1216  }
1217 }
1218 
1219 void VectorMassIntegrator::AssembleElementMatrix2(
1220  const FiniteElement &trial_fe, const FiniteElement &test_fe,
1221  ElementTransformation &Trans, DenseMatrix &elmat)
1222 {
1223  int tr_nd = trial_fe.GetDof();
1224  int te_nd = test_fe.GetDof();
1225 
1226  double norm;
1227 
1228  // If vdim is not set, set it to the space dimension
1229  vdim = (vdim == -1) ? Trans.GetSpaceDim() : vdim;
1230 
1231  elmat.SetSize(te_nd*vdim, tr_nd*vdim);
1232  shape.SetSize(tr_nd);
1233  te_shape.SetSize(te_nd);
1234  partelmat.SetSize(te_nd, tr_nd);
1235  if (VQ)
1236  {
1237  vec.SetSize(vdim);
1238  }
1239  else if (MQ)
1240  {
1241  mcoeff.SetSize(vdim);
1242  }
1243 
1244  const IntegrationRule *ir = IntRule;
1245  if (ir == NULL)
1246  {
1247  int order = (trial_fe.GetOrder() + test_fe.GetOrder() +
1248  Trans.OrderW() + Q_order);
1249 
1250  if (trial_fe.Space() == FunctionSpace::rQk)
1251  {
1252  ir = &RefinedIntRules.Get(trial_fe.GetGeomType(), order);
1253  }
1254  else
1255  {
1256  ir = &IntRules.Get(trial_fe.GetGeomType(), order);
1257  }
1258  }
1259 
1260  elmat = 0.0;
1261  for (int s = 0; s < ir->GetNPoints(); s++)
1262  {
1263  const IntegrationPoint &ip = ir->IntPoint(s);
1264  trial_fe.CalcShape(ip, shape);
1265  test_fe.CalcShape(ip, te_shape);
1266 
1267  Trans.SetIntPoint(&ip);
1268  norm = ip.weight * Trans.Weight();
1269 
1270  MultVWt(te_shape, shape, partelmat);
1271 
1272  if (VQ)
1273  {
1274  VQ->Eval(vec, Trans, ip);
1275  for (int k = 0; k < vdim; k++)
1276  {
1277  elmat.AddMatrix(norm*vec(k), partelmat, te_nd*k, tr_nd*k);
1278  }
1279  }
1280  else if (MQ)
1281  {
1282  MQ->Eval(mcoeff, Trans, ip);
1283  for (int i = 0; i < vdim; i++)
1284  for (int j = 0; j < vdim; j++)
1285  {
1286  elmat.AddMatrix(norm*mcoeff(i,j), partelmat, te_nd*i, tr_nd*j);
1287  }
1288  }
1289  else
1290  {
1291  if (Q)
1292  {
1293  norm *= Q->Eval(Trans, ip);
1294  }
1295  partelmat *= norm;
1296  for (int k = 0; k < vdim; k++)
1297  {
1298  elmat.AddMatrix(partelmat, te_nd*k, tr_nd*k);
1299  }
1300  }
1301  }
1302 }
1303 
1304 void VectorFEDivergenceIntegrator::AssembleElementMatrix2(
1305  const FiniteElement &trial_fe, const FiniteElement &test_fe,
1306  ElementTransformation &Trans, DenseMatrix &elmat)
1307 {
1308  int trial_nd = trial_fe.GetDof(), test_nd = test_fe.GetDof(), i;
1309 
1310 #ifdef MFEM_THREAD_SAFE
1311  Vector divshape(trial_nd), shape(test_nd);
1312 #else
1313  divshape.SetSize(trial_nd);
1314  shape.SetSize(test_nd);
1315 #endif
1316 
1317  elmat.SetSize(test_nd, trial_nd);
1318 
1319  const IntegrationRule *ir = IntRule;
1320  if (ir == NULL)
1321  {
1322  int order = trial_fe.GetOrder() + test_fe.GetOrder() - 1; // <--
1323  ir = &IntRules.Get(trial_fe.GetGeomType(), order);
1324  }
1325 
1326  elmat = 0.0;
1327  for (i = 0; i < ir->GetNPoints(); i++)
1328  {
1329  const IntegrationPoint &ip = ir->IntPoint(i);
1330  trial_fe.CalcDivShape(ip, divshape);
1331  test_fe.CalcShape(ip, shape);
1332  double w = ip.weight;
1333  if (Q)
1334  {
1335  Trans.SetIntPoint(&ip);
1336  w *= Q->Eval(Trans, ip);
1337  }
1338  shape *= w;
1339  AddMultVWt(shape, divshape, elmat);
1340  }
1341 }
1342 
1343 void VectorFEWeakDivergenceIntegrator::AssembleElementMatrix2(
1344  const FiniteElement &trial_fe, const FiniteElement &test_fe,
1345  ElementTransformation &Trans, DenseMatrix &elmat)
1346 {
1347  int trial_nd = trial_fe.GetDof(), test_nd = test_fe.GetDof(), i;
1348  int dim = trial_fe.GetDim();
1349 
1350  MFEM_ASSERT(test_fe.GetRangeType() == mfem::FiniteElement::SCALAR &&
1351  test_fe.GetMapType() == mfem::FiniteElement::VALUE &&
1353  "Trial space must be H(Curl) and test space must be H_1");
1354 
1355 #ifdef MFEM_THREAD_SAFE
1356  DenseMatrix dshape(test_nd, dim);
1357  DenseMatrix dshapedxt(test_nd, dim);
1358  DenseMatrix vshape(trial_nd, dim);
1359  DenseMatrix invdfdx(dim);
1360 #else
1361  dshape.SetSize(test_nd, dim);
1362  dshapedxt.SetSize(test_nd, dim);
1363  vshape.SetSize(trial_nd, dim);
1364  invdfdx.SetSize(dim);
1365 #endif
1366 
1367  elmat.SetSize(test_nd, trial_nd);
1368 
1369  const IntegrationRule *ir = IntRule;
1370  if (ir == NULL)
1371  {
1372  // The integrand on the reference element is:
1373  // -( Q/det(J) ) u_hat^T adj(J) adj(J)^T grad_hat(v_hat).
1374  //
1375  // For Trans in (P_k)^d, v_hat in P_l, u_hat in ND_m, and dim=sdim=d>=1
1376  // - J_{ij} is in P_{k-1}, so adj(J)_{ij} is in P_{(d-1)*(k-1)}
1377  // - so adj(J)^T grad_hat(v_hat) is in (P_{(d-1)*(k-1)+(l-1)})^d
1378  // - u_hat is in (P_m)^d
1379  // - adj(J)^T u_hat is in (P_{(d-1)*(k-1)+m})^d
1380  // - and u_hat^T adj(J) adj(J)^T grad_hat(v_hat) is in P_n with
1381  // n = 2*(d-1)*(k-1)+(l-1)+m
1382  //
1383  // For Trans in (Q_k)^d, v_hat in Q_l, u_hat in ND_m, and dim=sdim=d>1
1384  // - J_{i*}, J's i-th row, is in ( Q_{k-1,k,k}, Q_{k,k-1,k}, Q_{k,k,k-1} )
1385  // - adj(J)_{*j} is in ( Q_{s,s-1,s-1}, Q_{s-1,s,s-1}, Q_{s-1,s-1,s} )
1386  // with s = (d-1)*k
1387  // - adj(J)^T grad_hat(v_hat) is in Q_{(d-1)*k+(l-1)}
1388  // - u_hat is in ( Q_{m-1,m,m}, Q_{m,m-1,m}, Q_{m,m,m-1} )
1389  // - adj(J)^T u_hat is in Q_{(d-1)*k+(m-1)}
1390  // - and u_hat^T adj(J) adj(J)^T grad_hat(v_hat) is in Q_n with
1391  // n = 2*(d-1)*k+(l-1)+(m-1)
1392  //
1393  // In the next formula we use the expressions for n with k=1, which means
1394  // that the term Q/det(J) is disregarded:
1395  int ir_order = (trial_fe.Space() == FunctionSpace::Pk) ?
1396  (trial_fe.GetOrder() + test_fe.GetOrder() - 1) :
1397  (trial_fe.GetOrder() + test_fe.GetOrder() + 2*(dim-2));
1398  ir = &IntRules.Get(trial_fe.GetGeomType(), ir_order);
1399  }
1400 
1401  elmat = 0.0;
1402  for (i = 0; i < ir->GetNPoints(); i++)
1403  {
1404  const IntegrationPoint &ip = ir->IntPoint(i);
1405  test_fe.CalcDShape(ip, dshape);
1406 
1407  Trans.SetIntPoint(&ip);
1408  CalcAdjugate(Trans.Jacobian(), invdfdx);
1409  Mult(dshape, invdfdx, dshapedxt);
1410 
1411  trial_fe.CalcVShape(Trans, vshape);
1412 
1413  double w = ip.weight;
1414 
1415  if (Q)
1416  {
1417  w *= Q->Eval(Trans, ip);
1418  }
1419  dshapedxt *= -w;
1420 
1421  AddMultABt(dshapedxt, vshape, elmat);
1422  }
1423 }
1424 
1425 void VectorFECurlIntegrator::AssembleElementMatrix2(
1426  const FiniteElement &trial_fe, const FiniteElement &test_fe,
1427  ElementTransformation &Trans, DenseMatrix &elmat)
1428 {
1429  int trial_nd = trial_fe.GetDof(), test_nd = test_fe.GetDof(), i;
1430  int dim = trial_fe.GetDim();
1431  int dimc = (dim == 3) ? 3 : 1;
1432 
1433  MFEM_ASSERT(trial_fe.GetMapType() == mfem::FiniteElement::H_CURL ||
1435  "At least one of the finite elements must be in H(Curl)");
1436 
1437  int curl_nd, vec_nd;
1438  if ( trial_fe.GetMapType() == mfem::FiniteElement::H_CURL )
1439  {
1440  curl_nd = trial_nd;
1441  vec_nd = test_nd;
1442  }
1443  else
1444  {
1445  curl_nd = test_nd;
1446  vec_nd = trial_nd;
1447  }
1448 
1449 #ifdef MFEM_THREAD_SAFE
1450  DenseMatrix curlshapeTrial(curl_nd, dimc);
1451  DenseMatrix curlshapeTrial_dFT(curl_nd, dimc);
1452  DenseMatrix vshapeTest(vec_nd, dimc);
1453 #else
1454  curlshapeTrial.SetSize(curl_nd, dimc);
1455  curlshapeTrial_dFT.SetSize(curl_nd, dimc);
1456  vshapeTest.SetSize(vec_nd, dimc);
1457 #endif
1458  Vector shapeTest(vshapeTest.GetData(), vec_nd);
1459 
1460  elmat.SetSize(test_nd, trial_nd);
1461 
1462  const IntegrationRule *ir = IntRule;
1463  if (ir == NULL)
1464  {
1465  int order = trial_fe.GetOrder() + test_fe.GetOrder() - 1; // <--
1466  ir = &IntRules.Get(trial_fe.GetGeomType(), order);
1467  }
1468 
1469  elmat = 0.0;
1470  for (i = 0; i < ir->GetNPoints(); i++)
1471  {
1472  const IntegrationPoint &ip = ir->IntPoint(i);
1473 
1474  Trans.SetIntPoint(&ip);
1475  if (dim == 3)
1476  {
1477  if ( trial_fe.GetMapType() == mfem::FiniteElement::H_CURL )
1478  {
1479  trial_fe.CalcCurlShape(ip, curlshapeTrial);
1480  test_fe.CalcVShape(Trans, vshapeTest);
1481  }
1482  else
1483  {
1484  test_fe.CalcCurlShape(ip, curlshapeTrial);
1485  trial_fe.CalcVShape(Trans, vshapeTest);
1486  }
1487  MultABt(curlshapeTrial, Trans.Jacobian(), curlshapeTrial_dFT);
1488  }
1489  else
1490  {
1491  if ( trial_fe.GetMapType() == mfem::FiniteElement::H_CURL )
1492  {
1493  trial_fe.CalcCurlShape(ip, curlshapeTrial_dFT);
1494  test_fe.CalcShape(ip, shapeTest);
1495  }
1496  else
1497  {
1498  test_fe.CalcCurlShape(ip, curlshapeTrial_dFT);
1499  trial_fe.CalcShape(ip, shapeTest);
1500  }
1501  }
1502 
1503  double w = ip.weight;
1504 
1505  if (Q)
1506  {
1507  w *= Q->Eval(Trans, ip);
1508  }
1509  // Note: shapeTest points to the same data as vshapeTest
1510  vshapeTest *= w;
1511  if ( trial_fe.GetMapType() == mfem::FiniteElement::H_CURL )
1512  {
1513  AddMultABt(vshapeTest, curlshapeTrial_dFT, elmat);
1514  }
1515  else
1516  {
1517  AddMultABt(curlshapeTrial_dFT, vshapeTest, elmat);
1518  }
1519  }
1520 }
1521 
1522 void DerivativeIntegrator::AssembleElementMatrix2 (
1523  const FiniteElement &trial_fe,
1524  const FiniteElement &test_fe,
1525  ElementTransformation &Trans,
1526  DenseMatrix &elmat)
1527 {
1528  int dim = trial_fe.GetDim();
1529  int trial_nd = trial_fe.GetDof();
1530  int test_nd = test_fe.GetDof();
1531 
1532  int i, l;
1533  double det;
1534 
1535  elmat.SetSize (test_nd,trial_nd);
1536  dshape.SetSize (trial_nd,dim);
1537  dshapedxt.SetSize(trial_nd,dim);
1538  dshapedxi.SetSize(trial_nd);
1539  invdfdx.SetSize(dim);
1540  shape.SetSize (test_nd);
1541 
1542  const IntegrationRule *ir = IntRule;
1543  if (ir == NULL)
1544  {
1545  int order;
1546  if (trial_fe.Space() == FunctionSpace::Pk)
1547  {
1548  order = trial_fe.GetOrder() + test_fe.GetOrder() - 1;
1549  }
1550  else
1551  {
1552  order = trial_fe.GetOrder() + test_fe.GetOrder() + dim;
1553  }
1554 
1555  if (trial_fe.Space() == FunctionSpace::rQk)
1556  {
1557  ir = &RefinedIntRules.Get(trial_fe.GetGeomType(), order);
1558  }
1559  else
1560  {
1561  ir = &IntRules.Get(trial_fe.GetGeomType(), order);
1562  }
1563  }
1564 
1565  elmat = 0.0;
1566  for (i = 0; i < ir->GetNPoints(); i++)
1567  {
1568  const IntegrationPoint &ip = ir->IntPoint(i);
1569 
1570  trial_fe.CalcDShape(ip, dshape);
1571 
1572  Trans.SetIntPoint (&ip);
1573  CalcInverse (Trans.Jacobian(), invdfdx);
1574  det = Trans.Weight();
1575  Mult (dshape, invdfdx, dshapedxt);
1576 
1577  test_fe.CalcShape(ip, shape);
1578 
1579  for (l = 0; l < trial_nd; l++)
1580  {
1581  dshapedxi(l) = dshapedxt(l,xi);
1582  }
1583 
1584  shape *= Q->Eval(Trans,ip) * det * ip.weight;
1585  AddMultVWt (shape, dshapedxi, elmat);
1586  }
1587 }
1588 
1589 void CurlCurlIntegrator::AssembleElementMatrix
1591  DenseMatrix &elmat )
1592 {
1593  int nd = el.GetDof();
1594  int dim = el.GetDim();
1595  int dimc = (dim == 3) ? 3 : 1;
1596  double w;
1597 
1598 #ifdef MFEM_THREAD_SAFE
1599  Vector D;
1600  DenseMatrix curlshape(nd,dimc), curlshape_dFt(nd,dimc), M;
1601 #else
1602  curlshape.SetSize(nd,dimc);
1603  curlshape_dFt.SetSize(nd,dimc);
1604 #endif
1605  elmat.SetSize(nd);
1606  if (MQ) { M.SetSize(dimc); }
1607  if (DQ) { D.SetSize(dimc); }
1608 
1609  const IntegrationRule *ir = IntRule;
1610  if (ir == NULL)
1611  {
1612  int order;
1613  if (el.Space() == FunctionSpace::Pk)
1614  {
1615  order = 2*el.GetOrder() - 2;
1616  }
1617  else
1618  {
1619  order = 2*el.GetOrder();
1620  }
1621 
1622  ir = &IntRules.Get(el.GetGeomType(), order);
1623  }
1624 
1625  elmat = 0.0;
1626  for (int i = 0; i < ir->GetNPoints(); i++)
1627  {
1628  const IntegrationPoint &ip = ir->IntPoint(i);
1629 
1630  Trans.SetIntPoint (&ip);
1631 
1632  w = ip.weight / Trans.Weight();
1633 
1634  if ( dim == 3 )
1635  {
1636  el.CalcCurlShape(ip, curlshape);
1637  MultABt(curlshape, Trans.Jacobian(), curlshape_dFt);
1638  }
1639  else
1640  {
1641  el.CalcCurlShape(ip, curlshape_dFt);
1642  }
1643 
1644  if (MQ)
1645  {
1646  MQ->Eval(M, Trans, ip);
1647  M *= w;
1648  Mult(curlshape_dFt, M, curlshape);
1649  AddMultABt(curlshape, curlshape_dFt, elmat);
1650  }
1651  else if (DQ)
1652  {
1653  DQ->Eval(D, Trans, ip);
1654  D *= w;
1655  AddMultADAt(curlshape_dFt, D, elmat);
1656  }
1657  else if (Q)
1658  {
1659  w *= Q->Eval(Trans, ip);
1660  AddMult_a_AAt(w, curlshape_dFt, elmat);
1661  }
1662  else
1663  {
1664  AddMult_a_AAt(w, curlshape_dFt, elmat);
1665  }
1666  }
1667 }
1668 
1669 void CurlCurlIntegrator
1670 ::ComputeElementFlux(const FiniteElement &el, ElementTransformation &Trans,
1671  Vector &u, const FiniteElement &fluxelem, Vector &flux,
1672  bool with_coef)
1673 {
1674 #ifdef MFEM_THREAD_SAFE
1675  DenseMatrix projcurl;
1676 #endif
1677 
1678  fluxelem.ProjectCurl(el, Trans, projcurl);
1679 
1680  flux.SetSize(projcurl.Height());
1681  projcurl.Mult(u, flux);
1682 
1683  // TODO: Q, wcoef?
1684 }
1685 
1686 double CurlCurlIntegrator::ComputeFluxEnergy(const FiniteElement &fluxelem,
1687  ElementTransformation &Trans,
1688  Vector &flux, Vector *d_energy)
1689 {
1690  int nd = fluxelem.GetDof();
1691  int dim = fluxelem.GetDim();
1692 
1693 #ifdef MFEM_THREAD_SAFE
1694  DenseMatrix vshape;
1695 #endif
1696  vshape.SetSize(nd, dim);
1697  pointflux.SetSize(dim);
1698  if (d_energy) { vec.SetSize(dim); }
1699 
1700  int order = 2 * fluxelem.GetOrder(); // <--
1701  const IntegrationRule &ir = IntRules.Get(fluxelem.GetGeomType(), order);
1702 
1703  double energy = 0.0;
1704  if (d_energy) { *d_energy = 0.0; }
1705 
1706  Vector* pfluxes = NULL;
1707  if (d_energy)
1708  {
1709  pfluxes = new Vector[ir.GetNPoints()];
1710  }
1711 
1712  for (int i = 0; i < ir.GetNPoints(); i++)
1713  {
1714  const IntegrationPoint &ip = ir.IntPoint(i);
1715  Trans.SetIntPoint(&ip);
1716 
1717  fluxelem.CalcVShape(Trans, vshape);
1718  // fluxelem.CalcVShape(ip, vshape);
1719  vshape.MultTranspose(flux, pointflux);
1720 
1721  double w = Trans.Weight() * ip.weight;
1722 
1723  double e = w * (pointflux * pointflux);
1724 
1725  if (Q)
1726  {
1727  // TODO
1728  }
1729 
1730  energy += e;
1731 
1732 #if ANISO_EXPERIMENTAL
1733  if (d_energy)
1734  {
1735  pfluxes[i].SetSize(dim);
1736  Trans.Jacobian().MultTranspose(pointflux, pfluxes[i]);
1737 
1738  /*
1739  DenseMatrix Jadj(dim, dim);
1740  CalcAdjugate(Trans.Jacobian(), Jadj);
1741  pfluxes[i].SetSize(dim);
1742  Jadj.Mult(pointflux, pfluxes[i]);
1743  */
1744 
1745  // pfluxes[i] = pointflux;
1746  }
1747 #endif
1748  }
1749 
1750  if (d_energy)
1751  {
1752 #if ANISO_EXPERIMENTAL
1753  *d_energy = 0.0;
1754  Vector tmp;
1755 
1756  int n = (int) round(pow(ir.GetNPoints(), 1.0/3.0));
1757  MFEM_ASSERT(n*n*n == ir.GetNPoints(), "");
1758 
1759  // hack: get total variation of 'pointflux' in the x,y,z directions
1760  for (int k = 0; k < n; k++)
1761  for (int l = 0; l < n; l++)
1762  for (int m = 0; m < n; m++)
1763  {
1764  Vector &vec = pfluxes[(k*n + l)*n + m];
1765  if (m > 0)
1766  {
1767  tmp = vec; tmp -= pfluxes[(k*n + l)*n + (m-1)];
1768  (*d_energy)[0] += (tmp * tmp);
1769  }
1770  if (l > 0)
1771  {
1772  tmp = vec; tmp -= pfluxes[(k*n + (l-1))*n + m];
1773  (*d_energy)[1] += (tmp * tmp);
1774  }
1775  if (k > 0)
1776  {
1777  tmp = vec; tmp -= pfluxes[((k-1)*n + l)*n + m];
1778  (*d_energy)[2] += (tmp * tmp);
1779  }
1780  }
1781 #else
1782  *d_energy = 1.0;
1783 #endif
1784 
1785  delete [] pfluxes;
1786  }
1787 
1788  return energy;
1789 }
1790 
1791 void VectorCurlCurlIntegrator::AssembleElementMatrix(
1792  const FiniteElement &el, ElementTransformation &Trans, DenseMatrix &elmat)
1793 {
1794  int dim = el.GetDim();
1795  int dof = el.GetDof();
1796  int cld = (dim*(dim-1))/2;
1797 
1798 #ifdef MFEM_THREAD_SAFE
1799  DenseMatrix dshape_hat(dof, dim), dshape(dof, dim);
1800  DenseMatrix curlshape(dim*dof, cld), Jadj(dim);
1801 #else
1802  dshape_hat.SetSize(dof, dim);
1803  dshape.SetSize(dof, dim);
1804  curlshape.SetSize(dim*dof, cld);
1805  Jadj.SetSize(dim);
1806 #endif
1807 
1808  const IntegrationRule *ir = IntRule;
1809  if (ir == NULL)
1810  {
1811  // use the same integration rule as diffusion
1812  int order = 2 * Trans.OrderGrad(&el);
1813  ir = &IntRules.Get(el.GetGeomType(), order);
1814  }
1815 
1816  elmat.SetSize(dof*dim);
1817  elmat = 0.0;
1818  for (int i = 0; i < ir->GetNPoints(); i++)
1819  {
1820  const IntegrationPoint &ip = ir->IntPoint(i);
1821  el.CalcDShape(ip, dshape_hat);
1822 
1823  Trans.SetIntPoint(&ip);
1824  CalcAdjugate(Trans.Jacobian(), Jadj);
1825  double w = ip.weight / Trans.Weight();
1826 
1827  Mult(dshape_hat, Jadj, dshape);
1828  dshape.GradToCurl(curlshape);
1829 
1830  if (Q)
1831  {
1832  w *= Q->Eval(Trans, ip);
1833  }
1834 
1835  AddMult_a_AAt(w, curlshape, elmat);
1836  }
1837 }
1838 
1839 double VectorCurlCurlIntegrator::GetElementEnergy(
1840  const FiniteElement &el, ElementTransformation &Tr, const Vector &elfun)
1841 {
1842  int dim = el.GetDim();
1843  int dof = el.GetDof();
1844 
1845 #ifdef MFEM_THREAD_SAFE
1846  DenseMatrix dshape_hat(dof, dim), Jadj(dim), grad_hat(dim), grad(dim);
1847 #else
1848  dshape_hat.SetSize(dof, dim);
1849 
1850  Jadj.SetSize(dim);
1851  grad_hat.SetSize(dim);
1852  grad.SetSize(dim);
1853 #endif
1854  DenseMatrix elfun_mat(elfun.GetData(), dof, dim);
1855 
1856  const IntegrationRule *ir = IntRule;
1857  if (ir == NULL)
1858  {
1859  // use the same integration rule as diffusion
1860  int order = 2 * Tr.OrderGrad(&el);
1861  ir = &IntRules.Get(el.GetGeomType(), order);
1862  }
1863 
1864  double energy = 0.;
1865  for (int i = 0; i < ir->GetNPoints(); i++)
1866  {
1867  const IntegrationPoint &ip = ir->IntPoint(i);
1868  el.CalcDShape(ip, dshape_hat);
1869 
1870  MultAtB(elfun_mat, dshape_hat, grad_hat);
1871 
1872  Tr.SetIntPoint(&ip);
1873  CalcAdjugate(Tr.Jacobian(), Jadj);
1874  double w = ip.weight / Tr.Weight();
1875 
1876  Mult(grad_hat, Jadj, grad);
1877 
1878  if (dim == 2)
1879  {
1880  double curl = grad(0,1) - grad(1,0);
1881  w *= curl * curl;
1882  }
1883  else
1884  {
1885  double curl_x = grad(2,1) - grad(1,2);
1886  double curl_y = grad(0,2) - grad(2,0);
1887  double curl_z = grad(1,0) - grad(0,1);
1888  w *= curl_x * curl_x + curl_y * curl_y + curl_z * curl_z;
1889  }
1890 
1891  if (Q)
1892  {
1893  w *= Q->Eval(Tr, ip);
1894  }
1895 
1896  energy += w;
1897  }
1898 
1899  elfun_mat.ClearExternalData();
1900 
1901  return 0.5 * energy;
1902 }
1903 
1904 
1905 void VectorFEMassIntegrator::AssembleElementMatrix(
1906  const FiniteElement &el,
1907  ElementTransformation &Trans,
1908  DenseMatrix &elmat)
1909 {
1910  int dof = el.GetDof();
1911  int spaceDim = Trans.GetSpaceDim();
1912 
1913  double w;
1914 
1915 #ifdef MFEM_THREAD_SAFE
1916  Vector D(VQ ? VQ->GetVDim() : 0);
1917  DenseMatrix trial_vshape(dof, spaceDim);
1918  DenseMatrix K(MQ ? MQ->GetVDim() : 0, MQ ? MQ->GetVDim() : 0);
1919 #else
1920  trial_vshape.SetSize(dof, spaceDim);
1921  D.SetSize(VQ ? VQ->GetVDim() : 0);
1922  K.SetSize(MQ ? MQ->GetVDim() : 0, MQ ? MQ->GetVDim() : 0);
1923 #endif
1924  DenseMatrix tmp(trial_vshape.Height(), K.Width());
1925 
1926  elmat.SetSize(dof);
1927  elmat = 0.0;
1928 
1929  const IntegrationRule *ir = IntRule;
1930  if (ir == NULL)
1931  {
1932  // int order = 2 * el.GetOrder();
1933  int order = Trans.OrderW() + 2 * el.GetOrder();
1934  ir = &IntRules.Get(el.GetGeomType(), order);
1935  }
1936 
1937  for (int i = 0; i < ir->GetNPoints(); i++)
1938  {
1939  const IntegrationPoint &ip = ir->IntPoint(i);
1940 
1941  Trans.SetIntPoint (&ip);
1942 
1943  el.CalcVShape(Trans, trial_vshape);
1944 
1945  w = ip.weight * Trans.Weight();
1946  if (MQ)
1947  {
1948  MQ->Eval(K, Trans, ip);
1949  K *= w;
1950  Mult(trial_vshape,K,tmp);
1951  AddMultABt(tmp,trial_vshape,elmat);
1952  }
1953  else if (VQ)
1954  {
1955  VQ->Eval(D, Trans, ip);
1956  D *= w;
1957  AddMultADAt(trial_vshape, D, elmat);
1958  }
1959  else
1960  {
1961  if (Q)
1962  {
1963  w *= Q -> Eval (Trans, ip);
1964  }
1965  AddMult_a_AAt (w, trial_vshape, elmat);
1966  }
1967  }
1968 }
1969 
1970 void VectorFEMassIntegrator::AssembleElementMatrix2(
1971  const FiniteElement &trial_fe, const FiniteElement &test_fe,
1972  ElementTransformation &Trans, DenseMatrix &elmat)
1973 {
1974  if (test_fe.GetRangeType() == FiniteElement::SCALAR
1975  && trial_fe.GetRangeType() == FiniteElement::VECTOR)
1976  {
1977  // assume test_fe is scalar FE and trial_fe is vector FE
1978  int spaceDim = Trans.GetSpaceDim();
1979  int vdim = MQ ? MQ->GetHeight() : spaceDim;
1980  int trial_dof = trial_fe.GetDof();
1981  int test_dof = test_fe.GetDof();
1982  double w;
1983 
1984 #ifdef MFEM_THREAD_SAFE
1985  DenseMatrix trial_vshape(trial_dof, spaceDim);
1986  Vector shape(test_dof);
1987  Vector D(VQ ? VQ->GetVDim() : 0);
1988  DenseMatrix K(MQ ? MQ->GetVDim() : 0, MQ ? MQ->GetVDim() : 0);
1989 #else
1990  trial_vshape.SetSize(trial_dof, spaceDim);
1991  shape.SetSize(test_dof);
1992  D.SetSize(VQ ? VQ->GetVDim() : 0);
1993  K.SetSize(MQ ? MQ->GetVDim() : 0, MQ ? MQ->GetVDim() : 0);
1994 #endif
1995 
1996  elmat.SetSize(vdim*test_dof, trial_dof);
1997 
1998  const IntegrationRule *ir = IntRule;
1999  if (ir == NULL)
2000  {
2001  int order = (Trans.OrderW() + test_fe.GetOrder() + trial_fe.GetOrder());
2002  ir = &IntRules.Get(test_fe.GetGeomType(), order);
2003  }
2004 
2005  elmat = 0.0;
2006  for (int i = 0; i < ir->GetNPoints(); i++)
2007  {
2008  const IntegrationPoint &ip = ir->IntPoint(i);
2009 
2010  Trans.SetIntPoint (&ip);
2011 
2012  trial_fe.CalcVShape(Trans, trial_vshape);
2013  test_fe.CalcShape(ip, shape);
2014 
2015  w = ip.weight * Trans.Weight();
2016  if (VQ)
2017  {
2018  VQ->Eval(D, Trans, ip);
2019  D *= w;
2020  for (int d = 0; d < vdim; d++)
2021  {
2022  for (int j = 0; j < test_dof; j++)
2023  {
2024  for (int k = 0; k < trial_dof; k++)
2025  {
2026  elmat(d * test_dof + j, k) +=
2027  shape(j) * D(d) * trial_vshape(k, d);
2028  }
2029  }
2030  }
2031  }
2032  else if (MQ)
2033  {
2034  MQ->Eval(K, Trans, ip);
2035  K *= w;
2036  for (int d = 0; d < vdim; d++)
2037  {
2038  for (int j = 0; j < test_dof; j++)
2039  {
2040  for (int k = 0; k < trial_dof; k++)
2041  {
2042  double Kv = 0.0;
2043  for (int vd = 0; vd < spaceDim; vd++)
2044  {
2045  Kv += K(d, vd) * trial_vshape(k, vd);
2046  }
2047  elmat(d * test_dof + j, k) += shape(j) * Kv;
2048  }
2049  }
2050  }
2051  }
2052  else
2053  {
2054  if (Q)
2055  {
2056  w *= Q->Eval(Trans, ip);
2057  }
2058  for (int d = 0; d < vdim; d++)
2059  {
2060  for (int j = 0; j < test_dof; j++)
2061  {
2062  for (int k = 0; k < trial_dof; k++)
2063  {
2064  elmat(d * test_dof + j, k) +=
2065  w * shape(j) * trial_vshape(k, d);
2066  }
2067  }
2068  }
2069  }
2070  }
2071  }
2072  else if (test_fe.GetRangeType() == FiniteElement::VECTOR
2073  && trial_fe.GetRangeType() == FiniteElement::VECTOR)
2074  {
2075  // assume both test_fe and trial_fe are vector FE
2076  int spaceDim = Trans.GetSpaceDim();
2077  int trial_dof = trial_fe.GetDof();
2078  int test_dof = test_fe.GetDof();
2079  double w;
2080 
2081 #ifdef MFEM_THREAD_SAFE
2082  DenseMatrix trial_vshape(trial_dof,spaceDim);
2083  DenseMatrix test_vshape(test_dof,spaceDim);
2084  Vector D(VQ ? VQ->GetVDim() : 0);
2085  DenseMatrix K(MQ ? MQ->GetVDim() : 0, MQ ? MQ->GetVDim() : 0);
2086 #else
2087  trial_vshape.SetSize(trial_dof,spaceDim);
2088  test_vshape.SetSize(test_dof,spaceDim);
2089  D.SetSize(VQ ? VQ->GetVDim() : 0);
2090  K.SetSize(MQ ? MQ->GetVDim() : 0, MQ ? MQ->GetVDim() : 0);
2091 #endif
2092  DenseMatrix tmp(test_vshape.Height(), K.Width());
2093 
2094  elmat.SetSize (test_dof, trial_dof);
2095 
2096  const IntegrationRule *ir = IntRule;
2097  if (ir == NULL)
2098  {
2099  int order = (Trans.OrderW() + test_fe.GetOrder() + trial_fe.GetOrder());
2100  ir = &IntRules.Get(test_fe.GetGeomType(), order);
2101  }
2102 
2103  elmat = 0.0;
2104  for (int i = 0; i < ir->GetNPoints(); i++)
2105  {
2106  const IntegrationPoint &ip = ir->IntPoint(i);
2107 
2108  Trans.SetIntPoint (&ip);
2109 
2110  trial_fe.CalcVShape(Trans, trial_vshape);
2111  test_fe.CalcVShape(Trans, test_vshape);
2112 
2113  w = ip.weight * Trans.Weight();
2114  if (MQ)
2115  {
2116  MQ->Eval(K, Trans, ip);
2117  K *= w;
2118  Mult(test_vshape,K,tmp);
2119  AddMultABt(tmp,trial_vshape,elmat);
2120  }
2121  else if (VQ)
2122  {
2123  VQ->Eval(D, Trans, ip);
2124  D *= w;
2125  AddMultADBt(test_vshape,D,trial_vshape,elmat);
2126  }
2127  else
2128  {
2129  if (Q)
2130  {
2131  w *= Q -> Eval (Trans, ip);
2132  }
2133  AddMult_a_ABt(w,test_vshape,trial_vshape,elmat);
2134  }
2135  }
2136  }
2137  else
2138  {
2139  mfem_error("VectorFEMassIntegrator::AssembleElementMatrix2(...)\n"
2140  " is not implemented for given trial and test bases.");
2141  }
2142 }
2143 
2144 void VectorDivergenceIntegrator::AssembleElementMatrix2(
2145  const FiniteElement &trial_fe,
2146  const FiniteElement &test_fe,
2147  ElementTransformation &Trans,
2148  DenseMatrix &elmat)
2149 {
2150  int dim = trial_fe.GetDim();
2151  int trial_dof = trial_fe.GetDof();
2152  int test_dof = test_fe.GetDof();
2153  double c;
2154 
2155  dshape.SetSize (trial_dof, dim);
2156  gshape.SetSize (trial_dof, dim);
2157  Jadj.SetSize (dim);
2158  divshape.SetSize (dim*trial_dof);
2159  shape.SetSize (test_dof);
2160 
2161  elmat.SetSize (test_dof, dim*trial_dof);
2162 
2163  const IntegrationRule *ir = IntRule ? IntRule : &GetRule(trial_fe, test_fe,
2164  Trans);
2165 
2166  elmat = 0.0;
2167 
2168  for (int i = 0; i < ir -> GetNPoints(); i++)
2169  {
2170  const IntegrationPoint &ip = ir->IntPoint(i);
2171 
2172  trial_fe.CalcDShape (ip, dshape);
2173  test_fe.CalcShape (ip, shape);
2174 
2175  Trans.SetIntPoint (&ip);
2176  CalcAdjugate(Trans.Jacobian(), Jadj);
2177 
2178  Mult (dshape, Jadj, gshape);
2179 
2180  gshape.GradToDiv (divshape);
2181 
2182  c = ip.weight;
2183  if (Q)
2184  {
2185  c *= Q -> Eval (Trans, ip);
2186  }
2187 
2188  // elmat += c * shape * divshape ^ t
2189  shape *= c;
2190  AddMultVWt (shape, divshape, elmat);
2191  }
2192 }
2193 
2194 const IntegrationRule &VectorDivergenceIntegrator::GetRule(
2195  const FiniteElement &trial_fe,
2196  const FiniteElement &test_fe,
2197  ElementTransformation &Trans)
2198 {
2199  int order = Trans.OrderGrad(&trial_fe) + test_fe.GetOrder() + Trans.OrderJ();
2200  return IntRules.Get(trial_fe.GetGeomType(), order);
2201 }
2202 
2203 
2204 void DivDivIntegrator::AssembleElementMatrix(
2205  const FiniteElement &el,
2206  ElementTransformation &Trans,
2207  DenseMatrix &elmat)
2208 {
2209  int dof = el.GetDof();
2210  double c;
2211 
2212 #ifdef MFEM_THREAD_SAFE
2213  Vector divshape(dof);
2214 #else
2215  divshape.SetSize(dof);
2216 #endif
2217  elmat.SetSize(dof);
2218 
2219  const IntegrationRule *ir = IntRule;
2220  if (ir == NULL)
2221  {
2222  int order = 2 * el.GetOrder() - 2; // <--- OK for RTk
2223  ir = &IntRules.Get(el.GetGeomType(), order);
2224  }
2225 
2226  elmat = 0.0;
2227 
2228  for (int i = 0; i < ir -> GetNPoints(); i++)
2229  {
2230  const IntegrationPoint &ip = ir->IntPoint(i);
2231 
2232  el.CalcDivShape (ip, divshape);
2233 
2234  Trans.SetIntPoint (&ip);
2235  c = ip.weight / Trans.Weight();
2236 
2237  if (Q)
2238  {
2239  c *= Q -> Eval (Trans, ip);
2240  }
2241 
2242  // elmat += c * divshape * divshape ^ t
2243  AddMult_a_VVt (c, divshape, elmat);
2244  }
2245 }
2246 
2247 
2248 void VectorDiffusionIntegrator::AssembleElementMatrix(
2249  const FiniteElement &el,
2250  ElementTransformation &Trans,
2251  DenseMatrix &elmat)
2252 {
2253  const int dim = el.GetDim();
2254  const int dof = el.GetDof();
2255  const int sdim = Trans.GetSpaceDim();
2256  const bool square = (dim == sdim);
2257  double w;
2258 
2259  elmat.SetSize(sdim * dof);
2260 
2261  dshape.SetSize(dof, dim);
2262  dshapedxt.SetSize(dof, sdim);
2263  pelmat.SetSize(dof);
2264 
2265  const IntegrationRule *ir = IntRule;
2266  if (ir == NULL)
2267  {
2268  ir = &DiffusionIntegrator::GetRule(el,el);
2269  }
2270 
2271  elmat = 0.0;
2272  pelmat = 0.0;
2273 
2274  for (int i = 0; i < ir -> GetNPoints(); i++)
2275  {
2276  const IntegrationPoint &ip = ir->IntPoint(i);
2277  el.CalcDShape (ip, dshape);
2278  Trans.SetIntPoint (&ip);
2279  w = Trans.Weight();
2280  w = ip.weight / (square ? w : w*w*w);
2281  // AdjugateJacobian = / adj(J), if J is square
2282  // \ adj(J^t.J).J^t, otherwise
2283  Mult(dshape, Trans.AdjugateJacobian(), dshapedxt);
2284  if (Q) { w *= Q -> Eval (Trans, ip); }
2285  AddMult_a_AAt(w, dshapedxt, pelmat);
2286  }
2287  for (int d = 0; d < sdim; d++)
2288  {
2289  for (int k = 0; k < dof; k++)
2290  {
2291  for (int l = 0; l < dof; l++)
2292  {
2293  elmat(dof*d+k, dof*d+l) = pelmat(k, l);
2294  }
2295  }
2296  }
2297 }
2298 
2299 void VectorDiffusionIntegrator::AssembleElementVector(
2300  const FiniteElement &el, ElementTransformation &Tr,
2301  const Vector &elfun, Vector &elvect)
2302 {
2303  int dim = el.GetDim(); // assuming vector_dim == reference_dim
2304  int dof = el.GetDof();
2305  double w;
2306 
2307  Jinv.SetSize(dim);
2308  dshape.SetSize(dof, dim);
2309  pelmat.SetSize(dim);
2310  gshape.SetSize(dim);
2311 
2312  elvect.SetSize(dim*dof);
2313  DenseMatrix mat_in(elfun.GetData(), dof, dim);
2314  DenseMatrix mat_out(elvect.GetData(), dof, dim);
2315 
2316  const IntegrationRule *ir = IntRule;
2317  if (ir == NULL)
2318  {
2319  ir = &DiffusionIntegrator::GetRule(el,el);
2320  }
2321 
2322  elvect = 0.0;
2323  for (int i = 0; i < ir->GetNPoints(); i++)
2324  {
2325  const IntegrationPoint &ip = ir->IntPoint(i);
2326 
2327  Tr.SetIntPoint(&ip);
2328  CalcAdjugate(Tr.Jacobian(), Jinv);
2329  w = ip.weight / Tr.Weight();
2330  if (Q)
2331  {
2332  w *= Q->Eval(Tr, ip);
2333  }
2334  MultAAt(Jinv, gshape);
2335  gshape *= w;
2336 
2337  el.CalcDShape(ip, dshape);
2338 
2339  MultAtB(mat_in, dshape, pelmat);
2340  MultABt(pelmat, gshape, Jinv);
2341  AddMultABt(dshape, Jinv, mat_out);
2342  }
2343 }
2344 
2345 
2346 void ElasticityIntegrator::AssembleElementMatrix(
2347  const FiniteElement &el, ElementTransformation &Trans, DenseMatrix &elmat)
2348 {
2349  int dof = el.GetDof();
2350  int dim = el.GetDim();
2351  double w, L, M;
2352 
2353  MFEM_ASSERT(dim == Trans.GetSpaceDim(), "");
2354 
2355 #ifdef MFEM_THREAD_SAFE
2356  DenseMatrix dshape(dof, dim), gshape(dof, dim), pelmat(dof);
2357  Vector divshape(dim*dof);
2358 #else
2359  dshape.SetSize(dof, dim);
2360  gshape.SetSize(dof, dim);
2361  pelmat.SetSize(dof);
2362  divshape.SetSize(dim*dof);
2363 #endif
2364 
2365  elmat.SetSize(dof * dim);
2366 
2367  const IntegrationRule *ir = IntRule;
2368  if (ir == NULL)
2369  {
2370  int order = 2 * Trans.OrderGrad(&el); // correct order?
2371  ir = &IntRules.Get(el.GetGeomType(), order);
2372  }
2373 
2374  elmat = 0.0;
2375 
2376  for (int i = 0; i < ir -> GetNPoints(); i++)
2377  {
2378  const IntegrationPoint &ip = ir->IntPoint(i);
2379 
2380  el.CalcDShape(ip, dshape);
2381 
2382  Trans.SetIntPoint(&ip);
2383  w = ip.weight * Trans.Weight();
2384  Mult(dshape, Trans.InverseJacobian(), gshape);
2385  MultAAt(gshape, pelmat);
2386  gshape.GradToDiv (divshape);
2387 
2388  M = mu->Eval(Trans, ip);
2389  if (lambda)
2390  {
2391  L = lambda->Eval(Trans, ip);
2392  }
2393  else
2394  {
2395  L = q_lambda * M;
2396  M = q_mu * M;
2397  }
2398 
2399  if (L != 0.0)
2400  {
2401  AddMult_a_VVt(L * w, divshape, elmat);
2402  }
2403 
2404  if (M != 0.0)
2405  {
2406  for (int d = 0; d < dim; d++)
2407  {
2408  for (int k = 0; k < dof; k++)
2409  for (int l = 0; l < dof; l++)
2410  {
2411  elmat (dof*d+k, dof*d+l) += (M * w) * pelmat(k, l);
2412  }
2413  }
2414  for (int i = 0; i < dim; i++)
2415  for (int j = 0; j < dim; j++)
2416  {
2417  for (int k = 0; k < dof; k++)
2418  for (int l = 0; l < dof; l++)
2419  {
2420  elmat(dof*i+k, dof*j+l) +=
2421  (M * w) * gshape(k, j) * gshape(l, i);
2422  }
2423  }
2424  }
2425  }
2426 }
2427 
2428 void ElasticityIntegrator::ComputeElementFlux(
2429  const mfem::FiniteElement &el, ElementTransformation &Trans,
2430  Vector &u, const mfem::FiniteElement &fluxelem, Vector &flux,
2431  bool with_coef)
2432 {
2433  const int dof = el.GetDof();
2434  const int dim = el.GetDim();
2435  const int tdim = dim*(dim+1)/2; // num. entries in a symmetric tensor
2436  double L, M;
2437 
2438  MFEM_ASSERT(dim == 2 || dim == 3,
2439  "dimension is not supported: dim = " << dim);
2440  MFEM_ASSERT(dim == Trans.GetSpaceDim(), "");
2441  MFEM_ASSERT(fluxelem.GetMapType() == FiniteElement::VALUE, "");
2442  MFEM_ASSERT(dynamic_cast<const NodalFiniteElement*>(&fluxelem), "");
2443 
2444 #ifdef MFEM_THREAD_SAFE
2445  DenseMatrix dshape(dof, dim);
2446 #else
2447  dshape.SetSize(dof, dim);
2448 #endif
2449 
2450  double gh_data[9], grad_data[9];
2451  DenseMatrix gh(gh_data, dim, dim);
2452  DenseMatrix grad(grad_data, dim, dim);
2453 
2454  const IntegrationRule &ir = fluxelem.GetNodes();
2455  const int fnd = ir.GetNPoints();
2456  flux.SetSize(fnd * tdim);
2457 
2458  DenseMatrix loc_data_mat(u.GetData(), dof, dim);
2459  for (int i = 0; i < fnd; i++)
2460  {
2461  const IntegrationPoint &ip = ir.IntPoint(i);
2462  el.CalcDShape(ip, dshape);
2463  MultAtB(loc_data_mat, dshape, gh);
2464 
2465  Trans.SetIntPoint(&ip);
2466  Mult(gh, Trans.InverseJacobian(), grad);
2467 
2468  M = mu->Eval(Trans, ip);
2469  if (lambda)
2470  {
2471  L = lambda->Eval(Trans, ip);
2472  }
2473  else
2474  {
2475  L = q_lambda * M;
2476  M = q_mu * M;
2477  }
2478 
2479  // stress = 2*M*e(u) + L*tr(e(u))*I, where
2480  // e(u) = (1/2)*(grad(u) + grad(u)^T)
2481  const double M2 = 2.0*M;
2482  if (dim == 2)
2483  {
2484  L *= (grad(0,0) + grad(1,1));
2485  // order of the stress entries: s_xx, s_yy, s_xy
2486  flux(i+fnd*0) = M2*grad(0,0) + L;
2487  flux(i+fnd*1) = M2*grad(1,1) + L;
2488  flux(i+fnd*2) = M*(grad(0,1) + grad(1,0));
2489  }
2490  else if (dim == 3)
2491  {
2492  L *= (grad(0,0) + grad(1,1) + grad(2,2));
2493  // order of the stress entries: s_xx, s_yy, s_zz, s_xy, s_xz, s_yz
2494  flux(i+fnd*0) = M2*grad(0,0) + L;
2495  flux(i+fnd*1) = M2*grad(1,1) + L;
2496  flux(i+fnd*2) = M2*grad(2,2) + L;
2497  flux(i+fnd*3) = M*(grad(0,1) + grad(1,0));
2498  flux(i+fnd*4) = M*(grad(0,2) + grad(2,0));
2499  flux(i+fnd*5) = M*(grad(1,2) + grad(2,1));
2500  }
2501  }
2502 }
2503 
2504 double ElasticityIntegrator::ComputeFluxEnergy(const FiniteElement &fluxelem,
2505  ElementTransformation &Trans,
2506  Vector &flux, Vector *d_energy)
2507 {
2508  const int dof = fluxelem.GetDof();
2509  const int dim = fluxelem.GetDim();
2510  const int tdim = dim*(dim+1)/2; // num. entries in a symmetric tensor
2511  double L, M;
2512 
2513  // The MFEM_ASSERT constraints in ElasticityIntegrator::ComputeElementFlux
2514  // are assumed here too.
2515  MFEM_ASSERT(d_energy == NULL, "anisotropic estimates are not supported");
2516  MFEM_ASSERT(flux.Size() == dof*tdim, "invalid 'flux' vector");
2517 
2518 #ifndef MFEM_THREAD_SAFE
2519  shape.SetSize(dof);
2520 #else
2521  Vector shape(dof);
2522 #endif
2523  double pointstress_data[6];
2524  Vector pointstress(pointstress_data, tdim);
2525 
2526  // View of the 'flux' vector as a (dof x tdim) matrix
2527  DenseMatrix flux_mat(flux.GetData(), dof, tdim);
2528 
2529  // Use the same integration rule as in AssembleElementMatrix, replacing 'el'
2530  // with 'fluxelem' when 'IntRule' is not set.
2531  // Should we be using a different (more accurate) rule here?
2532  const IntegrationRule *ir = IntRule;
2533  if (ir == NULL)
2534  {
2535  int order = 2 * Trans.OrderGrad(&fluxelem);
2536  ir = &IntRules.Get(fluxelem.GetGeomType(), order);
2537  }
2538 
2539  double energy = 0.0;
2540 
2541  for (int i = 0; i < ir->GetNPoints(); i++)
2542  {
2543  const IntegrationPoint &ip = ir->IntPoint(i);
2544  fluxelem.CalcShape(ip, shape);
2545 
2546  flux_mat.MultTranspose(shape, pointstress);
2547 
2548  Trans.SetIntPoint(&ip);
2549  double w = Trans.Weight() * ip.weight;
2550 
2551  M = mu->Eval(Trans, ip);
2552  if (lambda)
2553  {
2554  L = lambda->Eval(Trans, ip);
2555  }
2556  else
2557  {
2558  L = q_lambda * M;
2559  M = q_mu * M;
2560  }
2561 
2562  // The strain energy density at a point is given by (1/2)*(s : e) where s
2563  // and e are the stress and strain tensors, respectively. Since we only
2564  // have the stress, we need to compute the strain from the stress:
2565  // s = 2*mu*e + lambda*tr(e)*I
2566  // Taking trace on both sides we find:
2567  // tr(s) = 2*mu*tr(e) + lambda*tr(e)*dim = (2*mu + dim*lambda)*tr(e)
2568  // which gives:
2569  // tr(e) = tr(s)/(2*mu + dim*lambda)
2570  // Then from the first identity above we can find the strain:
2571  // e = (1/(2*mu))*(s - lambda*tr(e)*I)
2572 
2573  double pt_e; // point strain energy density
2574  const double *s = pointstress_data;
2575  if (dim == 2)
2576  {
2577  // s entries: s_xx, s_yy, s_xy
2578  const double tr_e = (s[0] + s[1])/(2*(M + L));
2579  L *= tr_e;
2580  pt_e = (0.25/M)*(s[0]*(s[0] - L) + s[1]*(s[1] - L) + 2*s[2]*s[2]);
2581  }
2582  else // (dim == 3)
2583  {
2584  // s entries: s_xx, s_yy, s_zz, s_xy, s_xz, s_yz
2585  const double tr_e = (s[0] + s[1] + s[2])/(2*M + 3*L);
2586  L *= tr_e;
2587  pt_e = (0.25/M)*(s[0]*(s[0] - L) + s[1]*(s[1] - L) + s[2]*(s[2] - L) +
2588  2*(s[3]*s[3] + s[4]*s[4] + s[5]*s[5]));
2589  }
2590 
2591  energy += w * pt_e;
2592  }
2593 
2594  return energy;
2595 }
2596 
2597 void DGTraceIntegrator::AssembleFaceMatrix(const FiniteElement &el1,
2598  const FiniteElement &el2,
2600  DenseMatrix &elmat)
2601 {
2602  int dim, ndof1, ndof2;
2603 
2604  double un, a, b, w;
2605 
2606  dim = el1.GetDim();
2607  ndof1 = el1.GetDof();
2608  Vector vu(dim), nor(dim);
2609 
2610  if (Trans.Elem2No >= 0)
2611  {
2612  ndof2 = el2.GetDof();
2613  }
2614  else
2615  {
2616  ndof2 = 0;
2617  }
2618 
2619  shape1.SetSize(ndof1);
2620  shape2.SetSize(ndof2);
2621  elmat.SetSize(ndof1 + ndof2);
2622  elmat = 0.0;
2623 
2624  const IntegrationRule *ir = IntRule;
2625  if (ir == NULL)
2626  {
2627  int order;
2628  // Assuming order(u)==order(mesh)
2629  if (Trans.Elem2No >= 0)
2630  order = (min(Trans.Elem1->OrderW(), Trans.Elem2->OrderW()) +
2631  2*max(el1.GetOrder(), el2.GetOrder()));
2632  else
2633  {
2634  order = Trans.Elem1->OrderW() + 2*el1.GetOrder();
2635  }
2636  if (el1.Space() == FunctionSpace::Pk)
2637  {
2638  order++;
2639  }
2640  ir = &IntRules.Get(Trans.GetGeometryType(), order);
2641  }
2642 
2643  for (int p = 0; p < ir->GetNPoints(); p++)
2644  {
2645  const IntegrationPoint &ip = ir->IntPoint(p);
2646 
2647  // Set the integration point in the face and the neighboring elements
2648  Trans.SetAllIntPoints(&ip);
2649 
2650  // Access the neighboring elements' integration points
2651  // Note: eip2 will only contain valid data if Elem2 exists
2652  const IntegrationPoint &eip1 = Trans.GetElement1IntPoint();
2653  const IntegrationPoint &eip2 = Trans.GetElement2IntPoint();
2654 
2655  el1.CalcShape(eip1, shape1);
2656 
2657  u->Eval(vu, *Trans.Elem1, eip1);
2658 
2659  if (dim == 1)
2660  {
2661  nor(0) = 2*eip1.x - 1.0;
2662  }
2663  else
2664  {
2665  CalcOrtho(Trans.Jacobian(), nor);
2666  }
2667 
2668  un = vu * nor;
2669  a = 0.5 * alpha * un;
2670  b = beta * fabs(un);
2671  // note: if |alpha/2|==|beta| then |a|==|b|, i.e. (a==b) or (a==-b)
2672  // and therefore two blocks in the element matrix contribution
2673  // (from the current quadrature point) are 0
2674 
2675  if (rho)
2676  {
2677  double rho_p;
2678  if (un >= 0.0 && ndof2)
2679  {
2680  rho_p = rho->Eval(*Trans.Elem2, eip2);
2681  }
2682  else
2683  {
2684  rho_p = rho->Eval(*Trans.Elem1, eip1);
2685  }
2686  a *= rho_p;
2687  b *= rho_p;
2688  }
2689 
2690  w = ip.weight * (a+b);
2691  if (w != 0.0)
2692  {
2693  for (int i = 0; i < ndof1; i++)
2694  for (int j = 0; j < ndof1; j++)
2695  {
2696  elmat(i, j) += w * shape1(i) * shape1(j);
2697  }
2698  }
2699 
2700  if (ndof2)
2701  {
2702  el2.CalcShape(eip2, shape2);
2703 
2704  if (w != 0.0)
2705  for (int i = 0; i < ndof2; i++)
2706  for (int j = 0; j < ndof1; j++)
2707  {
2708  elmat(ndof1+i, j) -= w * shape2(i) * shape1(j);
2709  }
2710 
2711  w = ip.weight * (b-a);
2712  if (w != 0.0)
2713  {
2714  for (int i = 0; i < ndof2; i++)
2715  for (int j = 0; j < ndof2; j++)
2716  {
2717  elmat(ndof1+i, ndof1+j) += w * shape2(i) * shape2(j);
2718  }
2719 
2720  for (int i = 0; i < ndof1; i++)
2721  for (int j = 0; j < ndof2; j++)
2722  {
2723  elmat(i, ndof1+j) -= w * shape1(i) * shape2(j);
2724  }
2725  }
2726  }
2727  }
2728 }
2729 
2730 
2731 const IntegrationRule &DGTraceIntegrator::GetRule(
2733 {
2734  int int_order = T.Elem1->OrderW() + 2*order;
2735  return IntRules.Get(geom, int_order);
2736 }
2737 
2738 void DGDiffusionIntegrator::AssembleFaceMatrix(
2739  const FiniteElement &el1, const FiniteElement &el2,
2740  FaceElementTransformations &Trans, DenseMatrix &elmat)
2741 {
2742  int dim, ndof1, ndof2, ndofs;
2743  bool kappa_is_nonzero = (kappa != 0.);
2744  double w, wq = 0.0;
2745 
2746  dim = el1.GetDim();
2747  ndof1 = el1.GetDof();
2748 
2749  nor.SetSize(dim);
2750  nh.SetSize(dim);
2751  ni.SetSize(dim);
2752  adjJ.SetSize(dim);
2753  if (MQ)
2754  {
2755  mq.SetSize(dim);
2756  }
2757 
2758  shape1.SetSize(ndof1);
2759  dshape1.SetSize(ndof1, dim);
2760  dshape1dn.SetSize(ndof1);
2761  if (Trans.Elem2No >= 0)
2762  {
2763  ndof2 = el2.GetDof();
2764  shape2.SetSize(ndof2);
2765  dshape2.SetSize(ndof2, dim);
2766  dshape2dn.SetSize(ndof2);
2767  }
2768  else
2769  {
2770  ndof2 = 0;
2771  }
2772 
2773  ndofs = ndof1 + ndof2;
2774  elmat.SetSize(ndofs);
2775  elmat = 0.0;
2776  if (kappa_is_nonzero)
2777  {
2778  jmat.SetSize(ndofs);
2779  jmat = 0.;
2780  }
2781 
2782  const IntegrationRule *ir = IntRule;
2783  if (ir == NULL)
2784  {
2785  // a simple choice for the integration order; is this OK?
2786  int order;
2787  if (ndof2)
2788  {
2789  order = 2*max(el1.GetOrder(), el2.GetOrder());
2790  }
2791  else
2792  {
2793  order = 2*el1.GetOrder();
2794  }
2795  ir = &IntRules.Get(Trans.GetGeometryType(), order);
2796  }
2797 
2798  // assemble: < {(Q \nabla u).n},[v] > --> elmat
2799  // kappa < {h^{-1} Q} [u],[v] > --> jmat
2800  for (int p = 0; p < ir->GetNPoints(); p++)
2801  {
2802  const IntegrationPoint &ip = ir->IntPoint(p);
2803 
2804  // Set the integration point in the face and the neighboring elements
2805  Trans.SetAllIntPoints(&ip);
2806 
2807  // Access the neighboring elements' integration points
2808  // Note: eip2 will only contain valid data if Elem2 exists
2809  const IntegrationPoint &eip1 = Trans.GetElement1IntPoint();
2810  const IntegrationPoint &eip2 = Trans.GetElement2IntPoint();
2811 
2812  if (dim == 1)
2813  {
2814  nor(0) = 2*eip1.x - 1.0;
2815  }
2816  else
2817  {
2818  CalcOrtho(Trans.Jacobian(), nor);
2819  }
2820 
2821  el1.CalcShape(eip1, shape1);
2822  el1.CalcDShape(eip1, dshape1);
2823  w = ip.weight/Trans.Elem1->Weight();
2824  if (ndof2)
2825  {
2826  w /= 2;
2827  }
2828  if (!MQ)
2829  {
2830  if (Q)
2831  {
2832  w *= Q->Eval(*Trans.Elem1, eip1);
2833  }
2834  ni.Set(w, nor);
2835  }
2836  else
2837  {
2838  nh.Set(w, nor);
2839  MQ->Eval(mq, *Trans.Elem1, eip1);
2840  mq.MultTranspose(nh, ni);
2841  }
2842  CalcAdjugate(Trans.Elem1->Jacobian(), adjJ);
2843  adjJ.Mult(ni, nh);
2844  if (kappa_is_nonzero)
2845  {
2846  wq = ni * nor;
2847  }
2848  // Note: in the jump term, we use 1/h1 = |nor|/det(J1) which is
2849  // independent of Loc1 and always gives the size of element 1 in
2850  // direction perpendicular to the face. Indeed, for linear transformation
2851  // |nor|=measure(face)/measure(ref. face),
2852  // det(J1)=measure(element)/measure(ref. element),
2853  // and the ratios measure(ref. element)/measure(ref. face) are
2854  // compatible for all element/face pairs.
2855  // For example: meas(ref. tetrahedron)/meas(ref. triangle) = 1/3, and
2856  // for any tetrahedron vol(tet)=(1/3)*height*area(base).
2857  // For interior faces: q_e/h_e=(q1/h1+q2/h2)/2.
2858 
2859  dshape1.Mult(nh, dshape1dn);
2860  for (int i = 0; i < ndof1; i++)
2861  for (int j = 0; j < ndof1; j++)
2862  {
2863  elmat(i, j) += shape1(i) * dshape1dn(j);
2864  }
2865 
2866  if (ndof2)
2867  {
2868  el2.CalcShape(eip2, shape2);
2869  el2.CalcDShape(eip2, dshape2);
2870  w = ip.weight/2/Trans.Elem2->Weight();
2871  if (!MQ)
2872  {
2873  if (Q)
2874  {
2875  w *= Q->Eval(*Trans.Elem2, eip2);
2876  }
2877  ni.Set(w, nor);
2878  }
2879  else
2880  {
2881  nh.Set(w, nor);
2882  MQ->Eval(mq, *Trans.Elem2, eip2);
2883  mq.MultTranspose(nh, ni);
2884  }
2885  CalcAdjugate(Trans.Elem2->Jacobian(), adjJ);
2886  adjJ.Mult(ni, nh);
2887  if (kappa_is_nonzero)
2888  {
2889  wq += ni * nor;
2890  }
2891 
2892  dshape2.Mult(nh, dshape2dn);
2893 
2894  for (int i = 0; i < ndof1; i++)
2895  for (int j = 0; j < ndof2; j++)
2896  {
2897  elmat(i, ndof1 + j) += shape1(i) * dshape2dn(j);
2898  }
2899 
2900  for (int i = 0; i < ndof2; i++)
2901  for (int j = 0; j < ndof1; j++)
2902  {
2903  elmat(ndof1 + i, j) -= shape2(i) * dshape1dn(j);
2904  }
2905 
2906  for (int i = 0; i < ndof2; i++)
2907  for (int j = 0; j < ndof2; j++)
2908  {
2909  elmat(ndof1 + i, ndof1 + j) -= shape2(i) * dshape2dn(j);
2910  }
2911  }
2912 
2913  if (kappa_is_nonzero)
2914  {
2915  // only assemble the lower triangular part of jmat
2916  wq *= kappa;
2917  for (int i = 0; i < ndof1; i++)
2918  {
2919  const double wsi = wq*shape1(i);
2920  for (int j = 0; j <= i; j++)
2921  {
2922  jmat(i, j) += wsi * shape1(j);
2923  }
2924  }
2925  if (ndof2)
2926  {
2927  for (int i = 0; i < ndof2; i++)
2928  {
2929  const int i2 = ndof1 + i;
2930  const double wsi = wq*shape2(i);
2931  for (int j = 0; j < ndof1; j++)
2932  {
2933  jmat(i2, j) -= wsi * shape1(j);
2934  }
2935  for (int j = 0; j <= i; j++)
2936  {
2937  jmat(i2, ndof1 + j) += wsi * shape2(j);
2938  }
2939  }
2940  }
2941  }
2942  }
2943 
2944  // elmat := -elmat + sigma*elmat^t + jmat
2945  if (kappa_is_nonzero)
2946  {
2947  for (int i = 0; i < ndofs; i++)
2948  {
2949  for (int j = 0; j < i; j++)
2950  {
2951  double aij = elmat(i,j), aji = elmat(j,i), mij = jmat(i,j);
2952  elmat(i,j) = sigma*aji - aij + mij;
2953  elmat(j,i) = sigma*aij - aji + mij;
2954  }
2955  elmat(i,i) = (sigma - 1.)*elmat(i,i) + jmat(i,i);
2956  }
2957  }
2958  else
2959  {
2960  for (int i = 0; i < ndofs; i++)
2961  {
2962  for (int j = 0; j < i; j++)
2963  {
2964  double aij = elmat(i,j), aji = elmat(j,i);
2965  elmat(i,j) = sigma*aji - aij;
2966  elmat(j,i) = sigma*aij - aji;
2967  }
2968  elmat(i,i) *= (sigma - 1.);
2969  }
2970  }
2971 }
2972 
2973 
2974 // static method
2975 void DGElasticityIntegrator::AssembleBlock(
2976  const int dim, const int row_ndofs, const int col_ndofs,
2977  const int row_offset, const int col_offset,
2978  const double jmatcoef, const Vector &col_nL, const Vector &col_nM,
2979  const Vector &row_shape, const Vector &col_shape,
2980  const Vector &col_dshape_dnM, const DenseMatrix &col_dshape,
2981  DenseMatrix &elmat, DenseMatrix &jmat)
2982 {
2983  for (int jm = 0, j = col_offset; jm < dim; ++jm)
2984  {
2985  for (int jdof = 0; jdof < col_ndofs; ++jdof, ++j)
2986  {
2987  const double t2 = col_dshape_dnM(jdof);
2988  for (int im = 0, i = row_offset; im < dim; ++im)
2989  {
2990  const double t1 = col_dshape(jdof, jm) * col_nL(im);
2991  const double t3 = col_dshape(jdof, im) * col_nM(jm);
2992  const double tt = t1 + ((im == jm) ? t2 : 0.0) + t3;
2993  for (int idof = 0; idof < row_ndofs; ++idof, ++i)
2994  {
2995  elmat(i, j) += row_shape(idof) * tt;
2996  }
2997  }
2998  }
2999  }
3000 
3001  if (jmatcoef == 0.0) { return; }
3002 
3003  for (int d = 0; d < dim; ++d)
3004  {
3005  const int jo = col_offset + d*col_ndofs;
3006  const int io = row_offset + d*row_ndofs;
3007  for (int jdof = 0, j = jo; jdof < col_ndofs; ++jdof, ++j)
3008  {
3009  const double sj = jmatcoef * col_shape(jdof);
3010  for (int i = max(io,j), idof = i - io; idof < row_ndofs; ++idof, ++i)
3011  {
3012  jmat(i, j) += row_shape(idof) * sj;
3013  }
3014  }
3015  }
3016 }
3017 
3018 void DGElasticityIntegrator::AssembleFaceMatrix(
3019  const FiniteElement &el1, const FiniteElement &el2,
3020  FaceElementTransformations &Trans, DenseMatrix &elmat)
3021 {
3022 #ifdef MFEM_THREAD_SAFE
3023  // For descriptions of these variables, see the class declaration.
3024  Vector shape1, shape2;
3025  DenseMatrix dshape1, dshape2;
3026  DenseMatrix adjJ;
3027  DenseMatrix dshape1_ps, dshape2_ps;
3028  Vector nor;
3029  Vector nL1, nL2;
3030  Vector nM1, nM2;
3031  Vector dshape1_dnM, dshape2_dnM;
3032  DenseMatrix jmat;
3033 #endif
3034 
3035  const int dim = el1.GetDim();
3036  const int ndofs1 = el1.GetDof();
3037  const int ndofs2 = (Trans.Elem2No >= 0) ? el2.GetDof() : 0;
3038  const int nvdofs = dim*(ndofs1 + ndofs2);
3039 
3040  // Initially 'elmat' corresponds to the term:
3041  // < { sigma(u) . n }, [v] > =
3042  // < { (lambda div(u) I + mu (grad(u) + grad(u)^T)) . n }, [v] >
3043  // But eventually, it's going to be replaced by:
3044  // elmat := -elmat + alpha*elmat^T + jmat
3045  elmat.SetSize(nvdofs);
3046  elmat = 0.;
3047 
3048  const bool kappa_is_nonzero = (kappa != 0.0);
3049  if (kappa_is_nonzero)
3050  {
3051  jmat.SetSize(nvdofs);
3052  jmat = 0.;
3053  }
3054 
3055  adjJ.SetSize(dim);
3056  shape1.SetSize(ndofs1);
3057  dshape1.SetSize(ndofs1, dim);
3058  dshape1_ps.SetSize(ndofs1, dim);
3059  nor.SetSize(dim);
3060  nL1.SetSize(dim);
3061  nM1.SetSize(dim);
3062  dshape1_dnM.SetSize(ndofs1);
3063 
3064  if (ndofs2)
3065  {
3066  shape2.SetSize(ndofs2);
3067  dshape2.SetSize(ndofs2, dim);
3068  dshape2_ps.SetSize(ndofs2, dim);
3069  nL2.SetSize(dim);
3070  nM2.SetSize(dim);
3071  dshape2_dnM.SetSize(ndofs2);
3072  }
3073 
3074  const IntegrationRule *ir = IntRule;
3075  if (ir == NULL)
3076  {
3077  // a simple choice for the integration order; is this OK?
3078  const int order = 2 * max(el1.GetOrder(), ndofs2 ? el2.GetOrder() : 0);
3079  ir = &IntRules.Get(Trans.GetGeometryType(), order);
3080  }
3081 
3082  for (int pind = 0; pind < ir->GetNPoints(); ++pind)
3083  {
3084  const IntegrationPoint &ip = ir->IntPoint(pind);
3085 
3086  // Set the integration point in the face and the neighboring elements
3087  Trans.SetAllIntPoints(&ip);
3088 
3089  // Access the neighboring elements' integration points
3090  // Note: eip2 will only contain valid data if Elem2 exists
3091  const IntegrationPoint &eip1 = Trans.GetElement1IntPoint();
3092  const IntegrationPoint &eip2 = Trans.GetElement2IntPoint();
3093 
3094  el1.CalcShape(eip1, shape1);
3095  el1.CalcDShape(eip1, dshape1);
3096 
3097  CalcAdjugate(Trans.Elem1->Jacobian(), adjJ);
3098  Mult(dshape1, adjJ, dshape1_ps);
3099 
3100  if (dim == 1)
3101  {
3102  nor(0) = 2*eip1.x - 1.0;
3103  }
3104  else
3105  {
3106  CalcOrtho(Trans.Jacobian(), nor);
3107  }
3108 
3109  double w, wLM;
3110  if (ndofs2)
3111  {
3112  el2.CalcShape(eip2, shape2);
3113  el2.CalcDShape(eip2, dshape2);
3114  CalcAdjugate(Trans.Elem2->Jacobian(), adjJ);
3115  Mult(dshape2, adjJ, dshape2_ps);
3116 
3117  w = ip.weight/2;
3118  const double w2 = w / Trans.Elem2->Weight();
3119  const double wL2 = w2 * lambda->Eval(*Trans.Elem2, eip2);
3120  const double wM2 = w2 * mu->Eval(*Trans.Elem2, eip2);
3121  nL2.Set(wL2, nor);
3122  nM2.Set(wM2, nor);
3123  wLM = (wL2 + 2.0*wM2);
3124  dshape2_ps.Mult(nM2, dshape2_dnM);
3125  }
3126  else
3127  {
3128  w = ip.weight;
3129  wLM = 0.0;
3130  }
3131 
3132  {
3133  const double w1 = w / Trans.Elem1->Weight();
3134  const double wL1 = w1 * lambda->Eval(*Trans.Elem1, eip1);
3135  const double wM1 = w1 * mu->Eval(*Trans.Elem1, eip1);
3136  nL1.Set(wL1, nor);
3137  nM1.Set(wM1, nor);
3138  wLM += (wL1 + 2.0*wM1);
3139  dshape1_ps.Mult(nM1, dshape1_dnM);
3140  }
3141 
3142  const double jmatcoef = kappa * (nor*nor) * wLM;
3143 
3144  // (1,1) block
3145  AssembleBlock(
3146  dim, ndofs1, ndofs1, 0, 0, jmatcoef, nL1, nM1,
3147  shape1, shape1, dshape1_dnM, dshape1_ps, elmat, jmat);
3148 
3149  if (ndofs2 == 0) { continue; }
3150 
3151  // In both elmat and jmat, shape2 appears only with a minus sign.
3152  shape2.Neg();
3153 
3154  // (1,2) block
3155  AssembleBlock(
3156  dim, ndofs1, ndofs2, 0, dim*ndofs1, jmatcoef, nL2, nM2,
3157  shape1, shape2, dshape2_dnM, dshape2_ps, elmat, jmat);
3158  // (2,1) block
3159  AssembleBlock(
3160  dim, ndofs2, ndofs1, dim*ndofs1, 0, jmatcoef, nL1, nM1,
3161  shape2, shape1, dshape1_dnM, dshape1_ps, elmat, jmat);
3162  // (2,2) block
3163  AssembleBlock(
3164  dim, ndofs2, ndofs2, dim*ndofs1, dim*ndofs1, jmatcoef, nL2, nM2,
3165  shape2, shape2, dshape2_dnM, dshape2_ps, elmat, jmat);
3166  }
3167 
3168  // elmat := -elmat + alpha*elmat^t + jmat
3169  if (kappa_is_nonzero)
3170  {
3171  for (int i = 0; i < nvdofs; ++i)
3172  {
3173  for (int j = 0; j < i; ++j)
3174  {
3175  double aij = elmat(i,j), aji = elmat(j,i), mij = jmat(i,j);
3176  elmat(i,j) = alpha*aji - aij + mij;
3177  elmat(j,i) = alpha*aij - aji + mij;
3178  }
3179  elmat(i,i) = (alpha - 1.)*elmat(i,i) + jmat(i,i);
3180  }
3181  }
3182  else
3183  {
3184  for (int i = 0; i < nvdofs; ++i)
3185  {
3186  for (int j = 0; j < i; ++j)
3187  {
3188  double aij = elmat(i,j), aji = elmat(j,i);
3189  elmat(i,j) = alpha*aji - aij;
3190  elmat(j,i) = alpha*aij - aji;
3191  }
3192  elmat(i,i) *= (alpha - 1.);
3193  }
3194  }
3195 }
3196 
3197 
3198 void TraceJumpIntegrator::AssembleFaceMatrix(
3199  const FiniteElement &trial_face_fe, const FiniteElement &test_fe1,
3200  const FiniteElement &test_fe2, FaceElementTransformations &Trans,
3201  DenseMatrix &elmat)
3202 {
3203  int i, j, face_ndof, ndof1, ndof2;
3204  int order;
3205 
3206  double w;
3207 
3208  face_ndof = trial_face_fe.GetDof();
3209  ndof1 = test_fe1.GetDof();
3210 
3211  face_shape.SetSize(face_ndof);
3212  shape1.SetSize(ndof1);
3213 
3214  if (Trans.Elem2No >= 0)
3215  {
3216  ndof2 = test_fe2.GetDof();
3217  shape2.SetSize(ndof2);
3218  }
3219  else
3220  {
3221  ndof2 = 0;
3222  }
3223 
3224  elmat.SetSize(ndof1 + ndof2, face_ndof);
3225  elmat = 0.0;
3226 
3227  const IntegrationRule *ir = IntRule;
3228  if (ir == NULL)
3229  {
3230  if (Trans.Elem2No >= 0)
3231  {
3232  order = max(test_fe1.GetOrder(), test_fe2.GetOrder());
3233  }
3234  else
3235  {
3236  order = test_fe1.GetOrder();
3237  }
3238  order += trial_face_fe.GetOrder();
3239  if (trial_face_fe.GetMapType() == FiniteElement::VALUE)
3240  {
3241  order += Trans.OrderW();
3242  }
3243  ir = &IntRules.Get(Trans.GetGeometryType(), order);
3244  }
3245 
3246  for (int p = 0; p < ir->GetNPoints(); p++)
3247  {
3248  const IntegrationPoint &ip = ir->IntPoint(p);
3249 
3250  // Set the integration point in the face and the neighboring elements
3251  Trans.SetAllIntPoints(&ip);
3252 
3253  // Access the neighboring elements' integration points
3254  // Note: eip2 will only contain valid data if Elem2 exists
3255  const IntegrationPoint &eip1 = Trans.GetElement1IntPoint();
3256  const IntegrationPoint &eip2 = Trans.GetElement2IntPoint();
3257 
3258  // Trace finite element shape function
3259  trial_face_fe.CalcShape(ip, face_shape);
3260  // Side 1 finite element shape function
3261  test_fe1.CalcShape(eip1, shape1);
3262  if (ndof2)
3263  {
3264  // Side 2 finite element shape function
3265  test_fe2.CalcShape(eip2, shape2);
3266  }
3267  w = ip.weight;
3268  if (trial_face_fe.GetMapType() == FiniteElement::VALUE)
3269  {
3270  w *= Trans.Weight();
3271  }
3272  face_shape *= w;
3273  for (i = 0; i < ndof1; i++)
3274  for (j = 0; j < face_ndof; j++)
3275  {
3276  elmat(i, j) += shape1(i) * face_shape(j);
3277  }
3278  if (ndof2)
3279  {
3280  // Subtract contribution from side 2
3281  for (i = 0; i < ndof2; i++)
3282  for (j = 0; j < face_ndof; j++)
3283  {
3284  elmat(ndof1+i, j) -= shape2(i) * face_shape(j);
3285  }
3286  }
3287  }
3288 }
3289 
3290 void NormalTraceJumpIntegrator::AssembleFaceMatrix(
3291  const FiniteElement &trial_face_fe, const FiniteElement &test_fe1,
3292  const FiniteElement &test_fe2, FaceElementTransformations &Trans,
3293  DenseMatrix &elmat)
3294 {
3295  int i, j, face_ndof, ndof1, ndof2, dim;
3296  int order;
3297 
3298  MFEM_VERIFY(trial_face_fe.GetMapType() == FiniteElement::VALUE, "");
3299 
3300  face_ndof = trial_face_fe.GetDof();
3301  ndof1 = test_fe1.GetDof();
3302  dim = test_fe1.GetDim();
3303 
3304  face_shape.SetSize(face_ndof);
3305  normal.SetSize(dim);
3306  shape1.SetSize(ndof1,dim);
3307  shape1_n.SetSize(ndof1);
3308 
3309  if (Trans.Elem2No >= 0)
3310  {
3311  ndof2 = test_fe2.GetDof();
3312  shape2.SetSize(ndof2,dim);
3313  shape2_n.SetSize(ndof2);
3314  }
3315  else
3316  {
3317  ndof2 = 0;
3318  }
3319 
3320  elmat.SetSize(ndof1 + ndof2, face_ndof);
3321  elmat = 0.0;
3322 
3323  const IntegrationRule *ir = IntRule;
3324  if (ir == NULL)
3325  {
3326  if (Trans.Elem2No >= 0)
3327  {
3328  order = max(test_fe1.GetOrder(), test_fe2.GetOrder()) - 1;
3329  }
3330  else
3331  {
3332  order = test_fe1.GetOrder() - 1;
3333  }
3334  order += trial_face_fe.GetOrder();
3335  ir = &IntRules.Get(Trans.GetGeometryType(), order);
3336  }
3337 
3338  for (int p = 0; p < ir->GetNPoints(); p++)
3339  {
3340  const IntegrationPoint &ip = ir->IntPoint(p);
3341  IntegrationPoint eip1, eip2;
3342  // Trace finite element shape function
3343  trial_face_fe.CalcShape(ip, face_shape);
3344  Trans.Loc1.Transf.SetIntPoint(&ip);
3345  CalcOrtho(Trans.Loc1.Transf.Jacobian(), normal);
3346  // Side 1 finite element shape function
3347  Trans.Loc1.Transform(ip, eip1);
3348  test_fe1.CalcVShape(eip1, shape1);
3349  shape1.Mult(normal, shape1_n);
3350  if (ndof2)
3351  {
3352  // Side 2 finite element shape function
3353  Trans.Loc2.Transform(ip, eip2);
3354  test_fe2.CalcVShape(eip2, shape2);
3355  Trans.Loc2.Transf.SetIntPoint(&ip);
3356  CalcOrtho(Trans.Loc2.Transf.Jacobian(), normal);
3357  shape2.Mult(normal, shape2_n);
3358  }
3359  face_shape *= ip.weight;
3360  for (i = 0; i < ndof1; i++)
3361  for (j = 0; j < face_ndof; j++)
3362  {
3363  elmat(i, j) -= shape1_n(i) * face_shape(j);
3364  }
3365  if (ndof2)
3366  {
3367  // Subtract contribution from side 2
3368  for (i = 0; i < ndof2; i++)
3369  for (j = 0; j < face_ndof; j++)
3370  {
3371  elmat(ndof1+i, j) += shape2_n(i) * face_shape(j);
3372  }
3373  }
3374  }
3375 }
3376 
3377 
3378 void NormalInterpolator::AssembleElementMatrix2(
3379  const FiniteElement &dom_fe, const FiniteElement &ran_fe,
3380  ElementTransformation &Trans, DenseMatrix &elmat)
3381 {
3382  int spaceDim = Trans.GetSpaceDim();
3383  elmat.SetSize(ran_fe.GetDof(), spaceDim*dom_fe.GetDof());
3384  Vector n(spaceDim), shape(dom_fe.GetDof());
3385 
3386  const IntegrationRule &ran_nodes = ran_fe.GetNodes();
3387  for (int i = 0; i < ran_nodes.Size(); i++)
3388  {
3389  const IntegrationPoint &ip = ran_nodes.IntPoint(i);
3390  Trans.SetIntPoint(&ip);
3391  CalcOrtho(Trans.Jacobian(), n);
3392  dom_fe.CalcShape(ip, shape);
3393  for (int j = 0; j < shape.Size(); j++)
3394  {
3395  for (int d = 0; d < spaceDim; d++)
3396  {
3397  elmat(i, j+d*shape.Size()) = shape(j)*n(d);
3398  }
3399  }
3400  }
3401 }
3402 
3403 
3404 namespace internal
3405 {
3406 
3407 // Scalar shape functions scaled by scalar coefficient.
3408 // Used in the implementation of class ScalarProductInterpolator below.
3409 struct ShapeCoefficient : public VectorCoefficient
3410 {
3411  Coefficient &Q;
3412  const FiniteElement &fe;
3413 
3414  ShapeCoefficient(Coefficient &q, const FiniteElement &fe_)
3415  : VectorCoefficient(fe_.GetDof()), Q(q), fe(fe_) { }
3416 
3417  using VectorCoefficient::Eval;
3418  virtual void Eval(Vector &V, ElementTransformation &T,
3419  const IntegrationPoint &ip)
3420  {
3421  V.SetSize(vdim);
3422  fe.CalcPhysShape(T, V);
3423  V *= Q.Eval(T, ip);
3424  }
3425 };
3426 
3427 }
3428 
3429 void
3430 ScalarProductInterpolator::AssembleElementMatrix2(const FiniteElement &dom_fe,
3431  const FiniteElement &ran_fe,
3432  ElementTransformation &Trans,
3433  DenseMatrix &elmat)
3434 {
3435  internal::ShapeCoefficient dom_shape_coeff(*Q, dom_fe);
3436 
3437  elmat.SetSize(ran_fe.GetDof(),dom_fe.GetDof());
3438 
3439  Vector elmat_as_vec(elmat.Data(), ran_fe.GetDof()*dom_fe.GetDof());
3440 
3441  ran_fe.Project(dom_shape_coeff, Trans, elmat_as_vec);
3442 }
3443 
3444 
3445 void
3446 ScalarVectorProductInterpolator::AssembleElementMatrix2(
3447  const FiniteElement &dom_fe,
3448  const FiniteElement &ran_fe,
3449  ElementTransformation &Trans,
3450  DenseMatrix &elmat)
3451 {
3452  // Vector shape functions scaled by scalar coefficient
3453  struct VShapeCoefficient : public MatrixCoefficient
3454  {
3455  Coefficient &Q;
3456  const FiniteElement &fe;
3457 
3458  VShapeCoefficient(Coefficient &q, const FiniteElement &fe_, int sdim)
3459  : MatrixCoefficient(fe_.GetDof(), sdim), Q(q), fe(fe_) { }
3460 
3461  virtual void Eval(DenseMatrix &M, ElementTransformation &T,
3462  const IntegrationPoint &ip)
3463  {
3464  M.SetSize(height, width);
3465  fe.CalcPhysVShape(T, M);
3466  M *= Q.Eval(T, ip);
3467  }
3468  };
3469 
3470  VShapeCoefficient dom_shape_coeff(*Q, dom_fe, Trans.GetSpaceDim());
3471 
3472  elmat.SetSize(ran_fe.GetDof(),dom_fe.GetDof());
3473 
3474  Vector elmat_as_vec(elmat.Data(), ran_fe.GetDof()*dom_fe.GetDof());
3475 
3476  ran_fe.ProjectMatrixCoefficient(dom_shape_coeff, Trans, elmat_as_vec);
3477 }
3478 
3479 
3480 void
3481 VectorScalarProductInterpolator::AssembleElementMatrix2(
3482  const FiniteElement &dom_fe,
3483  const FiniteElement &ran_fe,
3484  ElementTransformation &Trans,
3485  DenseMatrix &elmat)
3486 {
3487  // Scalar shape functions scaled by vector coefficient
3488  struct VecShapeCoefficient : public MatrixCoefficient
3489  {
3490  VectorCoefficient &VQ;
3491  const FiniteElement &fe;
3492  Vector vc, shape;
3493 
3494  VecShapeCoefficient(VectorCoefficient &vq, const FiniteElement &fe_)
3495  : MatrixCoefficient(fe_.GetDof(), vq.GetVDim()), VQ(vq), fe(fe_),
3496  vc(width), shape(height) { }
3497 
3498  virtual void Eval(DenseMatrix &M, ElementTransformation &T,
3499  const IntegrationPoint &ip)
3500  {
3501  M.SetSize(height, width);
3502  VQ.Eval(vc, T, ip);
3503  fe.CalcPhysShape(T, shape);
3504  MultVWt(shape, vc, M);
3505  }
3506  };
3507 
3508  VecShapeCoefficient dom_shape_coeff(*VQ, dom_fe);
3509 
3510  elmat.SetSize(ran_fe.GetDof(),dom_fe.GetDof());
3511 
3512  Vector elmat_as_vec(elmat.Data(), ran_fe.GetDof()*dom_fe.GetDof());
3513 
3514  ran_fe.ProjectMatrixCoefficient(dom_shape_coeff, Trans, elmat_as_vec);
3515 }
3516 
3517 
3518 void
3519 VectorCrossProductInterpolator::AssembleElementMatrix2(
3520  const FiniteElement &dom_fe,
3521  const FiniteElement &ran_fe,
3522  ElementTransformation &Trans,
3523  DenseMatrix &elmat)
3524 {
3525  // Vector coefficient product with vector shape functions
3526  struct VCrossVShapeCoefficient : public MatrixCoefficient
3527  {
3528  VectorCoefficient &VQ;
3529  const FiniteElement &fe;
3530  DenseMatrix vshape;
3531  Vector vc;
3532 
3533  VCrossVShapeCoefficient(VectorCoefficient &vq, const FiniteElement &fe_)
3534  : MatrixCoefficient(fe_.GetDof(), vq.GetVDim()), VQ(vq), fe(fe_),
3535  vshape(height, width), vc(width)
3536  {
3537  MFEM_ASSERT(width == 3, "");
3538  }
3539 
3540  virtual void Eval(DenseMatrix &M, ElementTransformation &T,
3541  const IntegrationPoint &ip)
3542  {
3543  M.SetSize(height, width);
3544  VQ.Eval(vc, T, ip);
3545  fe.CalcPhysVShape(T, vshape);
3546  for (int k = 0; k < height; k++)
3547  {
3548  M(k,0) = vc(1) * vshape(k,2) - vc(2) * vshape(k,1);
3549  M(k,1) = vc(2) * vshape(k,0) - vc(0) * vshape(k,2);
3550  M(k,2) = vc(0) * vshape(k,1) - vc(1) * vshape(k,0);
3551  }
3552  }
3553  };
3554 
3555  VCrossVShapeCoefficient dom_shape_coeff(*VQ, dom_fe);
3556 
3557  if (ran_fe.GetRangeType() == FiniteElement::SCALAR)
3558  {
3559  elmat.SetSize(ran_fe.GetDof()*VQ->GetVDim(),dom_fe.GetDof());
3560  }
3561  else
3562  {
3563  elmat.SetSize(ran_fe.GetDof(),dom_fe.GetDof());
3564  }
3565 
3566  Vector elmat_as_vec(elmat.Data(), elmat.Height()*elmat.Width());
3567 
3568  ran_fe.ProjectMatrixCoefficient(dom_shape_coeff, Trans, elmat_as_vec);
3569 }
3570 
3571 
3572 namespace internal
3573 {
3574 
3575 // Vector shape functions dot product with a vector coefficient.
3576 // Used in the implementation of class VectorInnerProductInterpolator below.
3577 struct VDotVShapeCoefficient : public VectorCoefficient
3578 {
3579  VectorCoefficient &VQ;
3580  const FiniteElement &fe;
3581  DenseMatrix vshape;
3582  Vector vc;
3583 
3584  VDotVShapeCoefficient(VectorCoefficient &vq, const FiniteElement &fe_)
3585  : VectorCoefficient(fe_.GetDof()), VQ(vq), fe(fe_),
3586  vshape(vdim, vq.GetVDim()), vc(vq.GetVDim()) { }
3587 
3588  using VectorCoefficient::Eval;
3589  virtual void Eval(Vector &V, ElementTransformation &T,
3590  const IntegrationPoint &ip)
3591  {
3592  V.SetSize(vdim);
3593  VQ.Eval(vc, T, ip);
3594  fe.CalcPhysVShape(T, vshape);
3595  vshape.Mult(vc, V);
3596  }
3597 };
3598 
3599 }
3600 
3601 void
3602 VectorInnerProductInterpolator::AssembleElementMatrix2(
3603  const FiniteElement &dom_fe,
3604  const FiniteElement &ran_fe,
3605  ElementTransformation &Trans,
3606  DenseMatrix &elmat)
3607 {
3608  internal::VDotVShapeCoefficient dom_shape_coeff(*VQ, dom_fe);
3609 
3610  elmat.SetSize(ran_fe.GetDof(),dom_fe.GetDof());
3611 
3612  Vector elmat_as_vec(elmat.Data(), elmat.Height()*elmat.Width());
3613 
3614  ran_fe.Project(dom_shape_coeff, Trans, elmat_as_vec);
3615 }
3616 
3617 }
int GetNPoints() const
Returns the number of the points in the integration rule.
Definition: intrules.hpp:245
Abstract class for all finite elements.
Definition: fe.hpp:235
void MultABt(const DenseMatrix &A, const DenseMatrix &B, DenseMatrix &ABt)
Multiply a matrix A with the transpose of a matrix B: A*Bt.
Definition: densemat.cpp:2393
const DenseMatrix & AdjugateJacobian()
Return the adjugate of the Jacobian matrix of the transformation at the currently set IntegrationPoin...
Definition: eltrans.hpp:127
int GetDim() const
Returns the reference space dimension for the finite element.
Definition: fe.hpp:309
void AddMultVWt(const Vector &v, const Vector &w, DenseMatrix &VWt)
VWt += v w^t.
Definition: densemat.cpp:2778
Class for an integration rule - an Array of IntegrationPoint.
Definition: intrules.hpp:90
virtual int OrderGrad(const FiniteElement *fe) const =0
Return the order of .
void NewDataAndSize(double *d, int s)
Set the Vector data and size, deleting the old data, if owned.
Definition: vector.hpp:134
virtual void CalcVShape(const IntegrationPoint &ip, DenseMatrix &shape) const
Evaluate the values of all shape functions of a vector finite element in reference space at the given...
Definition: fe.cpp:40
void MultVWt(const Vector &v, const Vector &w, DenseMatrix &VWt)
Definition: densemat.cpp:2759
virtual int OrderW() const =0
Return the order of the determinant of the Jacobian (weight) of the transformation.
const IntegrationRule & Get(int GeomType, int Order)
Returns an integration rule for given GeomType and Order.
Definition: intrules.cpp:915
Geometry::Type GetGeometryType() const
Return the Geometry::Type of the reference element.
Definition: eltrans.hpp:149
Base class for vector Coefficients that optionally depend on time and space.
virtual void Project(Coefficient &coeff, ElementTransformation &Trans, Vector &dofs) const
Given a coefficient and a transformation, compute its projection (approximation) in the local finite ...
Definition: fe.cpp:130
virtual void Eval(Vector &V, ElementTransformation &T, const IntegrationPoint &ip)=0
Evaluate the vector coefficient in the element described by T at the point ip, storing the result in ...
void SetSize(int s)
Resize the vector to size s.
Definition: vector.hpp:459
const Geometry::Type geom
Definition: ex1.cpp:40
void Mult(const Table &A, const Table &B, Table &C)
C = A * B (as boolean matrices)
Definition: table.cpp:476
int Width() const
Get the width (size of input) of the Operator. Synonym with NumCols().
Definition: operator.hpp:71
double InnerProduct(const double *x, const double *y) const
Compute y^t A x.
Definition: densemat.cpp:299
void SetIntPoint(const IntegrationPoint *ip)
Set the integration point ip that weights and Jacobians will be evaluated at.
Definition: eltrans.hpp:85
A specialized ElementTransformation class representing a face and its two neighboring elements...
Definition: eltrans.hpp:467
void CalcAdjugate(const DenseMatrix &a, DenseMatrix &adja)
Definition: densemat.cpp:2091
int GetOrder() const
Returns the order of the finite element. In the case of anisotropic orders, returns the maximum order...
Definition: fe.hpp:319
Data type dense matrix using column-major storage.
Definition: densemat.hpp:23
int Size() const
Returns the size of the vector.
Definition: vector.hpp:160
IntegrationPointTransformation Loc2
Definition: eltrans.hpp:511
int Space() const
Returns the type of FunctionSpace on the element.
Definition: fe.hpp:329
void AddMult_a_ABt(double a, const DenseMatrix &A, const DenseMatrix &B, DenseMatrix &ABt)
ABt += a * A * B^t.
Definition: densemat.cpp:2591
const DenseMatrix & InverseJacobian()
Return the inverse of the Jacobian matrix of the transformation at the currently set IntegrationPoint...
Definition: eltrans.hpp:132
double kappa
Definition: ex24.cpp:54
const IntegrationPoint & GetElement2IntPoint()
Get a const reference to the integration point in neighboring element 2 corresponding to the currentl...
Definition: eltrans.hpp:574
int GetMapType() const
Returns the FiniteElement::MapType of the element describing how reference functions are mapped to ph...
Definition: fe.hpp:341
double * GetData() const
Returns the matrix data array.
Definition: densemat.hpp:100
ElementTransformation * Elem2
Definition: eltrans.hpp:509
double * GetData() const
Return a pointer to the beginning of the Vector data.
Definition: vector.hpp:169
void CalcOrtho(const DenseMatrix &J, Vector &n)
Definition: densemat.cpp:2305
virtual int OrderJ() const =0
Return the order of the elements of the Jacobian of the transformation.
void add(const Vector &v1, const Vector &v2, Vector &v)
Definition: vector.cpp:261
virtual int OrderW() const
Return the order of the determinant of the Jacobian (weight) of the transformation.
Definition: eltrans.cpp:444
virtual void ProjectCurl(const FiniteElement &fe, ElementTransformation &Trans, DenseMatrix &curl) const
Compute the discrete curl matrix from the given FiniteElement onto &#39;this&#39; FiniteElement. The ElementTransformation is included to support cases when the matrix depends on it.
Definition: fe.cpp:175
Geometry::Type GetGeomType() const
Returns the Geometry::Type of the reference element.
Definition: fe.hpp:312
IntegrationPoint & IntPoint(int i)
Returns a reference to the i-th integration point.
Definition: intrules.hpp:248
void MultTranspose(const double *x, double *y) const
Multiply a vector with the transpose matrix.
Definition: densemat.cpp:203
void Reset(double *d, int h, int w)
Change the data array and the size of the DenseMatrix.
Definition: densemat.hpp:75
int Height() const
Get the height (size of output) of the Operator. Synonym with NumRows().
Definition: operator.hpp:65
IntegrationPointTransformation Loc1
Definition: eltrans.hpp:511
void mfem_error(const char *msg)
Function called when an error is encountered. Used by the macros MFEM_ABORT, MFEM_ASSERT, MFEM_VERIFY.
Definition: error.cpp:153
void AddMult_a_VWt(const double a, const Vector &v, const Vector &w, DenseMatrix &VWt)
VWt += a * v w^t.
Definition: densemat.cpp:2823
double b
Definition: lissajous.cpp:42
void SetAllIntPoints(const IntegrationPoint *face_ip)
Set the integration point in the Face and the two neighboring elements, if present.
Definition: eltrans.hpp:553
const DenseMatrix & Jacobian()
Return the Jacobian matrix of the transformation at the currently set IntegrationPoint, using the method SetIntPoint().
Definition: eltrans.hpp:111
virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const =0
Evaluate the values of all shape functions of a scalar finite element in reference space at the given...
void Invert()
Replaces the current matrix with its inverse.
Definition: densemat.cpp:637
const IntegrationRule & GetNodes() const
Get a const reference to the nodes of the element.
Definition: fe.hpp:382
double Weight()
Return the weight of the Jacobian matrix of the transformation at the currently set IntegrationPoint...
Definition: eltrans.hpp:123
void AddMult_a_VVt(const double a, const Vector &v, DenseMatrix &VVt)
VVt += a * v v^t.
Definition: densemat.cpp:2845
int GetVDim()
Returns dimension of the vector.
void CalcInverse(const DenseMatrix &a, DenseMatrix &inva)
Definition: densemat.cpp:2199
double * Data() const
Returns the matrix data array.
Definition: densemat.hpp:96
void Transpose()
(*this) = (*this)^t
Definition: densemat.cpp:1378
void MultVVt(const Vector &v, DenseMatrix &vvt)
Make a matrix from a vector V.Vt.
Definition: densemat.cpp:2748
void AddMultABt(const DenseMatrix &A, const DenseMatrix &B, DenseMatrix &ABt)
ABt += A * B^t.
Definition: densemat.cpp:2498
Class FiniteElementSpace - responsible for providing FEM view of the mesh, mainly managing the set of...
Definition: fespace.hpp:87
int GetDof() const
Returns the number of degrees of freedom in the finite element.
Definition: fe.hpp:315
Base class Coefficients that optionally depend on space and time. These are used by the BilinearFormI...
Definition: coefficient.hpp:39
virtual int Order() const =0
Return the order of the current element we are using for the transformation.
void ClearExternalData()
Definition: densemat.hpp:80
Base class for Matrix Coefficients that optionally depend on time and space.
void Transform(const IntegrationPoint &, IntegrationPoint &)
Definition: eltrans.cpp:533
void MultAAt(const DenseMatrix &a, DenseMatrix &aat)
Calculate the matrix A.At.
Definition: densemat.cpp:2331
void GetColumnReference(int c, Vector &col)
Definition: densemat.hpp:270
virtual void CalcDivShape(const IntegrationPoint &ip, Vector &divshape) const
Evaluate the divergence of all shape functions of a vector finite element in reference space at the g...
Definition: fe.cpp:54
void AddMatrix(DenseMatrix &A, int ro, int co)
Perform (ro+i,co+j)+=A(i,j) for 0&lt;=i&lt;A.Height, 0&lt;=j&lt;A.Width.
Definition: densemat.cpp:1667
const IntegrationPoint & GetElement1IntPoint()
Get a const reference to the integration point in neighboring element 1 corresponding to the currentl...
Definition: eltrans.hpp:564
void SetDataAndSize(double *d, int s)
Set the Vector data and size.
Definition: vector.hpp:128
Vector & Set(const double a, const Vector &x)
(*this) = a * x
Definition: vector.cpp:228
virtual int GetSpaceDim() const =0
Get the dimension of the target (physical) space.
double a
Definition: lissajous.cpp:41
virtual void CalcCurlShape(const IntegrationPoint &ip, DenseMatrix &curl_shape) const
Evaluate the curl of all shape functions of a vector finite element in reference space at the given p...
Definition: fe.cpp:68
void AddMultADBt(const DenseMatrix &A, const Vector &D, const DenseMatrix &B, DenseMatrix &ADBt)
ADBt = A D B^t, where D is diagonal.
Definition: densemat.cpp:2555
Class for integration point with weight.
Definition: intrules.hpp:25
virtual void ProjectMatrixCoefficient(MatrixCoefficient &mc, ElementTransformation &T, Vector &dofs) const
Given a matrix coefficient and a transformation, compute an approximation (&quot;projection&quot;) in the local...
Definition: fe.cpp:148
double mu
Definition: ex25.cpp:135
int dim
Definition: ex24.cpp:53
IsoparametricTransformation Transf
Definition: eltrans.hpp:451
void GradToCurl(DenseMatrix &curl)
Definition: densemat.cpp:1436
ElementTransformation * Elem1
Definition: eltrans.hpp:509
const double alpha
Definition: ex15.cpp:336
void MultAtB(const DenseMatrix &A, const DenseMatrix &B, DenseMatrix &AtB)
Multiply the transpose of a matrix A with a matrix B: At*B.
Definition: densemat.cpp:2650
Vector data type.
Definition: vector.hpp:51
void Mult(const double *x, double *y) const
Matrix vector multiplication.
Definition: densemat.cpp:175
IntegrationRules RefinedIntRules(1, Quadrature1D::GaussLegendre)
A global object with all refined integration rules.
Definition: intrules.hpp:381
void AddMultADAt(const DenseMatrix &A, const Vector &D, DenseMatrix &ADAt)
ADAt += A D A^t, where D is diagonal.
Definition: densemat.cpp:2349
void SetSize(int s)
Change the size of the DenseMatrix to s x s.
Definition: densemat.hpp:90
virtual void CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const =0
Evaluate the gradients of all shape functions of a scalar finite element in reference space at the gi...
int GetRangeType() const
Returns the FiniteElement::RangeType of the element, one of {SCALAR, VECTOR}.
Definition: fe.hpp:332
IntegrationRules IntRules(0, Quadrature1D::GaussLegendre)
A global object with all integration rules (defined in intrules.cpp)
Definition: intrules.hpp:378
void AddMult_a_AAt(double a, const DenseMatrix &A, DenseMatrix &AAt)
AAt += a * A * A^t.
Definition: densemat.cpp:2707
void Neg()
(*this) = -(*this)
Definition: vector.cpp:253
const int ir_order
Definition: ex1.cpp:44
double sigma(const Vector &x)
Definition: maxwell.cpp:102