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