diff --git a/contrib/Netgen/README b/contrib/Netgen/README
index 37fb85051bd29845e57c8149554c2805a6d80d33..758926ba0fddcb4d6015a8ca1a8e5632c8acc319 100644
--- a/contrib/Netgen/README
+++ b/contrib/Netgen/README
@@ -2,16 +2,15 @@
 This directory contains a (very) slightly modified version of Joachim
 Sch\"oberl's NETGEN mesh generator:
 
-- only the libsrc directory was kept from the original distribution
+- only (part of the) the libsrc directory was kept from the original
+  distribution
 
-- libsrc/makefile.inc was replaced
-
-- libsrc/meshing/makefile was changed (removed some files from src)
+- some of the makefiles were changed
 
 - parts of interface/nglib.cpp were #ifdef'd to remove the dependency
   towards netgen's CAD engine
 
-All changed are marked with "MODIFIED FOR GMSH" in the source code
+All the changes are marked with "MODIFIED FOR GMSH" in the source code
 
 See COPYING.LIB for license information
 
diff --git a/contrib/Netgen/libsrc/general/Makefile b/contrib/Netgen/libsrc/general/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..1a8ac9e29c130774bcb134d2e92a0674a1b8d0cf
--- /dev/null
+++ b/contrib/Netgen/libsrc/general/Makefile
@@ -0,0 +1,12 @@
+#
+# Makefile for general purpose data types
+#
+src = array.cpp bitarray.cpp hashtabl.cpp symbolta.cpp table.cpp flags.cpp \
+	spbita2d.cpp seti.cpp optmem.cpp sort.cpp mystring.cpp parthreads.cpp \
+	moveablemem.cpp dynamicmem.cpp ngexception.cpp profiler.cpp
+#	
+lib = gen
+libpath = libsrc/general
+#
+include ../makefile.inc
+
diff --git a/contrib/Netgen/libsrc/general/array.cpp b/contrib/Netgen/libsrc/general/array.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..95d711a96fc7d09fb2e65a28b9c9fd490ed3fae9
--- /dev/null
+++ b/contrib/Netgen/libsrc/general/array.cpp
@@ -0,0 +1,75 @@
+#ifndef FILE_NGSTD_ARRAYCPP
+#define FILE_NGSTD_ARRAYCPP
+// necessary for SGI ????
+
+/**************************************************************************/
+/* File:   array.cpp                                                       */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   01. Jun. 95                                                    */
+/**************************************************************************/
+
+/* 
+   Abstract data type ARRAY
+*/
+
+#include <mystdlib.h>
+#include <myadt.hpp>
+#include <assert.h>
+
+
+namespace netgen
+{
+  //using namespace netgen;
+
+#ifdef NONE  
+  void BASE_ARRAY :: ReSize (int minsize, int elementsize)
+  {
+    cout << "resize, minsize = " << minsize << endl;
+
+    if (inc == -1)
+      throw Exception ("Try to resize fixed size array");
+
+    
+    void * p;
+    int nsize = (inc) ? allocsize + inc : 2 * allocsize;
+    if (nsize < minsize) nsize = minsize;
+
+    if (data)
+      {
+	p = new char [nsize * elementsize];
+	
+	int mins = (nsize < actsize) ? nsize : actsize; 
+	memcpy (p, data, mins * elementsize);
+	
+	delete [] static_cast<char*> (data);
+	data = p;
+      }
+    else
+      {
+	data = new char[nsize * elementsize];
+      }
+    
+    allocsize = nsize;
+    cout << "resize done" << endl;
+  }
+  
+  
+  
+  void BASE_ARRAY :: RangeCheck (int i) const
+  {
+    if (i < 0 || i >= actsize)
+      throw ArrayRangeException ();
+  }
+  
+  void BASE_ARRAY :: CheckNonEmpty () const
+  {
+    if (!actsize)
+      {
+	throw Exception ("Array should not be empty");
+	//      cerr << "Array souldn't be empty";
+      }
+  }
+#endif
+}
+#endif
+
diff --git a/contrib/Netgen/libsrc/general/array.hpp b/contrib/Netgen/libsrc/general/array.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..3d90894edfacb5551297a3ee7bada29ec5f0991a
--- /dev/null
+++ b/contrib/Netgen/libsrc/general/array.hpp
@@ -0,0 +1,632 @@
+#ifndef FILE_ARRAY
+#define FILE_ARRAY
+
+/**************************************************************************/
+/* File:   array.hpp                                                      */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   01. Jun. 95                                                    */
+/**************************************************************************/
+
+
+
+
+// template <class T, int B1, int B2> class IndirectArray;
+
+
+
+/**
+   A simple array container.
+   Array represented by size and data-pointer.
+   No memory allocation and deallocation, must be provided by user.
+   Helper functions for printing. 
+   Optional range check by macro RANGE_CHECK
+ */
+
+template <class T, int BASE = 0>
+class FlatArray
+{
+protected:
+  /// the size
+  int size;
+  /// the data
+  T * data;
+public:
+
+  /// provide size and memory
+  FlatArray (int asize, T * adata) 
+    : size(asize), data(adata) { ; }
+
+  /// the size
+  int Size() const { return size; }
+
+  int Begin() const { return BASE; }
+  int End() const { return size+BASE; }
+
+  /*
+  /// access array. 
+  T & operator[] (int i) 
+  { 
+#ifdef DEBUG
+    if (i-BASE < 0 || i-BASE >= size)
+      cout << "array<" << typeid(T).name() << "> out of range, i = " << i << ", s = " << size << endl;
+#endif
+
+    return data[i-BASE]; 
+  }
+  */
+
+  /// Access array. BASE-based
+  T & operator[] (int i) const
+  {
+#ifdef DEBUG
+    if (i-BASE < 0 || i-BASE >= size)
+      cout << "array<" << typeid(T).name() << "> out of range, i = " << i << ", s = " << size << endl;
+#endif
+
+    return data[i-BASE]; 
+  }
+
+  /*
+  template <int B2>
+  IndirectArray<T, BASE, B2> operator[] (const FlatArray<int, B2> & ind) 
+  { return IndirectArray<T, BASE, B2>  (*this, ind); }
+  */
+
+  /// Access array, one-based  (old fashioned)
+  T & Elem (int i)
+  {
+#ifdef DEBUG
+    if (i < 1 || i > size)
+      cout << "ARRAY<" << typeid(T).name() 
+	   << ">::Elem out of range, i = " << i
+	   << ", s = " << size << endl;
+#endif
+
+    return ((T*)data)[i-1]; 
+  }
+  
+  /// Access array, one-based  (old fashioned)
+  const T & Get (int i) const 
+  {
+#ifdef DEBUG
+    if (i < 1 || i > size)
+      cout << "ARRAY<" << typeid(T).name() << ">::Get out of range, i = " << i
+	   << ", s = " << size << endl;
+#endif
+
+    return ((const T*)data)[i-1]; 
+  }
+
+  /// Access array, one-based  (old fashioned)
+  void Set (int i, const T & el)
+  { 
+#ifdef DEBUG
+    if (i < 1 || i > size)
+      cout << "ARRAY<" << typeid(T).name() << ">::Set out of range, i = " << i
+	   << ", s = " << size << endl;
+#endif
+
+    ((T*)data)[i-1] = el; 
+  }
+
+
+
+  /// access first element
+  T & First () const
+  {
+    return data[0];
+  }
+
+
+  /// access last element. check by macro CHECK_RANGE
+  T & Last () const
+  {
+    return data[size-1];
+  }
+
+  /// Fill array with value val
+  FlatArray & operator= (const T & val)
+  {
+    for (int i = 0; i < size; i++)
+      data[i] = val;
+    return *this;
+  }
+
+  /// takes range starting from position start of end-start elements
+  const FlatArray<T> Range (int start, int end)
+  {
+    return FlatArray<T> (end-start, data+start);
+  }
+
+  /// first position of element elem, returns -1 if element not contained in array 
+  int Pos(const T & elem) const
+  {
+    int pos = -1;
+    for(int i=0; pos==-1 && i < this->size; i++)
+      if(elem == data[i]) pos = i;
+    return pos;
+  }
+
+  /// does the array contain element elem ?
+  bool Contains(const T & elem) const
+  {
+    return ( Pos(elem) >= 0 );
+  }
+};
+
+
+
+// print array
+template <class T, int BASE>
+inline ostream & operator<< (ostream & s, const FlatArray<T,BASE> & a)
+{
+  for (int i = a.Begin(); i < a.End(); i++)
+    s << i << ": " << a[i] << endl;
+  return s;
+}
+
+
+
+/** 
+   Dynamic array container.
+   
+   ARRAY<T> is an automatically increasing array container.
+   The allocated memory doubles on overflow. 
+   Either the container takes care of memory allocation and deallocation,
+   or the user provides one block of data.
+*/
+template <class T, int BASE = 0> 
+class ARRAY : public FlatArray<T, BASE>
+{
+protected:
+  /// physical size of array
+  int allocsize;
+  /// memory is responsibility of container
+  bool ownmem;
+
+public:
+
+  /// Generate array of logical and physical size asize
+  explicit ARRAY(int asize = 0)
+    : FlatArray<T, BASE> (asize, asize ? new T[asize] : 0)
+  {
+    allocsize = asize; 
+    ownmem = 1;
+  }
+
+  /// Generate array in user data
+  ARRAY(int asize, T* adata)
+    : FlatArray<T, BASE> (asize, adata)
+  {
+    allocsize = asize; 
+    ownmem = 0;
+  }
+
+  /// array copy 
+  explicit ARRAY (const ARRAY<T> & a2)
+    : FlatArray<T, BASE> (a2.Size(), a2.Size() ? new T[a2.Size()] : 0)
+  {
+    allocsize = this->size;
+    ownmem = 1;
+    for (int i = BASE; i < this->size+BASE; i++)
+      (*this)[i] = a2[i];
+  }
+
+
+
+  /// if responsible, deletes memory
+  ~ARRAY()
+  {
+    if (ownmem)
+      delete [] this->data;
+  }
+
+  /// Change logical size. If necessary, do reallocation. Keeps contents.
+  void SetSize(int nsize)
+  {
+    if (nsize > allocsize) 
+      ReSize (nsize);
+    this->size = nsize; 
+  }
+
+  /// Change physical size. Keeps logical size. Keeps contents.
+  void SetAllocSize (int nallocsize)
+  {
+    if (nallocsize > allocsize)
+      ReSize (nallocsize);
+  }
+
+
+  /// Add element at end of array. reallocation if necessary.
+  int Append (const T & el)
+  {
+    if (this->size == allocsize) 
+      ReSize (this->size+1);
+    this->data[this->size] = el;
+    this->size++;
+    return this->size;
+  }
+
+  template <typename T2, int B2>
+  void Append (FlatArray<T2, B2> a2)
+  {
+    if (this->size+a2.Size() > allocsize)
+      ReSize (this->size+a2.Size());
+    for (int i = 0; i < a2.Size(); i++)
+      this->data[this->size+i] = a2[i+B2];
+    this->size += a2.Size();
+  }
+
+
+  /*
+  template <int B1, int B2>
+  void Append (const IndirectArray<T,B1,B2> & a2)
+  {
+    if (this->size+a2.Size() > allocsize)
+      ReSize (this->size+a2.Size());
+    for (int i = 0; i < a2.Size(); i++)
+      this->data[this->size+i] = a2[i+B2];
+    this->size += a2.Size();
+  }
+  */
+
+  /// Delete element i (0-based). Move last element to position i.
+  void Delete (int i)
+  {
+#ifdef CHECK_ARRAY_RANGE
+    RangeCheck (i+1);
+#endif
+
+    this->data[i] = this->data[this->size-1];
+    this->size--;
+    //    DeleteElement (i+1);
+  }
+
+
+  /// Delete element i (1-based). Move last element to position i.
+  void DeleteElement (int i)
+  {
+#ifdef CHECK_ARRAY_RANGE
+    RangeCheck (i);
+#endif
+
+    this->data[i-1] = this->data[this->size-1];
+    this->size--;
+  }
+
+  /// Delete last element. 
+  void DeleteLast ()
+  {
+    this->size--;
+  }
+
+  /// Deallocate memory
+  void DeleteAll ()
+  {
+    if (ownmem)
+      delete [] this->data;
+    this->data = 0;
+    this->size = allocsize = 0;
+  }
+
+  /// Fill array with val
+  ARRAY & operator= (const T & val)
+  {
+    FlatArray<T, BASE>::operator= (val);
+    return *this;
+  }
+
+  /// array copy
+  ARRAY & operator= (const ARRAY & a2)
+  {
+    SetSize (a2.Size());
+    for (int i = BASE; i < this->size+BASE; i++)
+      (*this)[i] = a2[i];
+    return *this;
+  }
+
+  /// array copy
+  ARRAY & operator= (const FlatArray<T> & a2)
+  {
+    SetSize (a2.Size());
+    for (int i = BASE; i < this->size+BASE; i++)
+      (*this)[i] = a2[i];
+    return *this;
+  }
+
+
+private:
+
+  /// resize array, at least to size minsize. copy contents
+  void ReSize (int minsize)
+  {
+    int nsize = 2 * allocsize;
+    if (nsize < minsize) nsize = minsize;
+
+    if (this->data)
+      {
+	T * p = new T[nsize];
+	
+	int mins = (nsize < this->size) ? nsize : this->size; 
+	memcpy (p, this->data, mins * sizeof(T));
+
+	if (ownmem)
+	  delete [] this->data;
+	ownmem = 1;
+	this->data = p;
+      }
+    else
+      {
+	this->data = new T[nsize];
+	ownmem = 1;
+      }
+    
+    allocsize = nsize;
+  }
+};
+
+
+
+template <class T, int S> 
+class ArrayMem : public ARRAY<T>
+{
+  // T mem[S];     // Intel C++ calls dummy constructor
+  // char mem[S*sizeof(T)];
+  double mem[(S*sizeof(T)+7) / 8];
+public:
+  /// Generate array of logical and physical size asize
+  explicit ArrayMem(int asize = 0)
+    : ARRAY<T> (S, static_cast<T*> (static_cast<void*>(&mem[0])))
+  {
+    this->SetSize (asize);
+  }
+
+  ArrayMem & operator= (const T & val)  
+  {
+    ARRAY<T>::operator= (val);
+    return *this;
+  }
+};
+
+
+
+
+
+/*
+template <class T, int B1, int B2>
+class IndirectArray
+{
+  const FlatArray<T, B1> & array;
+  const FlatArray<int, B2> & ia; 
+
+public:
+  IndirectArray (const FlatArray<T,B1> & aa, const FlatArray<int, B2> & aia)
+    : array(aa), ia(aia) { ; }
+  int Size() const { return ia.Size(); }
+  const T & operator[] (int i) const { return array[ia[i]]; }
+};
+*/
+
+
+
+
+
+
+
+
+
+
+///
+template <class T, int BASE = 0> 
+class MoveableArray 
+{
+  int size;
+  int allocsize;
+  MoveableMem<T> data;
+
+public:
+
+  MoveableArray()
+  { 
+    size = allocsize = 0; 
+    data.SetName ("MoveableArray");
+  }
+
+  MoveableArray(int asize)
+    : size(asize), allocsize(asize), data(asize)
+  { ; }
+  
+  ~MoveableArray () { ; }
+
+  int Size() const { return size; }
+
+  void SetSize(int nsize)
+  {
+    if (nsize > allocsize) 
+      {
+	data.ReAlloc (nsize);
+	allocsize = nsize;
+      }
+    size = nsize;
+  }
+
+  void SetAllocSize (int nallocsize)
+  {
+    data.ReAlloc (nallocsize);
+    allocsize = nallocsize;
+  }
+
+  ///
+  T & operator[] (int i)
+  { return ((T*)data)[i-BASE]; }
+
+  ///
+  const T & operator[] (int i) const
+  { return ((const T*)data)[i-BASE]; }
+
+  ///
+  T & Elem (int i)
+  { return ((T*)data)[i-1]; }
+  
+  ///
+  const T & Get (int i) const 
+  { return ((const T*)data)[i-1]; }
+
+  ///
+  void Set (int i, const T & el)
+  { ((T*)data)[i-1] = el; }
+
+  ///
+  T & Last ()
+  { return ((T*)data)[size-1]; }
+  
+  ///
+  const T & Last () const
+  { return ((const T*)data)[size-1]; }
+  
+  ///
+  int Append (const T & el)
+  {
+    if (size == allocsize) 
+      {
+	SetAllocSize (2*allocsize+1);
+      }
+    ((T*)data)[size] = el;
+    size++;
+    return size;
+  }
+  
+  ///
+  void Delete (int i)
+  {
+    DeleteElement (i+1);
+  }
+
+  ///
+  void DeleteElement (int i)
+  {
+    ((T*)data)[i-1] = ((T*)data)[size-1];
+    size--;
+  }
+  
+  ///
+  void DeleteLast ()
+  { size--; }
+
+  ///
+  void DeleteAll ()
+  {
+    size = allocsize = 0;
+    data.Free();
+  }
+
+  ///
+  void PrintMemInfo (ostream & ost) const
+  {
+    ost << Size() << " elements of size " << sizeof(T) << " = " 
+	<< Size() * sizeof(T) << endl;
+  }
+
+  MoveableArray & operator= (const T & el)
+  {
+    for (int i = 0; i < size; i++)
+      ((T*)data)[i] = el;
+    return *this;
+  }
+
+
+  MoveableArray & Copy (const MoveableArray & a2)
+  {
+    SetSize (a2.Size());
+    for (int i = 0; i < this->size; i++)
+      data[i] = a2.data[i];
+    return *this;
+  }
+
+  /// array copy
+  MoveableArray & operator= (const MoveableArray & a2)
+  {
+    return Copy(a2);
+  }
+
+
+  void SetName (const char * aname)
+  {
+    data.SetName(aname);
+  }
+private:
+  ///
+  //MoveableArray & operator= (MoveableArray &); //???
+  ///
+  //MoveableArray (const MoveableArray &); //???
+};
+
+
+template <class T>
+inline ostream & operator<< (ostream & ost, MoveableArray<T> & a)
+{
+  for (int i = 0; i < a.Size(); i++)
+    ost << i << ": " << a[i] << endl;
+  return ost;
+}
+
+
+/// bubble sort array
+template <class T>
+inline void BubbleSort (const FlatArray<T> & data)
+{
+  T hv;
+  for (int i = 0; i < data.Size(); i++)
+    for (int j = i+1; j < data.Size(); j++)
+      if (data[i] > data[j])
+	{
+	  hv = data[i];
+	  data[i] = data[j];
+	  data[j] = hv;
+	}
+}
+/// bubble sort array
+template <class T, class S>
+inline void BubbleSort (FlatArray<T> & data, FlatArray<S> & slave)
+{
+  T hv;
+  S hvs;
+  for (int i = 0; i < data.Size(); i++)
+    for (int j = i+1; j < data.Size(); j++)
+      if (data[i] > data[j])
+	{
+	  hv = data[i];
+	  data[i] = data[j];
+	  data[j] = hv;
+
+	  hvs = slave[i];
+	  slave[i] = slave[j];
+	  slave[j] = hvs;
+	}
+}
+
+
+template <class T> 
+void Intersection (const FlatArray<T> & in1, const FlatArray<T> & in2, 
+		   ARRAY<T> & out)
+{
+  out.SetSize(0);
+  for(int i=0; i<in1.Size(); i++)
+    if(in2.Contains(in1[i]))
+      out.Append(in1[i]);
+}
+template <class T> 
+void Intersection (const FlatArray<T> & in1, const FlatArray<T> & in2, const FlatArray<T> & in3,
+		   ARRAY<T> & out)
+{
+  out.SetSize(0);
+  for(int i=0; i<in1.Size(); i++)
+    if(in2.Contains(in1[i]) && in3.Contains(in1[i]))
+      out.Append(in1[i]);
+}
+
+
+
+
+#endif
+
diff --git a/contrib/Netgen/libsrc/general/autoptr.hpp b/contrib/Netgen/libsrc/general/autoptr.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..b90841408bcd5e8d597e10bee5473b1956ddfa85
--- /dev/null
+++ b/contrib/Netgen/libsrc/general/autoptr.hpp
@@ -0,0 +1,31 @@
+#ifndef FILE_AUTOPTR
+#define FILE_AUTOPTR
+
+/**************************************************************************/
+/* File:   autoptr.hpp                                                    */
+/* Author: STL, Joachim Schoeberl                                         */
+/* Date:   29. Dec. 02                                                    */
+/**************************************************************************/
+
+template <typename T>
+class AutoPtr
+{
+private:
+  T * ptr;
+public:
+  typedef T* pT;
+  explicit AutoPtr (T * p = 0)  { ptr = p; }
+  ~AutoPtr () { delete ptr; }
+  
+  T & operator*() const { return *ptr; }
+  T* operator->() const { return ptr; }
+  T *& Ptr() { return ptr; }
+  T * Ptr() const { return ptr; }
+  void Reset(T * p = 0) { if (p != ptr) { delete ptr; ptr = p; } }
+  operator bool () { return ptr != 0; }
+private:
+  AutoPtr (AutoPtr &) { ; }
+  AutoPtr & operator= (AutoPtr &) { ; }
+};
+
+#endif
diff --git a/contrib/Netgen/libsrc/general/bitarray.cpp b/contrib/Netgen/libsrc/general/bitarray.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..1c36e5fc043b42213f48bc8a06807a7f9b357762
--- /dev/null
+++ b/contrib/Netgen/libsrc/general/bitarray.cpp
@@ -0,0 +1,132 @@
+/**************************************************************************/
+/* File:   bitarray.cc                                                    */
+/* Autho: Joachim Schoeberl                                              */
+/* Date:   01. Jun. 95                                                    */
+/**************************************************************************/
+
+/* 
+   data type BitArray
+*/
+
+#include <mystdlib.h>
+#include <myadt.hpp>
+
+
+namespace netgen
+{
+  //using namespace netgen;
+
+  BitArray :: BitArray ()
+  {
+    size = 0;
+    data = NULL;
+  }
+
+  BitArray :: BitArray (int asize)
+  {
+    size = 0;
+    data = NULL;
+    SetSize (asize);
+  }
+
+  BitArray :: ~BitArray ()
+  {
+    delete [] data;
+  }
+
+  void BitArray :: SetSize (int asize)
+  {
+    if (size == asize) return;
+    delete [] data;
+
+    size = asize;
+    data = new unsigned char [Addr (size)+1];
+  }
+
+  void BitArray :: Set ()
+  {
+    if (!size) return;
+    for (int i = 0; i <= Addr (size); i++)
+      data[i] = UCHAR_MAX;
+  }
+
+  void BitArray :: Clear ()
+  {
+    if (!size) return;
+    for (int i = 0; i <= Addr (size); i++)
+      data[i] = 0;
+  }
+
+
+
+  void BitArray :: Invert ()
+  {
+    if (!size) return;
+    for (int i = 0; i <= Addr (size); i++)
+      data[i] ^= 255;
+  }
+
+  void BitArray :: And (const BitArray & ba2)
+  {
+    if (!size) return;
+    for (int i = 0; i <= Addr (size); i++)
+      data[i] &= ba2.data[i];
+  }
+
+
+  void BitArray :: Or (const BitArray & ba2)
+  {
+    if (!size) return;
+    for (int i = 0; i <= Addr (size); i++)
+      data[i] |= ba2.data[i];
+  }
+
+
+
+
+
+
+
+
+
+
+
+  template <int BASE>
+  void BitArrayChar<BASE> :: Set ()
+  {
+    data = 1;
+  }
+
+  template <int BASE>
+  void BitArrayChar<BASE> :: Clear ()
+  {
+    data = 0;
+  }
+
+
+  template <int BASE>
+  void BitArrayChar<BASE> :: Invert ()
+  {
+    for (int i = BASE; i < data.Size()+BASE; i++)
+      data[i] = 1 - data[i];
+  }
+
+  template <int BASE>
+  void BitArrayChar<BASE> :: And (const BitArrayChar & ba2)
+  {
+    for (int i = BASE; i < data.Size()+BASE; i++)
+      data[i] &= ba2.data[i];
+  }
+  
+
+  template <int BASE>
+  void BitArrayChar<BASE> :: Or (const BitArrayChar & ba2)
+  {
+    for (int i = BASE; i < data.Size()+BASE; i++)
+      data[i] |= ba2.data[i];
+  }
+  
+
+  template class BitArrayChar<0>;
+  template class BitArrayChar<1>;
+}
diff --git a/contrib/Netgen/libsrc/general/bitarray.hpp b/contrib/Netgen/libsrc/general/bitarray.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..ee3478da417f337e646c3c5c655f9de4694b95e7
--- /dev/null
+++ b/contrib/Netgen/libsrc/general/bitarray.hpp
@@ -0,0 +1,222 @@
+#ifndef FILE_BitArray
+#define FILE_BitArray
+
+/**************************************************************************/
+/* File:   bitarray.hpp                                                   */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   01. Jun. 95                                                    */
+/**************************************************************************/
+
+#include <limits.h>
+
+/**
+   data type BitArray
+   
+   BitArray is a compressed array of Boolean information. By Set and Clear
+   the whole array or one bit can be set or reset, respectively. 
+   Test returns the state of the accoring bit.
+   No range checking is done.
+
+   index ranges from 0 to size-1
+*/
+class BitArray
+{
+  INDEX size;
+  unsigned char * data;
+
+public:
+  BitArray ();
+  ///
+  BitArray (INDEX asize);
+  ///
+  ~BitArray ();
+
+  /// 
+  void SetSize (INDEX asize);
+  ///
+  INDEX Size () const
+  {
+    return size;
+  }
+
+  ///
+  void Set ();
+  ///
+  void Set (INDEX i)
+  {
+    data[Addr(i)] |= Mask(i);
+  }
+  
+  void Clear ();
+
+
+  void Clear (INDEX i)
+  {
+    data[Addr(i)] &= ~Mask(i);
+  }
+
+  bool Test (INDEX i) const
+  {
+    return (data[i / CHAR_BIT] & (char(1) << (i % CHAR_BIT) ) ) ? true : false;
+  }
+
+  ///
+  void Invert ();
+  ///
+  void And (const BitArray & ba2);
+  ///
+  void Or (const BitArray & ba2);
+private:
+  ///
+  inline unsigned char Mask (INDEX i) const
+  {
+    return char(1) << (i % CHAR_BIT);
+  }
+  ///
+  inline INDEX Addr (INDEX i) const
+  {
+  return (i / CHAR_BIT);
+  }
+
+  ///
+  BitArray & operator= (BitArray &);
+  ///
+  BitArray (const BitArray &);
+};
+
+
+
+// print bitarray
+inline ostream & operator<< (ostream & s, const BitArray & a)
+{
+  for (int i = 1; i <= a.Size(); i++)
+    {
+      s << int (a.Test(i));
+      if (i % 40 == 0) s << "\n";
+    }
+  if (a.Size() % 40 != 0) s << "\n";
+  return s;
+}
+
+
+/*
+inline
+INDEX BitArray :: Size () const
+  {
+  return size;
+  }
+
+inline
+unsigned char BitArray :: Mask (INDEX i) const
+  {
+  return char(1) << (i % CHAR_BIT);
+  }
+
+inline
+INDEX BitArray :: Addr (INDEX i) const
+  {
+  return (i / CHAR_BIT);
+  }
+inline
+void BitArray :: Set (INDEX i)
+  {
+  data[Addr(i)] |= Mask(i);
+  }
+
+inline
+void BitArray :: Clear (INDEX i)
+  {
+  data[Addr(i)] &= ~Mask(i);
+  }
+
+
+inline
+int BitArray :: Test (INDEX i) const
+  {
+  return (data[i / CHAR_BIT] & (char(1) << (i % CHAR_BIT) ) ) ? 1 : 0;
+  }
+
+*/
+
+
+
+
+
+
+/**
+   data type BitArrayChar
+   
+   BitArray is an array of Boolean information. By Set and Clear
+   the whole array or one bit can be set or reset, respectively. 
+   Test returns the state of the accoring bit.
+   No range checking is done.
+*/
+template <int BASE = 1>
+class BitArrayChar
+{
+  ///
+  ARRAY<char,BASE> data;
+
+public:
+  ///
+  BitArrayChar ()
+  { ; }
+  ///
+  BitArrayChar (int asize)
+    : data(asize)
+  { ; }
+  ///
+  ~BitArrayChar ()
+  { ; }
+
+  ///
+  void SetSize (int asize)
+  { data.SetSize(asize); }
+
+  ///
+  inline int Size () const
+  { return data.Size(); }
+
+  ///
+  void Set ();
+  ///
+  inline void Set (int i)
+  { data[i] = 1; }
+  ///
+  void Clear ();
+  ///
+  inline void Clear (int i)
+  { data[i] = 0; }
+  ///
+  inline int Test (int i) const
+  { return data[i]; }
+  ///
+  void Invert ();
+  ///
+  void And (const BitArrayChar & ba2);
+  ///
+  void Or (const BitArrayChar & ba2);
+private:
+  ///  copy bitarray is not supported
+  BitArrayChar & operator= (BitArrayChar &) { return *this; }
+  ///  copy bitarray is not supported
+  BitArrayChar (const BitArrayChar &) { ; }
+};
+
+
+
+
+template <int BASE>
+inline ostream & operator<< (ostream & s, const BitArrayChar<BASE> & a)
+{
+  for (int i = BASE; i < a.Size()+BASE; i++)
+    {
+      s << a.Test(i);
+      if ( (i-BASE) % 40 == 39) s << "\n";
+    }
+  if (a.Size() % 40 != 0) s << "\n";
+  return s;
+}
+
+
+#endif
diff --git a/contrib/Netgen/libsrc/general/dynamicmem.cpp b/contrib/Netgen/libsrc/general/dynamicmem.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..f41422f54c0cf13c881457981174712fe4261663
--- /dev/null
+++ b/contrib/Netgen/libsrc/general/dynamicmem.cpp
@@ -0,0 +1,202 @@
+#include <iostream>
+#include <iomanip>
+
+#ifdef SSE
+#include <emmintrin.h>
+#endif
+
+#include <myadt.hpp>
+using namespace std;
+
+namespace netgen
+{
+
+  BaseDynamicMem * BaseDynamicMem::first = 0;
+  BaseDynamicMem * BaseDynamicMem::last = 0;
+
+
+  BaseDynamicMem :: BaseDynamicMem ()
+  {
+    prev = last;
+    next = 0;
+
+    if (last) last->next = this;
+    last = this;
+    if (!first) first = this;
+
+    size = 0;
+    ptr = 0;
+    name = 0;
+  }
+ 
+  BaseDynamicMem :: ~BaseDynamicMem ()
+  {
+    Free();
+
+    if (next) next->prev = prev;
+    else last = prev;
+    if (prev) prev->next = next;
+    else first = next;
+
+    delete [] name;
+  }
+
+  void BaseDynamicMem :: SetName (const char * aname)
+  {
+    delete [] name;
+    if (aname)
+      {
+	name = new char[strlen(aname)+1];
+	strcpy (name, aname);
+      }
+  }
+
+
+  void BaseDynamicMem :: Alloc (size_t s)
+  {
+    size = s;
+    ptr = new char[s];
+
+    if (!ptr)
+      {
+	cerr << "BaseynamicMem, cannot allocate " << s << " bytes" << endl;
+	Print ();
+	throw ("BaseDynamicMem::Alloc: out of memory");
+      }
+    // ptr = (char*)malloc (s);
+    // ptr = (char*) _mm_malloc (s,16);
+  }
+
+  void BaseDynamicMem :: ReAlloc (size_t s)
+  {
+    if (size == s) return;
+
+    char * old = ptr;
+    ptr = new char[s];
+
+    if (!ptr)
+      {
+	cerr << "BaseynamicMem, cannot Reallocate " << s << " bytes" << endl;
+	Print ();
+	throw ("BaseDynamicMem::Alloc: out of memory");
+      }
+
+
+    // ptr = (char*)malloc(s);
+    // ptr = (char*) _mm_malloc (s,16);
+    memmove (ptr, old, (s < size) ? s : size);
+    delete [] old;
+    // free (old);
+    // _mm_free (old);
+    size = s;
+  }
+
+  void BaseDynamicMem :: Free ()
+  {
+    delete [] ptr;
+    // free (ptr);
+    // _mm_free (ptr);
+    ptr = 0;
+  }
+
+  void BaseDynamicMem :: Swap (BaseDynamicMem & m2)
+  {
+    size_t hi;
+    char * cp;
+    hi = size; size  = m2.size; m2.size = hi;
+    cp = ptr; ptr = m2.ptr; m2.ptr = cp;
+    cp = name; name = m2.name; m2.name = cp;
+  }
+
+
+  void BaseDynamicMem :: Print ()
+  {
+    cout << "****************** Dynamic Mem Report ****************" << endl;
+    BaseDynamicMem * p = first;
+    size_t mem = 0;
+    int cnt = 0;
+    while (p)
+      {
+	mem += p->size;
+	cnt++;
+
+	cout << setw(10) << p->size << " Bytes";
+	cout << ", addr = " << (void*)p->ptr;
+	if (p->name)
+	  cout << " in block " << p->name;
+	cout << endl;
+
+	p = p->next;
+      }
+
+    if (mem > 100000000)
+      cout << "memory in dynamic memory: " << mem/1048576 << " MB" << endl;
+    else if (mem > 100000)
+      cout << "memory in dynamic memory: " << mem/1024 << " kB" << endl;
+    else
+      cout << "memory in dynamic memory: " << mem << " Bytes" << endl;
+    cout << "number of blocks:         " << cnt << endl;
+    //  cout << "******************************************************" << endl;
+  }
+
+
+#pragma warning(push)
+#ifdef __INTEL_COMPILER
+#pragma warning(disable:1684)
+#endif
+
+  void BaseDynamicMem :: GetUsed (int nr, char * ch)
+  {
+    BaseDynamicMem * p = first;
+
+    for (int i = 0; i < nr; i++)
+      ch[i] = '0';
+
+    while (p)
+      {
+        long unsigned hptr = (long unsigned) (p->ptr);
+	// uintptr_t hptr = reinterpret_cast<uintptr_t>(p->ptr); //??
+
+	hptr /= (1024*1024);
+	hptr /= (4096/nr);
+
+	size_t blocks = p->size / (1024*1024);
+	blocks /= (4096/nr);
+	
+	// cout << "ptr = " << (void*)(p->ptr) << ", size = " << p->size << ", hptr = " << hptr << " blocks = " << blocks << endl;
+
+	for (size_t i = 0; i <= blocks; i++)
+	  ch[hptr+i] = '1';
+
+	p = p->next;
+      }
+    
+    {
+
+    BaseMoveableMem * pm = BaseMoveableMem::first;
+    while (pm)
+      {
+        long unsigned hptr = (long unsigned) p->ptr;
+        // uintptr_t hptr = reinterpret_cast<uintptr_t>(pm->ptr);
+
+	hptr /= (1024*1024);
+	hptr /= (4096/nr);
+
+	size_t blocks = pm->size / (1024*1024);
+	blocks /= (4096/nr);
+	
+	// cout << "moveable, ptr = " << (void*)(pm->ptr) << ", size = " << pm->size << ", hptr = " << hptr << " blocks = " << blocks << endl;
+
+	for (size_t i = 0; i <= blocks; i++)
+	  ch[hptr+i] = '1';
+
+	pm = pm->next;
+      }
+    }
+
+
+
+  }
+
+#pragma warning(pop)
+}
diff --git a/contrib/Netgen/libsrc/general/dynamicmem.hpp b/contrib/Netgen/libsrc/general/dynamicmem.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..483c9a7f17be91bf46974ffb2037c6fd9a098843
--- /dev/null
+++ b/contrib/Netgen/libsrc/general/dynamicmem.hpp
@@ -0,0 +1,95 @@
+#ifndef FILE_DYNAMICMEM
+#define FILE_DYNAMICMEM
+
+/**************************************************************************/
+/* File:   dynamicmem.hpp                                                 */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   12. Feb. 2003                                                  */
+/**************************************************************************/
+
+
+
+
+class BaseDynamicMem
+{
+private:
+  static BaseDynamicMem *first, *last;
+
+  BaseDynamicMem *prev, *next;
+  size_t size;
+  char * ptr;
+  char * name;
+
+protected:
+  BaseDynamicMem ();
+  ~BaseDynamicMem ();
+  void Alloc (size_t s);
+  void ReAlloc (size_t s);
+  void Free ();
+  char * Ptr() { return ptr; }
+  const char * Ptr() const { return ptr; }
+  void Swap (BaseDynamicMem & m2);
+public:
+  void SetName (const char * aname);
+  static void Print ();
+  static void GetUsed (int nr, char * ch);
+};
+
+
+template <typename T>
+class DynamicMem : public BaseDynamicMem
+{
+public:
+  DynamicMem ()
+    : BaseDynamicMem () 
+  {
+    ;
+  }
+  DynamicMem (size_t s)
+    : BaseDynamicMem () 
+  {
+    Alloc (s);
+  }
+  void Alloc (size_t s)
+  {
+    BaseDynamicMem::Alloc (sizeof(T) * s);
+  }
+  void ReAlloc (size_t s)
+  {
+    BaseDynamicMem::ReAlloc (sizeof(T) * s);
+  }
+  void Free ()
+  {
+    BaseDynamicMem::Free ();
+  }
+
+  const T * Ptr() const
+  {
+    return reinterpret_cast<const T*> (BaseDynamicMem::Ptr());
+  }
+
+  T * Ptr()
+  {
+    return reinterpret_cast<T*> (BaseDynamicMem::Ptr());
+  }
+
+  operator const T* () const
+  {
+    return reinterpret_cast<const T*> (BaseDynamicMem::Ptr());
+  }
+
+  operator T* () 
+  {
+    return reinterpret_cast<T*> (BaseDynamicMem::Ptr());
+  }
+
+  void Swap (DynamicMem<T> & m2)
+  {
+    BaseDynamicMem::Swap (m2);
+  }
+protected:
+  DynamicMem (const DynamicMem & m);
+  DynamicMem & operator= (const DynamicMem & m);
+};
+
+#endif
diff --git a/contrib/Netgen/libsrc/general/flags.cpp b/contrib/Netgen/libsrc/general/flags.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..b6b5ccf26871420e6700590ed9318bff2ffbd7d6
--- /dev/null
+++ b/contrib/Netgen/libsrc/general/flags.cpp
@@ -0,0 +1,330 @@
+/**************************************************************************/
+/* File:   flags.cc                                                       */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   10. Oct. 96                                                    */
+/**************************************************************************/
+
+/* 
+   Datatype Flags
+*/
+
+#include <mystdlib.h>
+#include <myadt.hpp>
+
+namespace netgen
+{
+  //using namespace netgen;
+
+  Flags :: Flags ()
+  {
+    ;
+  }
+  
+  Flags :: ~Flags ()
+  {
+    DeleteFlags ();
+  }
+  
+  void Flags :: DeleteFlags ()
+  {
+    for (int i = 0; i < strflags.Size(); i++)
+      delete [] strflags[i];
+    for (int i = 0; i < numlistflags.Size(); i++)
+      delete numlistflags[i];
+    strflags.DeleteAll();
+    numflags.DeleteAll();
+    defflags.DeleteAll();
+    strlistflags.DeleteAll();
+    numlistflags.DeleteAll();
+  }
+  
+  void Flags :: SetFlag (const char * name, const char * val)
+  {
+    char * hval = new char[strlen (val) + 1];
+    strcpy (hval, val);
+    strflags.Set (name, hval);
+  }
+  
+  void Flags :: SetFlag (const char * name, double val)
+  {
+    numflags.Set (name, val);
+  }
+  
+  void Flags :: SetFlag (const char * name)
+  {
+    defflags.Set (name, 1);
+  }
+
+
+  void Flags :: SetFlag (const char * name, const ARRAY<char*> & val)
+  {
+    ARRAY<char*> * strarray = new ARRAY<char*>;
+    for (int i = 1; i <= val.Size(); i++)
+      {
+	strarray->Append (new char[strlen(val.Get(i))+1]);
+	strcpy (strarray->Last(), val.Get(i));
+      }
+    strlistflags.Set (name, strarray);
+  }
+
+  void Flags :: SetFlag (const char * name, const ARRAY<double> & val)
+  {
+    ARRAY<double> * numarray = new ARRAY<double>;
+    for (int i = 1; i <= val.Size(); i++)
+      numarray->Append (val.Get(i));
+    numlistflags.Set (name, numarray);
+  }
+
+
+
+
+  
+  const char * 
+  Flags :: GetStringFlag (const char * name, const char * def) const
+  {
+    if (strflags.Used (name))
+      return strflags.Get(name);
+    else
+      return def;
+  }
+
+  double Flags :: GetNumFlag (const char * name, double def) const
+  {
+    if (numflags.Used (name))
+      return numflags.Get(name);
+    else
+      return def;
+  }
+  
+  const double * Flags :: GetNumFlagPtr (const char * name) const
+  {
+    if (numflags.Used (name))
+      return & ((SYMBOLTABLE<double>&)numflags).Elem(name);
+    else
+      return NULL;
+  }
+  
+  double * Flags :: GetNumFlagPtr (const char * name) 
+  {
+    if (numflags.Used (name))
+      return & ((SYMBOLTABLE<double>&)numflags).Elem(name);
+    else
+      return NULL;
+  }
+  
+  bool Flags :: GetDefineFlag (const char * name) const
+  {
+    return defflags.Used (name);
+  }
+
+
+  const ARRAY<char*> & 
+  Flags :: GetStringListFlag (const char * name) const
+  {
+    if (strlistflags.Used (name))
+      return *strlistflags.Get(name);
+    else
+      {
+	static ARRAY<char*> hstra(0);
+	return hstra;
+      }
+  }
+
+  const ARRAY<double> & 
+  Flags ::GetNumListFlag (const char * name) const
+  {
+    if (numlistflags.Used (name))
+      return *numlistflags.Get(name);
+    else
+      {
+	static ARRAY<double> hnuma(0);
+	return hnuma;
+      }
+  }
+
+
+  bool Flags :: StringFlagDefined (const char * name) const
+  {
+    return strflags.Used (name);
+  }
+
+  bool Flags :: NumFlagDefined (const char * name) const
+  {
+    return numflags.Used (name);
+  }
+
+  bool Flags :: StringListFlagDefined (const char * name) const
+  {
+    return strlistflags.Used (name);
+  }
+
+  bool Flags :: NumListFlagDefined (const char * name) const
+  {
+    return numlistflags.Used (name);
+  }
+
+
+  void Flags :: SaveFlags (const char * filename) const 
+  {
+    int i;
+    ofstream outfile (filename);
+  
+    for (i = 1; i <= strflags.Size(); i++)
+      outfile << strflags.GetName(i) << " = " << strflags.Get(i) << endl;
+    for (i = 1; i <= numflags.Size(); i++)
+      outfile << numflags.GetName(i) << " = " << numflags.Get(i) << endl;
+    for (i = 1; i <= defflags.Size(); i++)
+      outfile << defflags.GetName(i) << endl;
+  }
+ 
+
+
+  void Flags :: PrintFlags (ostream & ost) const 
+  {
+    int i;
+  
+    for (i = 1; i <= strflags.Size(); i++)
+      ost << strflags.GetName(i) << " = " << strflags.Get(i) << endl;
+    for (i = 1; i <= numflags.Size(); i++)
+      ost << numflags.GetName(i) << " = " << numflags.Get(i) << endl;
+    for (i = 1; i <= defflags.Size(); i++)
+      ost << defflags.GetName(i) << endl;
+  }
+ 
+
+  void Flags :: LoadFlags (const char * filename) 
+  {
+    char name[100], str[100];
+    char ch;
+    double val;
+    ifstream infile(filename);
+
+    //  (*logout) << "Load flags from " << filename << endl << endl;
+    while (infile.good())
+      {
+	infile >> name;
+	if (strlen (name) == 0) break;
+
+	if (name[0] == '/' && name[1] == '/')
+	  {
+	    //	  (*logout) << "comment: ";
+	    ch = 0;
+	    while (ch != '\n' && infile.good())
+	      {
+		ch = infile.get();
+		//	      (*logout) << ch;
+	      }
+	    continue;
+	  }
+
+	//      (*logout)  << name;
+	ch = 0;
+	infile >> ch;
+	if (ch != '=')
+	  {
+	    //	  (*logout) << endl;
+	    infile.putback (ch);
+	    SetFlag (name);
+	  }
+	else
+	  {
+	    infile >> val;
+	    if (!infile.good())
+	      {
+		infile.clear();
+		infile >> str;
+		SetFlag (name, str);
+		//	      (*logout) << " = " << str << endl;
+	      }
+	    else
+	      {
+		SetFlag (name, val);
+		//	      (*logout) << " = " << val << endl;
+	      }
+	  }
+      }
+    //  (*logout) << endl;
+  }
+
+
+  void Flags :: SetCommandLineFlag (const char * st)
+  {
+    //  cout << "clflag = " << st << endl;
+    istringstream inst( (char *)st);
+    // istrstream defined with char *  (not const char *  ?????)
+
+    char name[100];
+    double val;
+
+
+    if (st[0] != '-')
+      {
+	cerr << "flag must start with '-'" << endl;
+	return;
+      }
+  
+    const char * pos = strchr (st, '=');
+  
+    if (!pos)
+      {
+	//      (cout) << "Add def flag: " << st+1 << endl;
+	SetFlag (st+1);
+      }
+    else
+      {
+	//      cout << "pos = " << pos << endl;
+
+	strncpy (name, st+1, (pos-st)-1);
+	name[pos-st-1] = 0;
+
+	//      cout << "name = " << name << endl;
+
+	pos++;
+	char * endptr = NULL;
+
+	val = strtod (pos, &endptr);
+
+	//      cout << "val = " << val << endl;
+
+	if (endptr == pos)
+	  {
+	    //	  (cout) << "Add String Flag: " << name << " = " << pos << endl;
+	    SetFlag (name, pos);
+	  }
+	else
+	  {
+	    //	  (cout) << "Add Num Flag: " << name << " = " << val << endl;
+	    SetFlag (name, val);
+	  }
+      }
+
+
+    /*
+      inst >> name;
+      (*mycout) << "name = " << name << endl;
+
+      ch = 0;
+      inst >> ch;
+      if (ch != '=')
+      {
+      SetFlag (name);
+      }
+      else
+      {
+      inst >> val;
+      if (!inst.good())
+      {
+      inst.clear();
+      inst >> str;
+      SetFlag (name, str);
+      (*mycout) << "str = " << str << endl;
+      }
+      else
+      {
+      SetFlag (name, val);
+      (*mycout) << "val = " << val << endl;
+      }
+      }
+    */
+  }
+}
diff --git a/contrib/Netgen/libsrc/general/flags.hpp b/contrib/Netgen/libsrc/general/flags.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..59c365ee18ed0e7722214f30893b379233f7e48d
--- /dev/null
+++ b/contrib/Netgen/libsrc/general/flags.hpp
@@ -0,0 +1,83 @@
+#ifndef FILE_FLAGS
+#define FILE_FLAGS
+
+
+/**************************************************************************/
+/* File:   flags.hh                                                       */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   10. Oct. 96                                                   */
+/**************************************************************************/
+
+/** 
+   Flag - Table.
+   A flag table maintains string variables, numerical 
+   variables and boolean flags.
+*/
+class Flags 
+{
+  ///
+  SYMBOLTABLE<char *> strflags;
+  ///
+  SYMBOLTABLE<double> numflags;
+  ///
+  SYMBOLTABLE<int> defflags;
+  ///
+  SYMBOLTABLE<ARRAY<char*>*> strlistflags;
+  ///
+  SYMBOLTABLE<ARRAY<double>*> numlistflags;
+public:
+  ///
+  Flags ();
+  ///
+  ~Flags ();
+  
+  /// Deletes all flags
+  void DeleteFlags ();
+  /// Sets string flag, overwrite if exists
+  void SetFlag (const char * name, const char * val);
+  /// Sets numerical flag, overwrite if exists
+  void SetFlag (const char * name, double val);
+  /// Sets boolean flag
+  void SetFlag (const char * name);
+  /// Sets string arary falg
+  void SetFlag (const char * name, const ARRAY<char*> & val);
+  /// Sets double array flag
+  void SetFlag (const char * name, const ARRAY<double> & val);
+  
+  /// Save flags to file
+  void SaveFlags (const char * filename) const;
+  /// write flags to stream
+  void PrintFlags (ostream & ost) const;
+  /// Load flags from file
+  void LoadFlags (const char * filename);
+  /// set flag of form -name=hello -val=0.5 -defined
+  void SetCommandLineFlag (const char * st);
+
+  /// Returns string flag, default value if not exists
+  const char * GetStringFlag (const char * name, const char * def) const;
+  /// Returns numerical flag, default value if not exists
+  double GetNumFlag (const char * name, double def) const;
+  /// Returns address of numerical flag, null if not exists
+  const double * GetNumFlagPtr (const char * name) const;
+  /// Returns address of numerical flag, null if not exists
+  double * GetNumFlagPtr (const char * name);
+  /// Returns boolean flag
+  bool GetDefineFlag (const char * name) const;
+  /// Returns string list flag, empty array if not exist
+  const ARRAY<char*> & GetStringListFlag (const char * name) const;
+  /// Returns num list flag, empty array if not exist
+  const ARRAY<double> & GetNumListFlag (const char * name) const;
+
+
+  /// Test, if string flag is defined
+  bool StringFlagDefined (const char * name) const;
+  /// Test, if num flag is defined
+  bool NumFlagDefined (const char * name) const;
+  /// Test, if string list flag is defined
+  bool StringListFlagDefined (const char * name) const;
+  /// Test, if num list flag is defined
+  bool NumListFlagDefined (const char * name) const;
+};
+  
+#endif
+
diff --git a/contrib/Netgen/libsrc/general/hashtabl.cpp b/contrib/Netgen/libsrc/general/hashtabl.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..d5b77f3cba0bd68a1141ca8aa16872af41525d42
--- /dev/null
+++ b/contrib/Netgen/libsrc/general/hashtabl.cpp
@@ -0,0 +1,327 @@
+/**************************************************************************/
+/* File:   hashtabl.cpp                                                   */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   01. Jun. 95                                                    */
+/**************************************************************************/
+
+/* 
+   Abstract data type HASHTABLE
+*/
+
+#include <algorithm>
+#include <mystdlib.h>
+#include <myadt.hpp>
+
+namespace netgen
+{
+  //using namespace netgen;
+
+  void INDEX_4 :: Sort ()
+  {
+    if (i[0] > i[1]) Swap (i[0], i[1]);
+    if (i[2] > i[3]) Swap (i[2], i[3]);
+    if (i[0] > i[2]) Swap (i[0], i[2]);
+    if (i[1] > i[3]) Swap (i[1], i[3]);
+    if (i[1] > i[2]) Swap (i[1], i[2]);
+  }
+
+
+
+  void INDEX_4Q :: Sort ()
+  {
+    if (min2 (i[1], i[2]) < min2 (i[0], i[3]))
+      { Swap (i[0], i[1]); Swap (i[2], i[3]);}
+    if (i[3] < i[0])
+      { Swap (i[0], i[3]); Swap (i[1], i[2]);}
+    if (i[3] < i[1])
+      { Swap (i[1], i[3]); }
+  }
+
+
+  ostream & operator<<(ostream  & s, const INDEX_2 & i2)
+  {
+    return s << i2.I1() << ", " << i2.I2();
+  }
+
+  ostream & operator<<(ostream  & s, const INDEX_3 & i3)
+  {
+    return s << i3.I1() << ", " << i3.I2() << ", " << i3.I3();
+  }
+
+  ostream & operator<<(ostream  & s, const INDEX_4 & i4)
+  {
+    return s << i4.I1() << ", " << i4.I2() << ", " << i4.I3() << ", " << i4.I4();
+  }
+
+  ostream & operator<<(ostream  & s, const INDEX_4Q & i4)
+  {
+    return s << i4.I1() << ", " << i4.I2() << ", " << i4.I3() << ", " << i4.I4();
+  }
+
+
+  int BASE_INDEX_HASHTABLE :: Position (int bnr, const INDEX & ind) const
+  {
+    int i;
+    for (i = 1; i <= hash.EntrySize (bnr); i++)
+      if (hash.Get(bnr, i) == ind)
+	return i;
+    return 0;
+  }
+
+
+
+  /*
+  int BASE_INDEX_2_HASHTABLE :: Position (int bnr, const INDEX_2 & ind) const
+  {
+    int i;
+    for (i = 1; i <= hash.EntrySize (bnr); i++)
+      if (hash.Get(bnr, i) == ind)
+	return i;
+    return 0;
+  }
+  */  
+
+  void BASE_INDEX_2_HASHTABLE :: PrintStat (ostream & ost) const
+  {
+    int n = hash.Size();
+    int i;
+    int sumn = 0, sumnn = 0;
+
+    for (i = 1; i <= n; i++)
+      {
+	sumn += hash.EntrySize(i);
+	sumnn += sqr (hash.EntrySize(i));
+      }
+
+    ost << "Hashtable: " << endl
+	<< "size             : " << n << endl
+	<< "elements per row : " << (double(sumn) / double(n)) << endl
+	<< "av. acces time   : " 
+	<< (sumn ? (double (sumnn) / double(sumn)) : 0) << endl;
+  }
+
+
+  /*
+    int BASE_INDEX_3_HASHTABLE :: Position (int bnr, const INDEX_3 & ind) const
+    {
+    int i;
+    const INDEX_3 * pi = &hash.Get(bnr, 1);
+    int n = hash.EntrySize(bnr);
+    for (i = 1; i <= n; ++i, ++pi)
+    {
+    if (*pi == ind)
+    return i;
+    }
+
+    return 0;
+    }
+  */
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+  BASE_INDEX_CLOSED_HASHTABLE ::
+  BASE_INDEX_CLOSED_HASHTABLE (int size)
+    : hash(size)
+  {
+    hash.SetName ("index-hashtable, hash");
+
+    invalid = -1;
+    for (int i = 1; i <= size; i++)
+      hash.Elem(i) = invalid;
+  }
+
+  void BASE_INDEX_CLOSED_HASHTABLE ::
+  BaseSetSize (int size)
+  {
+    hash.SetSize(size);
+    for (int i = 1; i <= size; i++)
+      hash.Elem(i) = invalid;
+  }
+
+  int BASE_INDEX_CLOSED_HASHTABLE ::
+  Position2 (const INDEX & ind) const
+  {
+    int i = HashValue(ind);
+    while (1)
+      {
+	i++;
+	if (i > hash.Size()) i = 1;
+	if (hash.Get(i) == ind) return i;
+	if (hash.Get(i) == invalid) return 0;
+      }
+  }
+
+  int BASE_INDEX_CLOSED_HASHTABLE ::
+  PositionCreate2 (const INDEX & ind, int & apos) 
+  {
+    int i = HashValue(ind);
+    int startpos = i;
+    while (1)
+      {
+	i++;
+	if (i > hash.Size()) i = 1;
+	if (hash.Get(i) == ind) 
+	  {
+	    apos = i;
+	    return 0;
+	  }
+	if (hash.Get(i) == invalid) 
+	  {
+	    hash.Elem(i) = ind;
+	    apos = i;
+	    return 1;
+	  }
+	if (i == startpos)
+	  throw NgException ("Try to set new element in full closed hashtable");
+      }
+  }
+
+  int BASE_INDEX_CLOSED_HASHTABLE :: UsedElements () const
+  {
+    int n = hash.Size();
+    int cnt = 0;
+    for (int i = 1; i <= n; i++)
+      if (hash.Get(i) != invalid)
+	cnt++;
+    return cnt;
+  }
+
+
+
+
+
+
+
+
+
+
+
+  BASE_INDEX_2_CLOSED_HASHTABLE ::
+  BASE_INDEX_2_CLOSED_HASHTABLE (int size)
+    : hash(size)
+  {
+    hash.SetName ("i2-hashtable, hash");
+
+    invalid = -1;
+    for (int i = 1; i <= size; i++)
+      hash.Elem(i).I1() = invalid;
+  }
+
+  void BASE_INDEX_2_CLOSED_HASHTABLE ::
+  BaseSetSize (int size)
+  {
+    hash.SetSize(size);
+    for (int i = 1; i <= size; i++)
+      hash.Elem(i).I1() = invalid;
+  }
+
+
+  int BASE_INDEX_2_CLOSED_HASHTABLE ::
+  Position2 (const INDEX_2 & ind) const
+  {
+    int i = HashValue(ind);
+    while (1)
+      {
+	i++;
+	if (i > hash.Size()) i = 1;
+	if (hash.Get(i) == ind) return i;
+	if (hash.Get(i).I1() == invalid) return 0;
+      }
+  }
+
+  int BASE_INDEX_2_CLOSED_HASHTABLE ::
+  PositionCreate2 (const INDEX_2 & ind, int & apos) 
+  {
+    int i = HashValue(ind);
+    int startpos = i;
+    while (1)
+      {
+	i++;
+	if (i > hash.Size()) i = 1;
+	if (hash.Get(i) == ind) 
+	  {
+	    apos = i;
+	    return 0;
+	  }
+	if (hash.Get(i).I1() == invalid) 
+	  {
+	    hash.Elem(i) = ind;
+	    apos = i;
+	    return 1;
+	  }
+	if (i == startpos)
+	  throw NgException ("Try to set new element in full closed hashtable");
+      }
+  }
+
+  int BASE_INDEX_2_CLOSED_HASHTABLE :: UsedElements () const
+  {
+    int n = hash.Size();
+    int cnt = 0;
+    for (int i = 1; i <= n; i++)
+      if (hash.Get(i).I1() != invalid)
+	cnt++;
+    return cnt;
+  }
+
+
+
+
+
+
+
+
+  void BASE_INDEX_3_CLOSED_HASHTABLE ::
+  BaseSetSize (int size)
+  {
+    hash.SetSize(size);
+    for (int i = 0; i < size; i++)
+      hash[i].I1() = invalid;
+  }
+
+  bool BASE_INDEX_3_CLOSED_HASHTABLE ::
+  PositionCreate2 (const INDEX_3 & ind, int & apos) 
+  {
+    int i = HashValue(ind);
+    int startpos = i;
+    while (1)
+      {
+        /*
+	i++;
+	if (i >= hash.Size()) i = 0;
+        */
+        i = (i+1) % hash.Size();
+	if (hash[i] == ind) 
+	  {
+	    apos = i;
+	    return false;
+	  }
+	if (hash[i].I1() == invalid) 
+	  {
+	    hash[i] = ind;
+	    apos = i;
+	    return true;
+	  }
+	if (i == startpos)
+	  throw NgException ("Try to set new element in full closed hashtable");
+      }
+  }
+}
+
diff --git a/contrib/Netgen/libsrc/general/hashtabl.hpp b/contrib/Netgen/libsrc/general/hashtabl.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..bc1781b9650f110cd5cbcd44a74077e3839857ac
--- /dev/null
+++ b/contrib/Netgen/libsrc/general/hashtabl.hpp
@@ -0,0 +1,1322 @@
+#ifndef FILE_HASHTABL
+#define FILE_HASHTABL
+
+/**************************************************************************/
+/* File:   hashtabl.hh                                                    */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   01. Jun. 95                                                    */
+/**************************************************************************/
+
+/**
+   Abstract data type HASHTABLE.
+   Hash is done by one INDEX
+*/
+class BASE_INDEX_HASHTABLE
+{
+protected:
+  /// keys are stored in this table
+  TABLE<INDEX> hash;
+  
+public:
+  ///
+  BASE_INDEX_HASHTABLE (int size)
+    : hash (size) { };
+  
+protected:
+  ///
+  int HashValue (const INDEX & ind) const
+    {
+      return ind % hash.Size() + 1;
+    }
+
+  ///
+  int Position (int bnr, const INDEX & ind) const;
+};
+
+///
+template <class T>
+class INDEX_HASHTABLE : private BASE_INDEX_HASHTABLE
+{
+  ///
+  TABLE<T> cont;
+  
+public:
+  ///
+  inline INDEX_HASHTABLE (int size);
+  ///
+  inline void Set (const INDEX & hash, const T & acont);
+  ///
+  inline const T & Get (const INDEX & ahash) const;
+  ///
+  inline bool Used (const INDEX & ahash) const;
+  ///
+  inline int GetNBags () const;
+  ///
+  inline int GetBagSize (int bnr) const;
+  ///
+  inline void GetData (int bnr, int colnr, INDEX & ahash, T & acont) const;
+
+  ///
+  inline void PrintMemInfo (ostream & ost) const;
+};
+
+
+
+
+
+
+
+
+
+
+
+///
+class BASE_INDEX_2_HASHTABLE
+{
+protected:
+  ///
+  TABLE<INDEX_2> hash;
+  
+public:
+  ///
+  BASE_INDEX_2_HASHTABLE (int size)
+    : hash (size) { };
+
+  ///
+  void PrintStat (ostream & ost) const;
+  void BaseSetSize(int s) {hash.SetSize(s);}
+protected:
+  ///
+  int HashValue (const INDEX_2 & ind) const
+    {
+      return (ind.I1() + ind.I2()) % hash.Size() + 1;
+    }
+  ///
+  int Position (int bnr, const INDEX_2 & ind) const
+  {
+    int i;
+    for (i = 1; i <= hash.EntrySize (bnr); i++)
+      if (hash.Get(bnr, i) == ind)
+	return i;
+    return 0;
+  }
+};
+
+
+///
+template <class T>
+class INDEX_2_HASHTABLE : public BASE_INDEX_2_HASHTABLE
+{
+  ///
+  TABLE<T> cont;
+  
+public:
+  ///
+ INDEX_2_HASHTABLE (int size)
+   : BASE_INDEX_2_HASHTABLE (size), cont(size)
+  { ; }  
+
+  ///
+  void SetSize(int s) 
+  { 
+    cont.SetSize(s); 
+    BaseSetSize(s);
+  }
+
+  ///
+  void Set (const INDEX_2 & ahash, const T & acont)
+  {
+    int bnr = HashValue (ahash);
+      int pos = Position (bnr, ahash);
+      if (pos)
+	cont.Set (bnr, pos, acont);
+      else
+	{
+	  hash.Add1 (bnr, ahash);
+	  cont.Add1 (bnr, acont);
+	}    
+  }
+  
+  ///
+  const T & Get (const INDEX_2 & ahash) const
+  {
+    int bnr = HashValue (ahash);
+    int pos = Position (bnr, ahash);
+    return cont.Get (bnr, pos);
+  }
+  
+  ///
+  bool Used (const INDEX_2 & ahash) const
+  {
+    return (Position (HashValue (ahash), ahash)) ? 1 : 0;
+  }
+ ///
+  int GetNBags () const
+  {
+    return cont.Size();
+  }
+  
+  ///
+  int GetBagSize (int bnr) const
+  {
+    return cont.EntrySize (bnr);
+  }
+    
+  ///
+  void GetData (int bnr, int colnr, 
+		INDEX_2 & ahash, T & acont) const
+  {
+    ahash = hash.Get(bnr, colnr);
+    acont = cont.Get(bnr, colnr);
+  }
+
+  ///
+  void SetData (int bnr, int colnr, 
+		const INDEX_2 & ahash, const T & acont) 
+  {
+    hash.Set(bnr, colnr, ahash);
+    cont.Set(bnr, colnr, acont);
+  }
+  
+  ///
+  void PrintMemInfo (ostream & ost) const
+  {
+    ost << "Hash: " << endl;
+    hash.PrintMemInfo (ost);
+    ost << "Cont: " << endl;
+    cont.PrintMemInfo (ost);
+  }
+
+
+  void DeleteData ()
+  {
+    int n = hash.Size();
+    hash.SetSize (n);
+    cont.SetSize (n);
+  }
+
+
+  class Iterator
+  {
+    const INDEX_2_HASHTABLE & ht;    
+    int bagnr, pos;
+  public:
+    Iterator (const INDEX_2_HASHTABLE & aht,
+	      int abagnr, int apos)
+      : ht(aht), bagnr(abagnr), pos(apos)
+    { ; }
+
+    int BagNr() const { return bagnr; }
+    int Pos() const { return pos; }
+
+    void operator++ (int)
+    {
+      // cout << "begin Operator ++: bagnr = " << bagnr << " -  pos = " << pos << endl;
+      pos++;
+      while (bagnr < ht.GetNBags() && 
+	     pos == ht.GetBagSize(bagnr+1))
+	{
+	  pos = 0;
+	  bagnr++;
+	}
+      // cout << "end Operator ++: bagnr = " << bagnr << " - pos = " << pos << endl;
+    }
+
+    bool operator != (int i) const
+    {
+      return bagnr != i;
+    }
+
+  };
+  
+  Iterator Begin () const
+  {
+    Iterator it(*this, 0, -1);
+    it++;
+    return it;
+  }
+
+  int End() const
+  {
+    return GetNBags();
+  }
+
+  void GetData (const Iterator & it,
+		INDEX_2 & ahash, T & acont) const
+  {
+    ahash = hash[it.BagNr()][it.Pos()];
+    acont = cont[it.BagNr()][it.Pos()];
+  }
+
+  const INDEX_2 & GetHash (const Iterator & it) const
+  { return hash[it.BagNr()][it.Pos()]; }
+
+  const T & GetData (const Iterator & it) const
+  { return cont[it.BagNr()][it.Pos()]; }
+};
+
+
+
+template <typename T> 
+inline ostream & operator<< (ostream & ost, const INDEX_2_HASHTABLE<T> & ht)
+{
+  for (typename INDEX_2_HASHTABLE<T>::Iterator it = ht.Begin();
+       it != ht.End(); it++)
+    {
+      ost << ht.GetHash(it) << ": " << ht.GetData(it) << endl;
+    }
+
+  return ost;
+}
+
+
+
+
+
+
+
+///
+class BASE_INDEX_3_HASHTABLE
+{
+protected:
+  ///
+  TABLE<INDEX_3> hash;
+
+public:
+  ///
+  BASE_INDEX_3_HASHTABLE (int size)
+    : hash (size) { };
+
+protected:
+  ///
+  int HashValue (const INDEX_3 & ind) const
+    {
+      return (ind.I1() + ind.I2() + ind.I3()) % hash.Size() + 1;
+    }
+
+  ///
+  int Position (int bnr, const INDEX_3 & ind) const
+  {
+    const INDEX_3 * pi = &hash.Get(bnr, 1);
+    int n = hash.EntrySize(bnr);
+    for (int i = 1; i <= n; ++i, ++pi)
+      {
+	if (*pi == ind)
+	return i;
+      }
+    
+    return 0;
+  }
+
+
+};
+
+
+///
+template <class T>
+class INDEX_3_HASHTABLE : private BASE_INDEX_3_HASHTABLE
+{
+  ///
+  TABLE<T> cont;
+
+public:
+  ///
+  inline INDEX_3_HASHTABLE (int size);
+  ///
+  inline void Set (const INDEX_3 & ahash, const T & acont);
+  ///
+  inline const T & Get (const INDEX_3 & ahash) const;
+  ///
+  inline bool Used (const INDEX_3 & ahash) const;
+  ///
+  inline int GetNBags () const;
+  ///
+  inline int GetBagSize (int bnr) const;
+  ///
+  inline void SetData (int bnr, int colnr, const INDEX_3 & ahash, const T & acont);
+  ///
+  inline void GetData (int bnr, int colnr, INDEX_3 & ahash, T & acont) const;
+  /// returns position, if not existing, will create (create == return 1)
+  inline int PositionCreate (const INDEX_3 & ahash, int & bnr, int & colnr);
+  ///
+  inline void SetSize (int size);
+
+  ///
+  inline void PrepareSet (const INDEX_3 & ahash);
+  ///
+  inline void AllocateElements ();
+
+  ///
+  inline void PrintMemInfo (ostream & ost) const;
+  ///
+  inline void DeleteData ();
+
+
+
+
+
+
+
+
+
+  class Iterator
+  {
+    const INDEX_3_HASHTABLE & ht;    
+    int bagnr, pos;
+  public:
+    Iterator (const INDEX_3_HASHTABLE & aht,
+	      int abagnr, int apos)
+      : ht(aht), bagnr(abagnr), pos(apos)
+    { ; }
+
+    int BagNr() const { return bagnr; }
+    int Pos() const { return pos; }
+
+    void operator++ (int)
+    {
+      // cout << "begin Operator ++: bagnr = " << bagnr << " -  pos = " << pos << endl;
+      pos++;
+      while (bagnr < ht.GetNBags() && 
+	     pos == ht.GetBagSize(bagnr+1))
+	{
+	  pos = 0;
+	  bagnr++;
+	}
+      // cout << "end Operator ++: bagnr = " << bagnr << " - pos = " << pos << endl;
+    }
+
+    bool operator != (int i) const
+    {
+      return bagnr != i;
+    }
+
+  };
+  
+  Iterator Begin () const
+  {
+    Iterator it(*this, 0, -1);
+    it++;
+    return it;
+  }
+
+  int End() const
+  {
+    return GetNBags();
+  }
+
+  void GetData (const Iterator & it,
+		INDEX_3 & ahash, T & acont) const
+  {
+    ahash = hash[it.BagNr()][it.Pos()];
+    acont = cont[it.BagNr()][it.Pos()];
+  }
+
+  const INDEX_3 & GetHash (const Iterator & it) const
+  { return hash[it.BagNr()][it.Pos()]; }
+
+  const T & GetData (const Iterator & it) const
+  { return cont[it.BagNr()][it.Pos()]; }
+
+
+
+};
+
+
+
+
+
+
+template <typename T> 
+inline ostream & operator<< (ostream & ost, const INDEX_3_HASHTABLE<T> & ht)
+{
+  for (typename INDEX_3_HASHTABLE<T>::Iterator it = ht.Begin();
+       it != ht.End(); it++)
+    {
+      ost << ht.GetHash(it) << ": " << ht.GetData(it) << endl;
+    }
+
+  return ost;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+/// Closed Hashing HT
+
+class BASE_INDEX_CLOSED_HASHTABLE
+{
+protected:
+  ///
+  MoveableArray<INDEX> hash;
+  ///
+  int invalid;
+public:
+  ///
+  BASE_INDEX_CLOSED_HASHTABLE (int size);
+
+  int Size() const { return hash.Size(); }
+  int UsedPos (int pos) const { return ! (hash.Get(pos) == invalid); }
+  int UsedElements () const;
+
+  ///
+  int HashValue (const INDEX & ind) const
+  {
+    return ind % hash.Size() + 1;
+  }
+
+
+  int Position (const INDEX & ind) const
+  {
+    int i = HashValue(ind);
+    while (1)
+      {
+	if (hash.Get(i) == ind) return i;
+	if (hash.Get(i) == invalid) return 0;
+	i++;
+	if (i > hash.Size()) i = 1;
+      }
+  }
+
+  // returns 1, if new postion is created
+  int PositionCreate (const INDEX & ind, int & apos)
+  {
+    int i = HashValue (ind);
+    if (hash.Get(i) == ind) 
+      {
+	apos = i;
+	return 0;
+      }
+    if (hash.Get(i) == invalid)
+      {
+	hash.Elem(i) = ind; 
+	apos = i;
+	return 1;
+      }
+    return PositionCreate2 (ind, apos);    
+  }
+
+protected:
+  int Position2 (const INDEX & ind) const;
+  int PositionCreate2 (const INDEX & ind, int & apos);
+  void BaseSetSize (int asize);
+};
+
+
+template <class T>
+class INDEX_CLOSED_HASHTABLE : public BASE_INDEX_CLOSED_HASHTABLE
+{
+  ///
+  MoveableArray<T> cont;
+
+public:
+  ///
+  INDEX_CLOSED_HASHTABLE (int size)
+    : BASE_INDEX_CLOSED_HASHTABLE(size), cont(size)
+  {
+    cont.SetName ("ind-hashtable, contents");
+  }
+
+
+  void Set (const INDEX & ahash, const T & acont)
+  {
+    int pos;
+    PositionCreate (ahash, pos);
+    hash.Elem(pos) = ahash;
+    cont.Elem(pos) = acont;
+  }
+
+  const T & Get (const INDEX & ahash) const
+  {
+    int pos = Position (ahash);
+    return cont.Get(pos);
+  }
+
+  ///
+  bool Used (const INDEX & ahash) const
+  {
+    int pos = Position (ahash);
+    return (pos != 0);
+  }
+  
+  
+  ///
+  inline void SetData (int pos, const INDEX & ahash, const T & acont)
+  {
+    hash.Elem(pos) = ahash;
+    cont.Elem(pos) = acont;
+  }
+
+  ///
+  void GetData (int pos, INDEX & ahash, T & acont) const
+  {
+    ahash = hash.Get(pos);
+    acont = cont.Get(pos);
+  }
+  
+  ///
+  inline void SetData (int pos, const T & acont)
+  {
+    cont.Elem(pos) = acont;
+  }
+  
+  ///
+  void GetData (int pos, T & acont) const
+  {
+    acont = cont.Get(pos);
+  }
+  
+  ///
+  const T & GetData (int pos) { return cont.Get(pos); }
+  ///
+  inline void SetSize (int size)
+  {
+    BaseSetSize(size);
+  cont.SetSize(size);
+  }
+  
+  ///
+  inline void DeleteData ()
+  { SetSize (cont.Size()); }
+
+  void SetName (const char * aname)
+  {
+    cont.SetName(aname);
+    hash.SetName(aname);
+  }
+};
+
+
+
+
+
+
+
+/// Closed Hashing HT
+
+class BASE_INDEX_2_CLOSED_HASHTABLE
+{
+protected:
+  ///
+  MoveableArray<INDEX_2> hash;
+  ///
+  int invalid;
+public:
+  ///
+  BASE_INDEX_2_CLOSED_HASHTABLE (int size);
+
+  int Size() const { return hash.Size(); }
+  int UsedPos (int pos) const { return ! (hash.Get(pos).I1() == invalid); }
+  int UsedElements () const;
+
+  ///
+  int HashValue (const INDEX_2 & ind) const
+    {
+      return (ind.I1() + 71 * ind.I2()) % hash.Size() + 1;
+    }
+
+
+  int Position (const INDEX_2 & ind) const
+  {
+    int i = HashValue(ind);
+    while (1)
+      {
+	if (hash.Get(i) == ind) return i;
+	if (hash.Get(i).I1() == invalid) return 0;
+	i++;
+	if (i > hash.Size()) i = 1;
+      }
+  }
+
+  // returns 1, if new postion is created
+  int PositionCreate (const INDEX_2 & ind, int & apos)
+  {
+    int i = HashValue (ind);
+    if (hash.Get(i) == ind) 
+      {
+	apos = i;
+	return 0;
+      }
+    if (hash.Get(i).I1() == invalid)
+      {
+	hash.Elem(i) = ind; 
+	apos = i;
+	return 1;
+      }
+    return PositionCreate2 (ind, apos);    
+  }
+
+protected:
+  ///
+
+  int Position2 (const INDEX_2 & ind) const;
+  int PositionCreate2 (const INDEX_2 & ind, int & apos);
+  void BaseSetSize (int asize);
+};
+
+
+template <class T>
+class INDEX_2_CLOSED_HASHTABLE : public BASE_INDEX_2_CLOSED_HASHTABLE
+{
+  ///
+  MoveableArray<T> cont;
+
+public:
+  ///
+  inline INDEX_2_CLOSED_HASHTABLE (int size);
+  ///
+  inline void Set (const INDEX_2 & ahash, const T & acont);
+  ///
+  inline const T & Get (const INDEX_2 & ahash) const;
+  ///
+  inline bool Used (const INDEX_2 & ahash) const;
+  ///
+  inline void SetData (int pos, const INDEX_2 & ahash, const T & acont);
+  ///
+  inline void GetData (int pos, INDEX_2 & ahash, T & acont) const;
+  ///
+  inline void SetData (int pos, const T & acont);
+  ///
+  inline void GetData (int pos, T & acont) const;
+  ///
+  const T & GetData (int pos) { return cont.Get(pos); }
+  ///
+  inline void SetSize (int size);
+  ///
+  inline void PrintMemInfo (ostream & ost) const;
+  ///
+  inline void DeleteData ()
+  { SetSize (cont.Size()); }
+
+  void SetName (const char * aname)
+  {
+    cont.SetName(aname);
+    hash.SetName(aname);
+  }
+};
+
+class BASE_INDEX_3_CLOSED_HASHTABLE
+{
+protected:
+  MoveableArray<INDEX_3> hash;
+  int invalid;
+
+protected: 
+  // public:    //SZ
+  BASE_INDEX_3_CLOSED_HASHTABLE (int size)
+    : hash(size)
+  {
+    hash.SetName ("i3-hashtable, hash");
+    invalid = -1;
+    for (int i = 0; i < size; i++)
+      hash[i].I1() = invalid;
+  }
+
+public:
+  int Size() const 
+  {
+    return hash.Size(); 
+  }
+
+  bool UsedPos (int pos) const 
+  { 
+    return ! (hash[pos].I1() == invalid); 
+  }
+
+  int UsedElements () const
+  {
+    int n = hash.Size();
+    int cnt = 0;
+    for (int i = 0; i < n; i++)
+      if (hash[i].I1() != invalid)
+	cnt++;
+    return cnt;
+  }
+
+  int HashValue (const INDEX_3 & ind) const
+  {
+    return (ind.I1() + 15 * ind.I2() + 41 * ind.I3()) % hash.Size();
+  }
+  
+  int Position (const INDEX_3 & ind) const
+  {
+    int i = HashValue(ind);
+    while (1)
+      {
+	if (hash[i] == ind) return i;
+	if (hash[i].I1() == invalid) return -1;
+        i = (i+1) % hash.Size();
+      }
+  }
+
+  int Costs (const INDEX_3 & ind) const
+  {
+    int i = HashValue(ind);
+    int c = 1;
+    while (1)
+      {
+	if (hash[i] == ind) return c;
+	if (hash[i].I1() == invalid) return c;
+        i = (i+1) % hash.Size();
+        c++;
+      }
+  }
+
+
+  
+  // returns true, if new postion is created
+  bool PositionCreate (const INDEX_3 & ind, int & apos)
+  {
+    int i = HashValue (ind);
+    if (hash[i] == ind) 
+      {
+	apos = i;
+	return false;
+      }
+    if (hash[i].I1() == invalid)
+      {
+	hash[i] = ind; 
+	apos = i;
+	return true;
+      }
+    return PositionCreate2 (ind, apos);    
+  }
+
+protected:
+  bool PositionCreate2 (const INDEX_3 & ind, int & apos);
+  void BaseSetSize (int asize);
+};
+
+
+
+template <class T>
+class INDEX_3_CLOSED_HASHTABLE : public BASE_INDEX_3_CLOSED_HASHTABLE
+{
+  MoveableArray<T,0> cont;
+
+public:
+  INDEX_3_CLOSED_HASHTABLE (int size)
+    : BASE_INDEX_3_CLOSED_HASHTABLE(size), cont(size)
+  {
+    cont.SetName ("i3-hashtable, contents");
+  }
+  
+  void Set (const INDEX_3 & ahash, const T & acont)
+  {
+    int pos;
+    PositionCreate (ahash, pos);
+    hash[pos] = ahash;
+    cont[pos] = acont;
+  }
+
+  const T & Get (const INDEX_3 & ahash) const
+  {
+    return cont[Position (ahash)];
+  }
+
+  bool Used (const INDEX_3 & ahash) const
+  {
+    return (Position (ahash) != -1);
+  }
+
+  void SetData (int pos, const INDEX_3 & ahash, const T & acont)
+  {
+    hash[pos] = ahash;
+    cont[pos] = acont;
+  }
+
+  void GetData (int pos, INDEX_3 & ahash, T & acont) const
+  {
+    ahash = hash[pos];
+    acont = cont[pos];
+  }
+
+  void SetData (int pos, const T & acont)
+  {
+    cont[pos] = acont;
+  }
+
+  void GetData (int pos, T & acont) const
+  {
+    acont = cont[pos];
+  }
+
+  const T & GetData (int pos) const
+  {
+    return cont[pos];
+  }
+
+   void SetSize (int size)
+  {
+    BaseSetSize(size);
+    cont.SetSize(size);
+  }
+
+  void PrintMemInfo (ostream & ost) const
+  {
+    cout << "Hashtable: " << Size() 
+         << " entries of size " << sizeof(INDEX_3) << " + " << sizeof(T) 
+         << " = " << Size() * (sizeof(INDEX_3) + sizeof(T)) << " bytes" << endl;
+    
+  }
+
+  void DeleteData ()
+  { 
+    SetSize (cont.Size()); 
+  }
+
+  void SetName (const char * aname)
+  {
+    cont.SetName(aname);
+    hash.SetName(aname);
+  }
+};
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+template<class T>
+inline INDEX_3_HASHTABLE<T> :: INDEX_3_HASHTABLE (int size)
+  : BASE_INDEX_3_HASHTABLE (size), cont(size)
+{
+  ;
+}
+
+template<class T>	
+inline int INDEX_3_HASHTABLE<T> :: PositionCreate (const INDEX_3 & ahash, int & bnr, int & colnr)
+{
+  bnr = HashValue (ahash);
+  colnr = Position (bnr, ahash);
+  if (!colnr)
+    {
+      hash.Add (bnr, ahash);
+      cont.AddEmpty (bnr);
+      colnr = cont.EntrySize (bnr);
+      return 1;
+    }
+  return 0;
+}
+
+
+template<class T>
+inline void INDEX_3_HASHTABLE<T> :: Set (const INDEX_3 & ahash, const T & acont)
+{
+  int bnr = HashValue (ahash);
+  int pos = Position (bnr, ahash);
+  if (pos)
+    cont.Set (bnr, pos, acont);
+  else
+    {
+      hash.Add1 (bnr, ahash);
+      cont.Add1 (bnr, acont);
+    }
+}
+
+template<class T>
+inline const T & INDEX_3_HASHTABLE<T> :: Get (const INDEX_3 & ahash) const
+{
+  int bnr = HashValue (ahash);
+  int pos = Position (bnr, ahash);
+  return cont.Get (bnr, pos);
+}
+
+template<class T>
+inline bool INDEX_3_HASHTABLE<T> :: Used (const INDEX_3 & ahash) const
+{
+  return (Position (HashValue (ahash), ahash)) ? 1 : 0;
+}
+
+template<class T>
+inline int INDEX_3_HASHTABLE<T> :: GetNBags () const
+{
+  return cont.Size();
+}
+
+template<class T>
+inline int INDEX_3_HASHTABLE<T> :: GetBagSize (int bnr) const
+{
+  return cont.EntrySize (bnr);
+}
+
+template<class T>
+inline void INDEX_3_HASHTABLE<T> :: GetData (int bnr, int colnr, INDEX_3 & ahash, T & acont) const
+{
+  ahash = hash.Get(bnr, colnr);
+  acont = cont.Get(bnr, colnr);
+}    
+
+template<class T>
+inline void INDEX_3_HASHTABLE<T> :: SetData (int bnr, int colnr, const INDEX_3 & ahash, const T & acont)
+{
+  hash.Set(bnr, colnr, ahash);
+  cont.Set(bnr, colnr, acont);
+}    
+
+template<class T>
+inline void INDEX_3_HASHTABLE<T> :: SetSize (int size)
+{
+  hash.SetSize (size);
+  cont.SetSize (size);
+}
+
+template<class T>
+inline void INDEX_3_HASHTABLE<T> :: DeleteData ()
+{
+  int n = hash.Size();
+  hash.SetSize (n);
+  cont.SetSize (n);
+}
+
+template<class T>
+inline void INDEX_3_HASHTABLE<T> :: PrepareSet (const INDEX_3 & ahash)
+{
+  int bnr = HashValue (ahash);
+  hash.IncSizePrepare (bnr-1);
+  cont.IncSizePrepare (bnr-1);
+}
+
+
+template<class T>
+inline void INDEX_3_HASHTABLE<T> :: AllocateElements ()
+{
+  hash.AllocateElementsOneBlock();
+  cont.AllocateElementsOneBlock();
+}
+
+
+
+template<class T>
+inline void INDEX_3_HASHTABLE<T> :: PrintMemInfo (ostream & ost) const
+  {
+    ost << "Hash: " << endl;
+    hash.PrintMemInfo (ost);
+    ost << "Cont: " << endl;
+    cont.PrintMemInfo (ost);
+  }
+
+
+
+
+
+template<class T>
+inline INDEX_HASHTABLE<T> :: INDEX_HASHTABLE (int size)
+  : BASE_INDEX_HASHTABLE (size), cont(size)
+  {
+    ;
+  }
+	
+template<class T>
+inline void INDEX_HASHTABLE<T> :: Set (const INDEX & ahash, const T & acont)
+    {
+    int bnr = HashValue (ahash);
+    int pos = Position (bnr, ahash);
+    if (pos)
+      cont.Set (bnr, pos, acont);
+    else
+      {
+      hash.Add (bnr, ahash);
+      cont.Add (bnr, acont);
+      }
+    }
+
+template<class T>
+inline const T & INDEX_HASHTABLE<T> :: Get (const INDEX & ahash) const
+    {
+    int bnr = HashValue (ahash);
+    int pos = Position (bnr, ahash);
+    return cont.Get (bnr, pos);
+    }
+
+template<class T>
+inline bool INDEX_HASHTABLE<T> :: Used (const INDEX & ahash) const
+    {
+    return (Position (HashValue (ahash), ahash)) ? 1 : 0;
+    }
+
+template<class T>
+inline int INDEX_HASHTABLE<T> :: GetNBags () const
+    {
+    return hash.Size();
+    }
+
+template<class T>
+inline int INDEX_HASHTABLE<T> :: GetBagSize (int bnr) const
+    {
+    return hash.EntrySize(bnr);
+    }
+
+template<class T>
+inline void INDEX_HASHTABLE<T> :: GetData (int bnr, int colnr, INDEX & ahash, T & acont) const
+    {
+    ahash = hash.Get(bnr, colnr);   
+    acont = cont.Get(bnr, colnr);
+    }
+    
+template<class T>
+inline void INDEX_HASHTABLE<T> :: PrintMemInfo (ostream & ost) const
+  {
+    ost << "Hash: " << endl;
+    hash.PrintMemInfo (ost);
+    ost << "Cont: " << endl;
+    cont.PrintMemInfo (ost);
+  }
+
+
+    
+    
+    
+    
+    
+
+
+
+
+
+
+
+
+/* *********** Closed Hashing ************************* */
+
+
+
+template<class T>
+inline INDEX_2_CLOSED_HASHTABLE<T> :: 
+INDEX_2_CLOSED_HASHTABLE (int size)
+  : BASE_INDEX_2_CLOSED_HASHTABLE(size), cont(size)
+{
+  cont.SetName ("i2-hashtable, contents");
+}
+
+template<class T>
+inline void INDEX_2_CLOSED_HASHTABLE<T> :: 
+Set (const INDEX_2 & ahash, const T & acont)
+{
+  int pos;
+  PositionCreate (ahash, pos);
+  hash.Elem(pos) = ahash;
+  cont.Elem(pos) = acont;
+}
+
+template<class T>
+inline const T & INDEX_2_CLOSED_HASHTABLE<T> :: 
+Get (const INDEX_2 & ahash) const
+{
+  int pos = Position (ahash);
+  return cont.Get(pos);
+}
+
+template<class T>
+inline bool INDEX_2_CLOSED_HASHTABLE<T> :: 
+Used (const INDEX_2 & ahash) const
+{
+  int pos = Position (ahash);
+  return (pos != 0);
+}
+
+template<class T>
+inline void INDEX_2_CLOSED_HASHTABLE<T> :: 
+SetData (int pos, const INDEX_2 & ahash, const T & acont)
+{
+  hash.Elem(pos) = ahash;
+  cont.Elem(pos) = acont;
+}
+  
+template<class T>
+inline void INDEX_2_CLOSED_HASHTABLE<T> :: 
+GetData (int pos, INDEX_2 & ahash, T & acont) const
+{
+  ahash = hash.Get(pos);
+  acont = cont.Get(pos);
+}
+
+template<class T>
+inline void INDEX_2_CLOSED_HASHTABLE<T> :: 
+SetData (int pos, const T & acont)
+{
+  cont.Elem(pos) = acont;
+}
+  
+template<class T>
+inline void INDEX_2_CLOSED_HASHTABLE<T> :: 
+GetData (int pos, T & acont) const
+{
+  acont = cont.Get(pos);
+}
+
+
+template<class T>
+inline void INDEX_2_CLOSED_HASHTABLE<T> :: 
+SetSize (int size)
+{
+  BaseSetSize(size);
+  cont.SetSize(size);
+}
+
+
+  
+template<class T>
+inline void INDEX_2_CLOSED_HASHTABLE<T> :: 
+PrintMemInfo (ostream & ost) const
+{
+  cout << "Hashtable: " << Size() 
+       << " entries of size " << sizeof(INDEX_2) << " + " << sizeof(T) 
+       << " = " << Size() * (sizeof(INDEX_2) + sizeof(T)) << " bytes." 
+       << " Used els: " << UsedElements() 
+       << endl;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+/*
+template<class T>
+inline INDEX_3_CLOSED_HASHTABLE<T> :: 
+INDEX_3_CLOSED_HASHTABLE (int size)
+  : BASE_INDEX_3_CLOSED_HASHTABLE(size), cont(size)
+{
+  cont.SetName ("i3-hashtable, contents");
+}
+
+template<class T>
+inline void INDEX_3_CLOSED_HASHTABLE<T> :: 
+Set (const INDEX_3 & ahash, const T & acont)
+{
+  int pos;
+  PositionCreate (ahash, pos);
+  hash.Elem(pos) = ahash;
+  cont.Elem(pos) = acont;
+}
+
+template<class T>
+inline const T & INDEX_3_CLOSED_HASHTABLE<T> :: 
+Get (const INDEX_3 & ahash) const
+{
+  int pos = Position (ahash);
+  return cont[pos];
+}
+
+template<class T>
+inline bool INDEX_3_CLOSED_HASHTABLE<T> :: 
+Used (const INDEX_3 & ahash) const
+{
+  int pos = Position (ahash);
+  return (pos != 0);
+}
+
+template<class T>
+inline void INDEX_3_CLOSED_HASHTABLE<T> :: 
+SetData (int pos, const INDEX_3 & ahash, const T & acont)
+{
+  hash.Elem(pos) = ahash;
+  cont.Elem(pos) = acont;
+}
+  
+template<class T>
+inline void INDEX_3_CLOSED_HASHTABLE<T> :: 
+GetData (int pos, INDEX_3 & ahash, T & acont) const
+{
+  ahash = hash.Get(pos);
+  acont = cont.Get(pos);
+}
+
+template<class T>
+inline void INDEX_3_CLOSED_HASHTABLE<T> :: 
+SetData (int pos, const T & acont)
+{
+  cont.Elem(pos) = acont;
+}
+  
+template<class T>
+inline void INDEX_3_CLOSED_HASHTABLE<T> :: 
+GetData (int pos, T & acont) const
+{
+  acont = cont.Get(pos);
+}
+
+template<class T>
+inline const T & INDEX_3_CLOSED_HASHTABLE<T> :: 
+GetData (int pos) const
+{
+  return cont.Get(pos);
+}
+
+
+template<class T>
+inline void INDEX_3_CLOSED_HASHTABLE<T> :: 
+SetSize (int size)
+{
+  BaseSetSize(size);
+  cont.SetSize(size);
+}
+  
+template<class T>
+inline void INDEX_3_CLOSED_HASHTABLE<T> :: 
+PrintMemInfo (ostream & ost) const
+{
+  cout << "Hashtable: " << Size() 
+       << " entries of size " << sizeof(INDEX_3) << " + " << sizeof(T) 
+       << " = " << Size() * (sizeof(INDEX_3) + sizeof(T)) << " bytes" << endl;
+}
+*/
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#endif
diff --git a/contrib/Netgen/libsrc/general/moveablemem.cpp b/contrib/Netgen/libsrc/general/moveablemem.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..e7f3c1dab6df0a8d8e32417fc28aeeee60271f42
--- /dev/null
+++ b/contrib/Netgen/libsrc/general/moveablemem.cpp
@@ -0,0 +1,271 @@
+#include <iostream>
+#include <iomanip>
+
+#include <myadt.hpp>
+using namespace std;
+namespace netgen
+{
+  
+  NgMutex mem_mutex;
+  
+  size_t BaseMoveableMem::totalsize = 0; // 500000000;
+  size_t BaseMoveableMem::used = 0;
+  char * BaseMoveableMem::largeblock = 0;
+  
+  BaseMoveableMem * BaseMoveableMem::first = 0;
+  BaseMoveableMem * BaseMoveableMem::last = 0;
+  
+
+  BaseMoveableMem :: BaseMoveableMem (size_t s)
+  {
+    // cout << "Construct object begin" << endl;
+    //   Print ();
+
+  prev = last;
+  next = 0;
+
+  if (last) last->next = this;
+  last = this;
+  if (!first) first = this;
+
+  size = 0;
+
+  if (prev)
+    pos = prev->pos + prev->size;
+  else
+    pos = 0;
+
+  ptr = 0;
+  name = NULL;
+
+  if (s) Alloc(s);
+}
+ 
+BaseMoveableMem :: ~BaseMoveableMem () throw()
+{
+  Free();
+
+  if (next) next->prev = prev;
+  else last = prev;
+  if (prev) prev->next = next;
+  else first = next;
+
+  if(name != NULL)
+    {
+      delete [] name;
+      name = NULL;
+    }
+}
+
+void BaseMoveableMem :: SetName (const char * aname)
+{
+  if(name != NULL)
+    {
+      delete [] name;
+      name = NULL;
+    }
+  if (aname)
+    {
+      name = new char[strlen(aname)+1];
+      strcpy (name, aname);
+    }
+}
+
+
+void BaseMoveableMem :: Alloc (size_t s)
+{
+  if (totalsize == 0)
+    {
+      size = s;
+      //ptr = (char*) malloc(s);
+      ptr = new char[s];
+
+      if (!ptr)
+	{
+	  cerr << "BaseynamicMem, cannot allocate " << s << " bytes" << endl;
+	  Print ();
+	  throw ("BaseDynamicMem::Alloc: out of memory");
+	}
+
+      return;
+    }
+
+
+  used += s - size;
+
+  size_t r = s % 8;
+  if (r) s += 8-r;
+  if (prev)
+    pos = prev->pos + prev->size;
+  else
+    pos = 0;
+  size = s;
+  
+  if (next)
+    {
+      NgLock lock(mem_mutex);
+      lock.Lock();
+      try
+	{
+	  next->MoveTo (pos+size);
+	}
+      catch (NgException e)
+      {
+	lock.UnLock();
+	throw NgException ("MoveableMem overflow");
+      }
+      lock.UnLock();
+    }
+
+  if (size)
+    {
+      if (!largeblock)
+	{
+	  cout << "moveable memory: allocate large block of "
+	       << totalsize / 1048576  << " MB" << endl; 
+	  // largeblock = new char[totalsize];
+	  // largeblock = (char*)malloc (totalsize);
+	  largeblock = new char[totalsize];
+	}
+      ptr = largeblock+pos;
+
+      if (pos + size > totalsize)
+	throw NgException ("MoveableMem overflow");
+    }
+  else
+    ptr = 0;
+}
+
+void BaseMoveableMem :: ReAlloc (size_t s)
+{
+  if (totalsize == 0)
+    {
+      if (size == s) return;
+      
+      char * old = ptr;
+      ptr = new char[s];
+
+      if (!ptr)
+	{
+	  cerr << "BaseynamicMem, cannot Reallocate " << s << " bytes" << endl;
+	  Print ();
+	  throw ("BaseDynamicMem::Alloc: out of memory");
+	}
+      
+
+
+      memmove (ptr, old, (s < size) ? s : size);
+      //free (old);
+      delete [] old;
+      size = s;
+      return;
+    }
+
+  Alloc (s);
+}
+
+void BaseMoveableMem :: MoveTo (size_t newpos)
+{
+  //  cout << "move block, oldpos = " << pos << "; newpos = " << newpos
+  // << ", size = " << size << endl;
+  static size_t move = 0;
+
+  if (newpos + size > totalsize)
+    throw NgException ("MoveableMem overflow");
+  if (newpos > pos)
+    {
+      if (next) next->MoveTo (newpos+size);
+      memmove (largeblock+newpos, largeblock+pos, size);
+      move += size;
+    }
+  else if (newpos < pos)
+    {
+      // cout << "move down: " << size << endl;
+      memmove (largeblock+newpos, largeblock+pos, size);
+      if (next) next->MoveTo (newpos+size);
+      move += size;
+    }
+  pos = newpos;
+  ptr = largeblock+pos;
+  //  cout << "total move: " << move << endl;
+}
+
+void BaseMoveableMem :: Free () throw()
+{
+  if (totalsize == 0)
+    {
+      //free (ptr);
+      delete [] ptr;
+      ptr = 0;
+      return;
+    }
+
+  /*
+    cout << "free block, pos = " << pos << "size = " << size << endl;
+    cout << "before: " << endl;
+    Print();
+  */
+  used -= size;
+  if (next) 
+    {
+      NgLock lock(mem_mutex);
+      lock.Lock();
+      next->MoveTo (pos);
+      lock.UnLock();
+    }
+  
+  size = 0;
+  ptr = 0;
+  // pos = 0;
+}
+
+void BaseMoveableMem :: Swap (BaseMoveableMem & m2) throw()
+{
+  size_t hi;
+  // BaseMoveableMem * hp;
+  char * cp;
+  hi = size; size  = m2.size; m2.size = hi;
+  hi = pos; pos = m2.pos; m2.pos = hi;
+  /*
+  hp = prev; prev = m2.prev; m2.prev = hp;
+  hp = next; next = m2.next; m2.next = hp;
+  */
+  cp = ptr; ptr = m2.ptr; m2.ptr = cp;
+  cp = name; name = m2.name; m2.name = cp;
+}
+
+
+void BaseMoveableMem :: Print ()
+{
+  cout << "****************** Moveable Mem Report ****************" << endl;
+  BaseMoveableMem * p = first;
+  long int mem = 0;
+  int cnt = 0;
+  while (p)
+    {
+      mem += long(p->size);
+      cnt++;
+
+      cout << setw(10) << p->size << " Bytes";
+      cout << ", pos = " << p->pos;
+      cout << ", addr = " << (void*)p->ptr;
+      if (p->name)
+	cout << " in block " << p->name;
+      cout << endl;
+
+      p = p->next;
+    }
+
+  if (mem > 100000000)
+    cout << "memory in moveable arena: " << mem/1048576 << " MB" << endl;
+  else if (mem > 100000)
+    cout << "memory in moveable arena: " << mem/1024 << " kB" << endl;
+  else
+    cout << "memory in moveable arena: " << mem << " Bytes" << endl;
+  cout << "number of blocks:         " << cnt << endl;
+  
+  cout << " used  = " << used << endl;
+  //  cout << "******************************************************" << endl;
+}
+
+}
diff --git a/contrib/Netgen/libsrc/general/moveablemem.hpp b/contrib/Netgen/libsrc/general/moveablemem.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..b0761ee233ad51f40bfbece3e8913dd4157928a7
--- /dev/null
+++ b/contrib/Netgen/libsrc/general/moveablemem.hpp
@@ -0,0 +1,99 @@
+#ifndef FILE_MOVEABLEMEM
+#define FILE_MOVEABLEMEM
+
+/**************************************************************************/
+/* File:   moveablemem.hpp                                                */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   12. Feb. 2003                                                  */
+/**************************************************************************/
+
+
+extern NgMutex mem_mutex;
+
+class BaseMoveableMem
+{
+public:
+  static size_t totalsize;
+  static size_t used;
+
+private:
+  static char * largeblock;
+  static BaseMoveableMem *first, *last;
+
+  BaseMoveableMem *prev, *next;
+  size_t size, pos;
+  char * ptr;
+  char * name;
+
+protected:
+  BaseMoveableMem (size_t s = 0);
+  ~BaseMoveableMem () throw();
+  void Alloc (size_t s);
+  void ReAlloc (size_t s);
+  void MoveTo (size_t newpos);
+  void Free () throw(); 
+  char * Ptr() { return ptr; }
+  char * Ptr() const { return ptr; }
+  void Swap (BaseMoveableMem & m2) throw(); 
+public:
+  void SetName (const char * aname);
+  static void Print ();
+
+  friend class BaseDynamicMem;
+};
+
+
+
+
+template <typename T>
+class MoveableMem : public BaseMoveableMem
+{
+public:
+  MoveableMem (size_t s = 0)
+    : BaseMoveableMem (sizeof(T) * s) 
+  {
+    ;
+  }
+  void Alloc (size_t s)
+  {
+    BaseMoveableMem::Alloc (sizeof(T) * s);
+  }
+  void ReAlloc (size_t s)
+  {
+    BaseMoveableMem::ReAlloc (sizeof(T) * s);
+  }
+  void Free ()
+  {
+    BaseMoveableMem::Free ();
+  }
+
+  const T * Ptr() const
+  {
+    return reinterpret_cast<const T*> (BaseMoveableMem::Ptr());
+  }
+
+  T * Ptr()
+  {
+    return reinterpret_cast<T*> (BaseMoveableMem::Ptr());
+  }
+
+  operator T* () const
+  {
+    return reinterpret_cast<T*> (BaseMoveableMem::Ptr());
+  }
+
+  operator T* () 
+  {
+    return reinterpret_cast<T*> (BaseMoveableMem::Ptr());
+  }
+
+  void Swap (MoveableMem<T> & m2)
+  {
+    BaseMoveableMem::Swap (m2);
+  }
+protected:
+  MoveableMem (const MoveableMem & m) { ; }
+  MoveableMem & operator= (const MoveableMem & m) { ; }
+};
+
+#endif
diff --git a/contrib/Netgen/libsrc/general/myadt.hpp b/contrib/Netgen/libsrc/general/myadt.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..ec0740296065f7934d8443f84b5a1de64b5332b7
--- /dev/null
+++ b/contrib/Netgen/libsrc/general/myadt.hpp
@@ -0,0 +1,46 @@
+#ifndef FILE_MYADT
+#define FILE_MYADT
+
+/**************************************************************************/
+/* File:   myadt.hpp                                                      */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   01. Jun. 95                                                    */
+/**************************************************************************/
+
+/* 
+   include for all abstract data types
+*/
+
+
+
+#include "../include/mystdlib.h"
+#include "../include/mydefs.hpp"
+
+
+namespace netgen
+{
+#include "ngexception.hpp"
+#include "parthreads.hpp"
+#include "moveablemem.hpp"
+#include "dynamicmem.hpp"
+
+#include "template.hpp"
+#include "array.hpp"
+#include "table.hpp"
+#include "hashtabl.hpp"
+#include "symbolta.hpp"
+#include "bitarray.hpp"
+#include "flags.hpp"
+#include "spbita2d.hpp"
+#include "seti.hpp"
+#include "optmem.hpp"
+#include "autoptr.hpp"
+#include "sort.hpp"
+#include "stack.hpp"
+#include "mystring.hpp"
+#include "profiler.hpp"
+#include "netgenout.hpp"
+
+}
+
+#endif
diff --git a/contrib/Netgen/libsrc/general/mystring.cpp b/contrib/Netgen/libsrc/general/mystring.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..6538a460310e91d460230b09a6ea88022420059c
--- /dev/null
+++ b/contrib/Netgen/libsrc/general/mystring.cpp
@@ -0,0 +1,437 @@
+
+//**************************************************************
+//
+// filename:             mystring.cpp
+//
+// project:              doctoral thesis
+//
+// autor:                Dipl.-Ing. Gerstmayr Johannes
+//
+// generated:            20.12.98
+// last change:          20.12.98
+// description:          implementation for strings
+// remarks:
+//
+//**************************************************************
+
+// string class
+#include <mystdlib.h>
+#include <myadt.hpp>
+
+#include <linalg.hpp>
+#include <gprim.hpp>
+
+/*
+#include <iostream.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <math.h>
+#include <fstream.h>
+#include "mystring.hh"
+
+ */
+
+namespace netgen
+{
+
+
+  void ReadEnclString(istream & in, string & str, const char encl)
+  {
+    char currchar;
+    str = "";
+
+    in.get(currchar);
+    while(in && currchar == ' ' || currchar == '\t' || currchar == '\n')
+      in.get(currchar);
+	
+    if(currchar == encl)
+      {
+	in.get(currchar);
+	while(in && currchar != encl)
+	  {
+	    str += currchar;
+	    in.get(currchar);
+	  }
+      }
+    else
+      {
+	in.putback(currchar);
+	in >> str;
+      }
+  }
+	    
+	
+    
+  
+
+
+void DefaultStringErrHandler()
+{
+  cerr << "Error : string operation out of range\n" << flush;
+}
+
+void (*MyStr::ErrHandler)() = DefaultStringErrHandler;
+
+  /*     
+MyStr::MyStr()
+{
+  length = 0;
+  str = shortstr;
+  str[0] = 0;
+}
+  */
+
+MyStr::MyStr(const char *s)
+{
+  length = unsigned(strlen(s));
+
+  if (length > SHORTLEN)
+    str = new char[length + 1];
+  else
+    str = shortstr;
+  strcpy(str, s);
+}
+
+/*
+MyStr::MyStr(char s)
+{
+  length = 1;
+  str = shortstr;
+  str[0] = s;
+  str[1] = (char)0;
+}
+*/
+
+MyStr::MyStr(const MyStr& s)
+{
+  length = s.length;
+  if (length > SHORTLEN)
+    str = new char[length + 1];
+  else
+    str = shortstr;
+  strcpy(str, s.str);
+}
+
+MyStr::MyStr(int i)
+{
+  char buffer[32];
+  sprintf(buffer, "%d", i);
+  length = unsigned(strlen(buffer));
+  if (length > SHORTLEN)
+    str = new char[length + 1];
+  else
+    str = shortstr;
+  strcpy(str, buffer);
+}
+
+MyStr::MyStr(void * p)
+{
+  char buffer[32];
+  sprintf(buffer, "%p", p);
+  length = unsigned(strlen(buffer));
+  if (length > SHORTLEN)
+    str = new char[length + 1];
+  else
+    str = shortstr;
+  strcpy(str, buffer);
+}
+
+
+MyStr::MyStr(long l)
+{
+  char buffer[32];
+  sprintf(buffer, "%ld", l);
+  length = unsigned(strlen(buffer));
+  if (length > SHORTLEN)
+    str = new char[length + 1];
+  else
+    str = shortstr;
+  strcpy(str, buffer);
+}
+
+MyStr::MyStr(double d)
+{
+  char buffer[32];
+  //if (fabs(d) < 1E-100) {d = 0;}
+  sprintf(buffer, "%g", d);
+  length = unsigned(strlen(buffer));
+  if (length > SHORTLEN)
+    str = new char[length + 1];
+  else
+    str = shortstr;
+  strcpy(str, buffer);
+}
+
+MyStr::MyStr(const Point3d& p)
+{
+  char buffer[80];
+  //if (fabs(d) < 1E-100) {d = 0;}
+  sprintf(buffer, "[%g, %g, %g]", p.X(), p.Y(), p.Z());
+  length = unsigned(strlen(buffer));
+  if (length > SHORTLEN)
+    str = new char[length + 1];
+  else
+    str = shortstr;
+  strcpy(str, buffer);
+}
+
+MyStr::MyStr(const Vec3d& p)
+{
+  char buffer[80];
+  //if (fabs(d) < 1E-100) {d = 0;}
+  sprintf(buffer, "[%g, %g, %g]", p.X(), p.Y(), p.Z());
+  length = unsigned(strlen(buffer));
+  if (length > SHORTLEN)
+    str = new char[length + 1];
+  else
+    str = shortstr;
+  strcpy(str, buffer);
+}
+
+MyStr::MyStr(unsigned n, int)
+{
+  length = n;
+  if (length > SHORTLEN)
+    str = new char[length + 1];
+  else
+    str = shortstr;
+  str[n] = 0;
+}
+
+MyStr::MyStr(const string & st)
+{
+  length = unsigned(st.length());
+  if (length > SHORTLEN)
+    str = new char[length + 1];
+  else
+    str = shortstr;
+  strcpy (str, st.c_str());
+}
+
+
+
+MyStr MyStr::Left(unsigned r)
+{
+  if(r > length)
+    {
+      MyStr::ErrHandler();
+      MyStr s;
+      return s;
+    }
+  else
+    {
+      MyStr tmp(r, 0);
+      strncpy(tmp.str, str, r);
+      return tmp;
+    }
+}
+
+MyStr MyStr::Right(unsigned l)
+{
+  if(l > length)
+    {
+      MyStr::ErrHandler();
+      MyStr s;
+      return s;
+    }
+  else
+    {
+      MyStr tmp(l, 0);
+      strncpy(tmp.str, str + length - l, l);
+      return tmp;
+    }
+}
+
+MyStr& MyStr::InsertAt(unsigned pos, const MyStr& s)
+{
+  if(pos > length)
+    {
+      MyStr::ErrHandler();
+      return *this;
+    }
+  int newLength = length + s.length;
+  char *tmp = new char[newLength + 1];
+  strncpy(tmp, str, pos);
+  strcpy(tmp + pos, s.str);
+  strcpy(tmp + pos + s.length, str + pos);
+
+  if (length > SHORTLEN) delete [] str;
+  length = newLength;
+  if (length > SHORTLEN)
+    str = tmp;
+  else
+    {
+      strcpy (shortstr, tmp);
+      delete [] tmp;
+      str = shortstr;
+    }
+  return *this;
+}
+
+MyStr &MyStr::WriteAt(unsigned pos, const MyStr& s)
+{
+  if(pos > length)
+  {
+    MyStr::ErrHandler();
+    return *this;
+  }
+  unsigned n = length - pos;
+  if(s.length < n)
+    n = s.length;
+  strncpy(str + pos, s.str, n);
+  return *this;
+}
+
+void MyStr::ConvertTextToExcel()
+{
+  /*
+  for (int i = 0; i < Length(); i++)
+    {
+      if ((*this)[i]==',') {(*this)[i] = ';';}
+      else if ((*this)[i]=='.') {(*this)[i] = ',';}
+    }
+  */
+}
+
+void MyStr::ConvertExcelToText()
+{
+  /*
+  for (int i = 0; i < Length(); i++)
+    {
+      if ((*this)[i]==',') {(*this)[i] = '.';}
+      else if ((*this)[i]==';') {(*this)[i] = ',';}
+    }
+  */
+}
+
+MyStr& MyStr::operator = (const MyStr& s)
+{
+  if (length > SHORTLEN) delete [] str;
+  length = s.length;
+  if (length > SHORTLEN)
+    str = new char[length + 1];
+  else
+    str = shortstr;
+  strcpy(str, s.str);
+  return *this;
+}
+
+MyStr operator + (const MyStr& s1, const MyStr& s2)
+{
+  MyStr tmp(s1.length + s2.length, 0);
+  if (s1.length != 0) strcpy(tmp.str, s1.str);
+  if (s2.length != 0) strcpy(tmp.str + s1.length, s2.str);
+  return tmp;
+}
+
+void MyStr::operator += (const MyStr& s)
+{
+  if (length+s.length <= SHORTLEN)
+    {
+      if (s.length != 0) strcpy(shortstr + length, s.str);
+    }
+  else
+    {
+      char *tmp = new char[length + s.length + 1];
+      if (length != 0) strcpy(tmp, str);
+      if (s.length != 0) strcpy(tmp + length, s.str);
+      if (length > SHORTLEN) delete [] str;
+      length += s.length;
+      str = tmp;
+    }
+}
+
+char& MyStr::operator [] (unsigned n)
+{
+  static char dummy;
+  if(n < length)
+    return str[n];
+  else
+  {
+    MyStr::ErrHandler();
+    return dummy;
+  }
+}
+
+char MyStr::operator [] (unsigned n) const
+{
+  static char dummy;
+  if(n < length)
+    return str[n];
+  else
+  {
+    MyStr::ErrHandler();
+    return dummy;
+  }
+}
+
+MyStr MyStr::operator () (unsigned l, unsigned r)
+{
+  if((l > r) || (r > length))
+  {
+    MyStr::ErrHandler();
+    MyStr s;
+    return s;
+  }
+  else
+  {
+    int n = r - l + 1;
+    MyStr tmp(n, 0);
+    strncpy(tmp.str, str + 1, n);
+    return tmp;
+  }
+}
+
+string MyStr::cpp_string(void) const
+{
+  string aux(str,length);
+  return aux;
+}
+
+/*
+istream& operator >> (istream& is, MyStr& s)
+{
+  const int buflen = 1000;
+  char buffer[buflen+1];
+
+  int end = 0;
+  s = "";
+  MyStr str;
+
+  while (!end)
+  {
+    is.get(buffer, buflen);
+    str = MyStr(buffer);
+    s += str;
+    if (is.peek() == EOF) {end = 1;}
+  }
+
+  return is;
+}
+*/
+/*
+#ifdef __borland
+::ifstream& operator >> (::ifstream& is, MyStr& s)       // wb
+{                                                        // wb
+  const int buflen = 1000;                               // wb
+  char buffer[buflen+1];                                 // wb
+                                                         // wb
+  int end = 0;                                           // wb
+  s = "";                                                // wb
+  MyStr str;                                             // wb
+                                                         // wb
+  while (!end)                                           // wb
+  {                                                      // wb
+    is.get(buffer, buflen);                              // wb
+    str = MyStr(buffer);                                 // wb
+    s += str;                                            // wb
+    if (is.peek() == EOF) {end = 1;}                     // wb
+  }                                                      // wb
+                                                         // wb
+  return is;                                             // wb
+}          
+
+#endif
+*/
+}
diff --git a/contrib/Netgen/libsrc/general/mystring.hpp b/contrib/Netgen/libsrc/general/mystring.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..434ba9a3cb8b06d7f72b1332572cfd8d00df7ee7
--- /dev/null
+++ b/contrib/Netgen/libsrc/general/mystring.hpp
@@ -0,0 +1,216 @@
+
+//**************************************************************
+//
+// filename:             mystring.h
+//
+// project:              doctoral thesis, program smart
+//
+// autor:                Dipl.-Ing. Gerstmayr Johannes
+//
+// generated:            20.12.98
+// last change:          20.12.98
+// description:          base class for strings
+// remarks:              string with n characters has
+//                       0..n-1 characters and at pos n a 0
+//
+//**************************************************************
+
+
+#ifndef MYSTRING__H
+#define MYSTRING__H
+
+class Point3d;
+class Vec3d;
+
+
+// extract string str which is enclosed by the given character encl from a given string in
+void ReadEnclString(istream & in, string & str, const char encl);
+
+
+class MyStr;
+
+MyStr operator + (const MyStr &, const MyStr &);
+int operator == (const MyStr &, const MyStr &);
+int operator < (const MyStr &, const MyStr &);
+int operator <= (const MyStr &, const MyStr &);
+int operator > (const MyStr &, const MyStr &);
+int operator >= (const MyStr &, const MyStr &);
+int operator != (const MyStr &, const MyStr &);
+ostream& operator << (ostream &, const MyStr &);
+istream& operator >> (istream &, MyStr &);
+
+class MyStr
+{
+public:
+  MyStr();
+  MyStr(const char *);
+  MyStr(char);
+  MyStr(const MyStr &);
+  MyStr(int);
+  MyStr(void *);
+  MyStr(long);
+  MyStr(double);
+  MyStr(const Point3d& p);
+  MyStr(const Vec3d& p);
+  MyStr(const string & st);
+
+  ~MyStr();
+  MyStr Left(unsigned);
+  MyStr Right(unsigned);
+  MyStr& InsertAt(unsigned, const MyStr &);
+  MyStr& WriteAt(unsigned, const MyStr &);
+  unsigned Length() const;
+  int Find(const char);
+  int Find(const char *);
+  int Find(const MyStr &);
+  MyStr& operator = (const MyStr &);
+  friend MyStr operator + (const MyStr &, const MyStr &);
+  void operator += (const MyStr &);
+  char* c_str();
+  string cpp_string(void) const;
+
+  //change every ',' -> ';', '.' -> ','
+  void ConvertTextToExcel();
+  //change every ','->'.', ';'->','
+  void ConvertExcelToText();
+
+  MyStr operator () (unsigned, unsigned);
+  operator int();
+  operator double();
+  operator long();
+  operator char *();
+  char& operator [] (unsigned int);
+  char operator [] (unsigned int) const;
+
+  friend int operator == (const MyStr &, const MyStr &);
+  friend int operator < (const MyStr &, const MyStr &);
+  friend int operator <= (const MyStr &, const MyStr &);
+  friend int operator > (const MyStr &, const MyStr &);
+  friend int operator >= (const MyStr &, const MyStr &);
+  friend int operator != (const MyStr &, const MyStr &);
+  friend ostream& operator << (ostream &, const MyStr &);
+  friend istream& operator >> (istream &, MyStr &);
+  static void SetToErrHandler(void (*)());
+private:
+  MyStr(unsigned, int);
+  char *str;
+  unsigned length;
+  enum { SHORTLEN = 24 };
+  char shortstr[SHORTLEN+1];
+  static void(*ErrHandler)();
+};
+
+
+inline MyStr::MyStr()
+{
+  length = 0;
+  str = shortstr;
+  str[0] = 0;
+}
+
+inline MyStr::MyStr(char s)
+{
+  length = 1;
+  str = shortstr;
+  str[0] = s;
+  str[1] = (char)0;
+}
+
+inline MyStr::~MyStr()
+{
+  if (length > SHORTLEN)
+    delete [] str;
+}
+
+inline unsigned MyStr::Length() const
+{
+  return length;
+}
+
+inline int MyStr::Find(const char c)
+{
+  char *pos = strchr(str, int(c));
+  return pos ? int(pos - str) : -1;
+}
+
+inline int MyStr::Find(const MyStr &s)
+{
+  char *pos = strstr(str, s.str);
+  return pos ? int(pos - str) : -1;
+}
+
+inline int MyStr::Find(const char *s)
+{
+  char *pos = strstr(str, s);
+  return pos ? int(pos - str) : -1;
+}
+
+inline MyStr::operator int()
+{
+  return atoi(str);
+}
+
+inline MyStr::operator double()
+{
+  return atof(str);
+}
+
+inline MyStr::operator long()
+{
+  return atol(str);
+}
+
+inline MyStr::operator char *()
+{
+  return str;
+}
+
+inline char* MyStr::c_str()
+{
+  return str;
+}
+
+
+inline int operator == (const MyStr &s1, const MyStr& s2)
+{
+  return strcmp(s1.str, s2.str) == 0;
+}
+
+inline int operator < (const MyStr &s1, const MyStr& s2)
+{
+  return strcmp(s1.str, s2.str) < 0;
+}
+
+inline int operator <= (const MyStr &s1, const MyStr& s2)
+{
+  return strcmp(s1.str, s2.str) <= 0;
+}
+
+inline int operator > (const MyStr &s1, const MyStr& s2)
+{
+  return strcmp(s1.str, s2.str) > 0;
+}
+
+inline int operator >= (const MyStr &s1, const MyStr& s2)
+{
+  return strcmp(s1.str, s2.str) >= 0;
+}
+
+inline int operator != (const MyStr &s1, const MyStr& s2)
+{
+  return !(s1 == s2);
+}
+
+inline ostream& operator << (ostream& os, const MyStr& s)
+{
+  return os << s.str;
+}
+
+inline void MyStr::SetToErrHandler(void (*Handler)())
+{
+  ErrHandler = Handler;
+};
+
+#endif
+
+   
diff --git a/contrib/Netgen/libsrc/general/netgenout.hpp b/contrib/Netgen/libsrc/general/netgenout.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..2338445ad068ff10b1fbb648be05f86aead265b9
--- /dev/null
+++ b/contrib/Netgen/libsrc/general/netgenout.hpp
@@ -0,0 +1,184 @@
+#ifndef NETGEN_OUT_STREAM_HPP__
+#define NETGEN_OUT_STREAM_HPP__
+
+// #include <ostream>
+// #include <mystdlib.h>
+// #include <meshing.hpp>
+
+#ifdef PARALLEL
+extern int id;
+extern int ntasks;
+#endif
+extern int printmessage_importance;
+
+
+
+class Imp
+{
+  int importance;
+public:
+  Imp () : importance(0) { ; }
+
+  Imp ( int aimportance ) : importance(aimportance) { ; }
+
+  int GetImp () const { return importance; }
+};
+
+
+class Proc
+{
+  int proc;
+public:
+  Proc () : proc(0) { ; }
+
+  Proc ( int aproc ) : proc(aproc) { ; }
+
+  int GetProc () const { return proc; }
+};
+
+class Procs
+{
+  const netgen::FlatArray<int> procs;
+
+public:
+
+  Procs ( const netgen::FlatArray<int> & aprocs ) : procs (aprocs) { ; }
+
+  const netgen::FlatArray<int> & GetProcs () const { return procs; }
+};
+
+
+
+class NetgenOutStream
+{
+  ostream * out;
+
+  bool print;
+  bool printheader;
+
+
+public:
+  NetgenOutStream() :
+    out(&std::cout),
+    print(1),
+    printheader(1)
+  {
+    ;
+  }  
+
+  NetgenOutStream(ostream * aout, Imp imp ) :
+    out(aout),
+    printheader(1)
+  { 
+    if ( netgen::printmessage_importance >= imp.GetImp() )
+      print = true;
+    else
+      print = false;
+  }
+
+  NetgenOutStream(ostream * aout, Proc proc ) :
+    out(aout),
+    printheader(1)
+  { 
+#ifdef PARALLEL
+    if ( netgen::id == proc.GetProc() )
+      print = true;
+    else
+      print = false;
+#else
+    if ( 0 == proc.GetProc() )
+      print = true;
+    else
+      print = false;
+
+#endif
+  }
+
+  NetgenOutStream(ostream * aout, Procs & procs ) :
+    out(aout),
+    printheader(1)
+  { 
+#ifdef PARALLEL
+    if ( procs.GetProcs().Contains(netgen::id) )
+      print = true;
+    else
+      print = false;
+#else
+    if ( procs.GetProcs().Contains(0) )
+      print = true;
+    else
+      print = false;
+
+#endif
+  }
+
+  ostream & OStream ()
+  {
+    return *out;
+  }
+
+  template <typename T>
+  NetgenOutStream & operator<< (T & var)
+  {
+    if ( print )
+      {
+#ifdef PARALLEL
+	if ( printheader )
+	  {
+	    *out << "proc " << netgen::id << ": ";
+	    printheader = false;
+	  }
+#endif
+	*out << var;
+      }
+    return (*this); 
+  }
+
+  NetgenOutStream& operator<< (ostream& ( *pf )(ostream&))
+  {
+    if ( print )
+      *out << (*pf) ;
+
+    return (*this);
+  }
+
+  NetgenOutStream& operator<< (ios& ( *pf )(ios&))
+  {
+    if ( print)
+      *out << (*pf) ;
+
+    printheader = 1;
+
+    return (*this);
+  }
+
+  NetgenOutStream& operator<< (ios_base& ( *pf )(ios_base&))
+  {
+    if (print )
+      *out << (*pf) ;
+    return (*this);
+  }
+
+
+};
+
+
+NetgenOutStream operator<< ( ostream & ost, Imp  imp );
+NetgenOutStream operator<< ( ostream & ost, Proc proc );
+NetgenOutStream operator<< ( ostream & ost, Procs & procs );
+// {
+//   return ( NetgenOutStream ( &ost, imp.GetImp() ) );
+// }
+
+// template <typename T>
+// NetgenOutStream& operator<< (NetgenOutStream& out, T c )
+// {
+//   out.OStream() << c << endl;
+//   return out;
+// }
+
+
+
+
+
+#endif
diff --git a/contrib/Netgen/libsrc/general/ngexception.cpp b/contrib/Netgen/libsrc/general/ngexception.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..2496f6b3be3b2b410727d4cd04234a3015d10df0
--- /dev/null
+++ b/contrib/Netgen/libsrc/general/ngexception.cpp
@@ -0,0 +1,33 @@
+/**************************************************************************/
+/* File:   ngexception.cpp                                                */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   16. Jan. 02                                                    */
+/**************************************************************************/
+
+#include <myadt.hpp>
+
+namespace netgen
+{
+  //using namespace netgen;
+
+
+
+  NgException :: NgException (const string & s) 
+    : what(s)
+  {
+    ; 
+  }
+
+
+  NgException :: ~NgException () 
+  {
+    ;
+  }
+
+  /// append string to description
+  void NgException :: Append (const string & s)
+  { 
+    what += s; 
+  }
+
+}
diff --git a/contrib/Netgen/libsrc/general/ngexception.hpp b/contrib/Netgen/libsrc/general/ngexception.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..56c561aa8cdd14eb038d9e728d114140cdbfb304
--- /dev/null
+++ b/contrib/Netgen/libsrc/general/ngexception.hpp
@@ -0,0 +1,30 @@
+#ifndef FILE_NGEXCEPTION
+#define FILE_NGEXCEPTION
+
+/**************************************************************************/
+/* File:   ngexception.hpp                                                */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   16. Jan. 2002                                                  */
+/**************************************************************************/
+
+
+/// Base class for all ng exceptions
+class NgException 
+{
+  /// verbal description of exception
+  string what;
+public:
+  ///
+  NgException (const string & s);
+  ///
+  virtual ~NgException ();
+
+  /// append string to description
+  void Append (const string & s);
+  //  void Append (const char * s);
+  
+  /// verbal description of exception
+  const string & What() const { return what; }
+};
+
+#endif
diff --git a/contrib/Netgen/libsrc/general/optmem.cpp b/contrib/Netgen/libsrc/general/optmem.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..d3f939ac1ae4453536490016806c929611d7590f
--- /dev/null
+++ b/contrib/Netgen/libsrc/general/optmem.cpp
@@ -0,0 +1,64 @@
+/**************************************************************************/
+/* File:   optmem.cc                                                      */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   04. Apr. 97                                                    */
+/**************************************************************************/
+
+/* 
+   Abstract data type ARRAY
+*/
+
+
+#include <mystdlib.h>
+#include <myadt.hpp>
+
+namespace netgen
+{
+  //using namespace netgen;
+
+  BlockAllocator :: BlockAllocator (unsigned asize, unsigned ablocks)
+    : bablocks (0)
+  {
+    if (asize < sizeof(void*))
+      asize = sizeof(void*);
+    size = asize;
+    blocks = ablocks;
+    freelist = NULL;
+  }
+
+  BlockAllocator :: ~BlockAllocator ()
+  {
+    //for (unsigned i = 0; i < bablocks.Size(); i++)
+    for (int i = 0; i < bablocks.Size(); i++)
+      delete [] bablocks[i];
+  }
+
+  void * BlockAllocator :: Alloc ()
+  {
+    //  return new char[size];
+    if (!freelist)
+      {
+	// cout << "freelist = " << freelist << endl;
+	// cout << "BlockAlloc: " << size*blocks << endl;
+	char * hcp = new char [size * blocks];
+	bablocks.Append (hcp);
+	bablocks.Last() = hcp;
+	for (unsigned i = 0; i < blocks-1; i++)
+	  *(void**)&(hcp[i * size]) = &(hcp[ (i+1) * size]);
+	*(void**)&(hcp[(blocks-1)*size]) = NULL;
+	freelist = hcp;
+      }
+
+    void * p = freelist;
+    freelist = *(void**)freelist;
+    return p;
+  }
+
+  /*
+  void BlockAllocator :: Free (void * p)
+  {
+    *(void**)p = freelist;
+    freelist = p;
+  }
+  */
+}
diff --git a/contrib/Netgen/libsrc/general/optmem.hpp b/contrib/Netgen/libsrc/general/optmem.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..0015b20b783efb4f199df420efb9d4dab144447a
--- /dev/null
+++ b/contrib/Netgen/libsrc/general/optmem.hpp
@@ -0,0 +1,59 @@
+#ifndef FILE_OPTMEM
+#define FILE_OPTMEM
+
+/**************************************************************************/
+/* File:   optmem.hh                                                      */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   04. Apr. 97                                                    */
+/**************************************************************************/
+
+/** 
+    Optimized Memory allocation classes
+*/
+
+class BlockAllocator
+{
+private:
+  ///
+  unsigned size, blocks;
+  ///
+  void * freelist;
+  ///
+  ARRAY<char*> bablocks;
+public:
+  ///
+  BlockAllocator (unsigned asize, unsigned ablocks = 100);
+  ///
+  ~BlockAllocator ();
+  ///
+
+  void * Alloc ();
+  /*
+  {
+    if (!freelist)
+      Alloc2();
+
+    void * p = freelist;
+    // freelist = *(void**)freelist;
+    freelist = *static_cast<void**> (freelist);
+
+    return p;
+  }
+  */
+
+
+  ///
+  void Free (void * p)
+  {
+    *(void**)p = freelist;
+    freelist = p;
+  }
+  
+
+private:
+  //  void Alloc2 ();
+};
+
+
+
+#endif
diff --git a/contrib/Netgen/libsrc/general/parthreads.cpp b/contrib/Netgen/libsrc/general/parthreads.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..81e9d0b6cce14da76c8e1cb196666a9fab2c3fc1
--- /dev/null
+++ b/contrib/Netgen/libsrc/general/parthreads.cpp
@@ -0,0 +1,40 @@
+/**************************************************************************/
+/* File:   parthreads.cpp                                                 */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   01. Jun. 95                                                    */
+/**************************************************************************/
+
+
+#include <mystdlib.h>
+#include <myadt.hpp>
+
+/*
+
+namespace netgen
+{
+  using namespace netgen;
+
+#ifdef WIN32
+
+  NgLock :: NgLock (NgMutex & mut)
+    : sl(&mut.cs)
+  {
+    ;
+  }
+
+  void NgLock :: Lock ()
+  {
+    sl.Lock();
+  }
+  void NgLock :: UnLock ()
+  {
+    sl.Unlock();
+  }
+
+
+#else
+
+#endif
+}
+
+*/
diff --git a/contrib/Netgen/libsrc/general/parthreads.hpp b/contrib/Netgen/libsrc/general/parthreads.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..a00ff9e287caec8361d94da6a9193a6de8e576b0
--- /dev/null
+++ b/contrib/Netgen/libsrc/general/parthreads.hpp
@@ -0,0 +1,129 @@
+#ifndef FILE_PARTHREADS
+#define FILE_PARTHREADS
+
+/**************************************************************************/
+/* File:   parthreads.hh                                                  */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   22. Nov. 2000                                                  */
+/**************************************************************************/
+
+/*
+  Parallel thread, Mutex,
+*/
+
+#ifdef NO_PARALLEL_THREADS
+
+class NgMutex { };
+
+class NgLock
+{
+public:
+  NgLock (NgMutex & mut, bool lock = 0) { ; }
+  void Lock () { ; }
+  void UnLock () { ; }
+};
+
+
+#else
+
+#ifdef _MSC_VER
+
+class NgMutex
+{
+  CCriticalSection cs;
+
+public:
+  NgMutex ()
+  { ; }
+  friend class NgLock;
+};
+
+class NgLock
+{
+  CSingleLock sl;
+  bool locked;
+public:
+  NgLock (NgMutex & mut, bool lock = 0)
+    : sl(&mut.cs)
+  {
+    if (lock) sl.Lock();
+    locked = lock;
+  }
+
+  ~NgLock ()
+  {
+    if (locked) sl.Unlock();
+  }
+
+  void Lock ()
+  {
+    sl.Lock();
+    locked = 1;
+  }
+
+  void UnLock ()
+  {
+    sl.Unlock();
+    locked = 0;
+  }
+};
+
+#else
+
+
+// #include <pthread.h>
+
+class NgMutex
+{
+  pthread_mutex_t mut;
+public:
+  NgMutex ()
+  {
+    pthread_mutex_init (&mut, NULL);
+   }
+  friend class NgLock;
+};
+
+class NgLock
+{
+  pthread_mutex_t & mut;
+  bool locked;
+public:
+  NgLock (NgMutex & ngmut, bool lock = false)
+    : mut (ngmut.mut)
+  {
+    if (lock)
+      pthread_mutex_lock (&mut);
+
+    locked = lock;
+  };
+
+  ~NgLock()
+  {
+    if (locked)
+      pthread_mutex_unlock (&mut);
+  }
+
+  void Lock ()
+  {
+    pthread_mutex_lock (&mut);
+    locked = true;
+  }
+  void UnLock ()
+  {
+    pthread_mutex_unlock (&mut);
+    locked = false;
+  }
+  /*
+  int TryLock ()
+  {
+    return pthread_mutex_trylock (&mut);
+  }
+  */
+};
+
+#endif
+
+#endif
+
+#endif
diff --git a/contrib/Netgen/libsrc/general/profiler.cpp b/contrib/Netgen/libsrc/general/profiler.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..4d61a7056bcb45bfb6edc549cab8a7cfc23c29fa
--- /dev/null
+++ b/contrib/Netgen/libsrc/general/profiler.cpp
@@ -0,0 +1,112 @@
+/**************************************************************************/
+/* File:   profiler.cpp                                                   */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   19. Apr. 2002                                                  */
+/**************************************************************************/
+
+
+#include <myadt.hpp>
+
+namespace netgen
+{
+  //using namespace netgen;
+
+  long int NgProfiler::tottimes[SIZE];
+  long int NgProfiler::starttimes[SIZE];
+  long int NgProfiler::counts[SIZE];
+  string NgProfiler::names[SIZE];
+  int NgProfiler::usedcounter[SIZE];
+  
+
+  NgProfiler :: NgProfiler()
+  {
+    for (int i = 0; i < SIZE; i++)
+      {
+	tottimes[i] = 0;
+	usedcounter[i] = 0;
+      }
+
+    total_timer = CreateTimer ("total CPU time");
+    StartTimer (total_timer);
+  }
+
+  NgProfiler :: ~NgProfiler()
+  {
+    StopTimer (total_timer);
+
+    //ofstream prof;
+    //prof.open("ng.prof");
+
+    // ofstream-constructor may be called after STL-stuff is destructed,
+    // which leads to an "order of destruction"-problem,
+    // thus we use the C-variant:
+
+    char filename[100];
+#ifdef PARALLEL
+    sprintf (filename, "netgen.prof.%d", id);
+#else
+    sprintf (filename, "netgen.prof");
+#endif
+
+    FILE *prof = fopen(filename,"w");
+    Print (prof);
+    fclose(prof);
+  }
+
+
+//   void NgProfiler :: Print (ostream & prof)
+//   {
+//     for (int i = 0; i < SIZE; i++)
+//       if (counts[i] != 0 || usedcounter[i] != 0)
+// 	{
+// 	  prof.setf (ios::fixed, ios::floatfield);
+// 	  prof.setf (ios::showpoint);
+
+// 	  prof // << "job " << setw(3) << i 
+// 	    << "calls " << setw(8) << counts[i] 
+// 	    << ", time " << setprecision(2) << setw(6) << double(tottimes[i]) / CLOCKS_PER_SEC << " sec";
+
+// 	  if (usedcounter[i]) 
+// 	    prof << " " << names[i];
+// 	  else
+// 	    prof << " " << i;
+	    
+// 	  prof << endl;
+// 	}
+//   }
+
+
+  void NgProfiler :: Print (FILE * prof)
+  {
+    for (int i = 0; i < SIZE; i++)
+      if (counts[i] != 0 || usedcounter[i] != 0)
+	{
+	  //fprintf(prof,"job %3i calls %8i, time %6.2f sec",i,counts[i],double(tottimes[i]) / CLOCKS_PER_SEC);
+	  fprintf(prof,"calls %8i, time %6.2f sec",counts[i],double(tottimes[i]) / CLOCKS_PER_SEC);
+	  if(usedcounter[i])
+	    fprintf(prof," %s",names[i].c_str());
+	  else
+	    fprintf(prof," %i",i);
+	  fprintf(prof,"\n");
+	}
+  }
+
+  int NgProfiler :: CreateTimer (const string & name)
+  {
+    for (int i = SIZE-1; i > 0; i--)
+      if(names[i] == name)
+	return i;
+
+    for (int i = SIZE-1; i > 0; i--)
+      if (!usedcounter[i])
+	{
+	  usedcounter[i] = 1;
+	  names[i] = name;
+	  return i;
+	}
+    return -1;
+  }
+
+
+  NgProfiler prof;
+}
diff --git a/contrib/Netgen/libsrc/general/profiler.hpp b/contrib/Netgen/libsrc/general/profiler.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..b08708be83a056e6284e67c650b6373f708513b8
--- /dev/null
+++ b/contrib/Netgen/libsrc/general/profiler.hpp
@@ -0,0 +1,62 @@
+#ifndef FILE_NG_PROFILER
+#define FILE_NG_PROFILER
+
+/**************************************************************************/
+/* File:   profiler.hpp                                                   */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   5. Jan. 2005                                                  */
+/**************************************************************************/
+
+
+
+#ifdef VTRACE
+#include "vt_user.h"
+#else
+  #define VT_USER_START(n)
+  #define VT_USER_END(n)
+  #define VT_TRACER(n)
+#endif
+
+
+
+class NgProfiler
+{
+  enum { SIZE = 1000 };
+
+  static long int tottimes[SIZE];
+  static long int starttimes[SIZE];
+  static long int counts[SIZE];
+  static string names[SIZE];
+  static int usedcounter[SIZE];
+
+  int total_timer;
+public: 
+  NgProfiler();
+  ~NgProfiler();
+  static int CreateTimer (const string & name);
+
+  static void StartTimer (int nr) 
+  { 
+    starttimes[nr] = clock(); counts[nr]++; 
+    VT_USER_START (const_cast<char*> (names[nr].c_str())); 
+  }
+  static void StopTimer (int nr) 
+  { 
+    tottimes[nr] += clock()-starttimes[nr]; 
+    VT_USER_END (const_cast<char*> (names[nr].c_str())); 
+  }
+
+  //static void Print (ostream & ost);
+  static void Print (FILE * prof);
+
+  class RegionTimer
+  {
+    int nr;
+  public:
+    RegionTimer (int anr) : nr(anr)
+      { StartTimer (nr); }
+    ~RegionTimer () { StopTimer (nr); }
+  };
+};
+
+#endif
diff --git a/contrib/Netgen/libsrc/general/seti.cpp b/contrib/Netgen/libsrc/general/seti.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..e7f5b2ea74b1ee42c2f1299fd0a3a5b908eb1852
--- /dev/null
+++ b/contrib/Netgen/libsrc/general/seti.cpp
@@ -0,0 +1,70 @@
+#include <mystdlib.h>
+#include <myadt.hpp>
+
+
+namespace netgen
+{
+  //using namespace netgen;
+
+  IndexSet :: IndexSet (int maxind)
+  {
+    SetMaxIndex (maxind);
+  }
+
+  IndexSet :: ~IndexSet ()
+  {
+    Clear();
+  }
+
+
+  void IndexSet :: SetMaxIndex (int maxind)
+  {
+    if (maxind > flags.Size())
+      {
+	flags.SetSize (2 * maxind);
+	flags.Clear();
+      }
+  }
+
+  /*
+    int IndexSet :: IsIn (int ind) const
+    {
+    return flags.Test (ind);
+    }
+  */
+
+  /*
+    void IndexSet :: Add (int ind)
+    {
+    if (ind > flags.Size())
+    {
+    cerr << "out of range" << endl;
+    exit (1);
+    }
+
+    if (!flags.Test(ind))
+    {
+    set.Append (ind);
+    flags.Set (ind);
+    }
+    }
+  */
+
+  void IndexSet :: Del (int ind)
+  {
+    for (int i = 1; i <= set.Size(); i++)
+      if (set.Get(i) == ind)
+	{
+	  set.DeleteElement (ind);
+	  break;
+	}
+    flags.Clear (ind);
+  }
+
+  void IndexSet :: Clear ()
+  {
+    for (int i = 1; i <= set.Size(); i++)
+      flags.Clear (set.Get(i));
+    set.SetSize (0);
+  }
+}
diff --git a/contrib/Netgen/libsrc/general/seti.hpp b/contrib/Netgen/libsrc/general/seti.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..4ca0b8eb4ef2e25fec2e9c4a27bd5cd6731cf4a2
--- /dev/null
+++ b/contrib/Netgen/libsrc/general/seti.hpp
@@ -0,0 +1,45 @@
+#ifndef FILE_SETI
+#define FILE_SETI
+
+
+/**************************************************************************/
+/* File:   seti.hh                                                        */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   20. Mar. 98                                                    */
+/**************************************************************************/
+
+/**
+  Set of Integers
+  */
+class IndexSet
+{
+  ARRAY<int> set;
+  BitArray flags;
+public:
+  IndexSet (int maxind);
+  
+  ~IndexSet ();
+  /// increase range to maxind
+  void SetMaxIndex (int maxind);
+  int IsIn (int ind) const
+  { 
+    return flags.Test (ind); 
+  }
+
+  void Add (int ind)
+  {
+    if (!flags.Test(ind))
+      {
+	set.Append (ind);
+	flags.Set (ind);
+      }
+  }
+
+  void Del (int ind);
+  void Clear ();
+  
+  const ARRAY<int> & Array() { return set; }
+};
+
+#endif
+
diff --git a/contrib/Netgen/libsrc/general/sort.cpp b/contrib/Netgen/libsrc/general/sort.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..264a132a748c4cd4be406ffa1d85b5f75ad0f1b7
--- /dev/null
+++ b/contrib/Netgen/libsrc/general/sort.cpp
@@ -0,0 +1,75 @@
+/**************************************************************************/
+/* File:   sort.cc                                                        */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   07. Jan. 00                                                    */
+/**************************************************************************/
+
+/* 
+   Sorting
+*/
+
+
+#include <algorithm>
+#include <mystdlib.h>
+#include <myadt.hpp>
+
+namespace netgen
+{
+
+void Sort (const ARRAY<double> & values,
+	   ARRAY<int> & order)
+{
+  int n = values.Size();
+  int i, j;
+
+  order.SetSize (n);
+
+  for (i = 1; i <= n; i++)
+    order.Elem(i) = i;
+  for (i = 1; i <= n-1; i++)
+    for (j = 1; j <= n-1; j++)
+      if (values.Get(order.Elem(j)) > values.Get(order.Elem(j+1)))
+	{
+	  Swap (order.Elem(j), order.Elem(j+1));
+	}
+}
+
+
+void QickSortRec (const ARRAY<double> & values,
+		  ARRAY<int> & order, 
+		  int left, int right)
+{
+  int i, j;
+  double midval;
+
+  i = left;
+  j = right;
+  midval = values.Get(order.Get((i+j)/2));
+  
+  do
+    {
+      while (values.Get(order.Get(i)) < midval) i++;
+      while (midval < values.Get(order.Get(j))) j--;
+      
+      if (i <= j)
+	{
+	  Swap (order.Elem(i), order.Elem(j));
+	  i++; j--;
+	}
+    }
+  while (i <= j);
+  if (left < j) QickSortRec (values, order, left, j);
+  if (i < right) QickSortRec (values, order, i, right);
+}
+
+void QickSort (const ARRAY<double> & values,
+	       ARRAY<int> & order)
+{
+  int i, n = values.Size();
+  order.SetSize (n);
+  for (i = 1; i <= n; i++)
+    order.Elem(i) = i;
+
+  QickSortRec (values, order, 1, order.Size());
+}
+}
diff --git a/contrib/Netgen/libsrc/general/sort.hpp b/contrib/Netgen/libsrc/general/sort.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..f65aa24fce073cadeab371ce71d3d4aa3b658ea9
--- /dev/null
+++ b/contrib/Netgen/libsrc/general/sort.hpp
@@ -0,0 +1,42 @@
+#ifndef FILE_SORT
+#define FILE_SORT
+
+/**************************************************************************/
+/* File:   sort.hh                                                        */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   07. Jan. 00                                                    */
+/**************************************************************************/
+
+
+// order(i) is sorted index of element i
+extern void Sort (const ARRAY<double> & values,
+		  ARRAY<int> & order);
+
+extern void QickSort (const ARRAY<double> & values,
+		      ARRAY<int> & order);
+
+
+
+
+template <class T>
+inline void BubbleSort (int size, T * data)
+{
+  T hv;
+  for (int i = 0; i < size; i++)
+    for (int j = i+1; j < size; j++)
+      if (data[i] > data[j])
+	{
+	  hv = data[i];
+	  data[i] = data[j];
+	  data[j] = hv;
+	}
+}
+
+template <class T>
+inline void BubbleSort (ARRAY<T> & data)
+{
+  if(data.Size() > 0)
+	  BubbleSort (data.Size(), &data[data.Begin()]);
+}
+
+#endif
diff --git a/contrib/Netgen/libsrc/general/spbita2d.cpp b/contrib/Netgen/libsrc/general/spbita2d.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..5badfe9a7c99b21254b7310024c4b92627f344f4
--- /dev/null
+++ b/contrib/Netgen/libsrc/general/spbita2d.cpp
@@ -0,0 +1,172 @@
+/**************************************************************************/
+/* File:   spbita2d.cpp                                                   */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   01. Jun. 95                                                    */
+/**************************************************************************/
+
+/* 
+   Implementation of sparse 2 dimensional bitarray
+*/
+
+
+#include <mystdlib.h>
+#include <myadt.hpp>
+
+namespace netgen
+{
+  //using namespace netgen;
+
+  SPARSE_BIT_ARRAY_2D :: SPARSE_BIT_ARRAY_2D (int ah, int aw)
+  {
+    lines = NULL;
+    SetSize (ah, aw);
+  }
+
+  SPARSE_BIT_ARRAY_2D :: ~SPARSE_BIT_ARRAY_2D ()
+  {
+    DeleteElements ();
+    delete lines;
+  }
+
+
+  void SPARSE_BIT_ARRAY_2D :: SetSize (int ah, int aw)
+  {
+    DeleteElements();
+    if (lines)
+      {
+	delete lines;
+	lines = NULL;
+      }
+
+    if (!aw) aw = ah;
+
+    height = ah;
+    width = aw;
+
+    if (!ah) return;
+    lines = new linestruct[ah];
+
+    if (lines)
+      {
+	for (int i = 0; i < ah; i++)
+	  {
+	    lines[i].size = 0;
+	    lines[i].maxsize = 0;
+	    lines[i].col = NULL;
+	  }
+      }
+    else
+      {
+	height = width = 0;
+	MyError ("SPARSE_ARRAY::SetSize: Out of memory");
+      }
+  }
+
+
+
+  void SPARSE_BIT_ARRAY_2D :: DeleteElements ()
+  {
+    if (lines)
+      {
+	for (int i = 0; i < height; i++)
+	  {
+	    if (lines[i].col)
+	      {
+		delete [] lines[i].col;
+		lines[i].col = NULL;
+		lines[i].size = 0;
+		lines[i].maxsize = 0;
+	      }
+	  }
+      }
+  }
+
+
+  int SPARSE_BIT_ARRAY_2D :: Test (int i, int j) const
+  {
+    int k, max, *col;
+
+    if (!lines) return 0;
+    if (i < 1 || i > height) return 0;
+
+    col = lines[i-1].col;
+    max = lines[i-1].size;
+
+    for (k = 0; k < max; k++, col++)
+      if (*col == j) return 1;
+
+    return 0;
+  }
+
+
+
+  void SPARSE_BIT_ARRAY_2D :: Set(int i, int j)
+  {
+    int k, max, *col;
+
+    i--;
+    col = lines[i].col;
+    max = lines[i].size;
+
+    for (k = 0; k < max; k++, col++)
+      if (*col == j)
+	return;
+
+    if (lines[i].size)
+      {
+	if (lines[i].size == lines[i].maxsize)
+	  {
+	    col = new int[lines[i].maxsize+2];
+	    if (col)
+	      {
+		lines[i].maxsize += 2;
+		memcpy (col, lines[i].col, sizeof (int) * lines[i].size);
+		delete [] lines[i].col;
+		lines[i].col = col;
+	      }
+	    else
+	      {
+		MyError ("SPARSE_BIT_ARRAY::Set: Out of mem 1");
+		return;
+	      }
+	  }
+	else
+	  col = lines[i].col;
+
+	if (col)
+	  {
+	    k = lines[i].size-1;
+	    while (k >= 0 && col[k] > j)
+	      {
+		col[k+1] = col[k];
+		k--;
+	      }
+
+	    k++;
+	    lines[i].size++;
+	    col[k] = j;
+	    return;
+	  }
+	else
+	  {
+	    MyError ("SPARSE_ARRAY::Set: Out of memory 2");
+	  }
+      }
+    else
+      {
+	lines[i].col = new int[4];
+	if (lines[i].col)
+	  {
+	    lines[i].maxsize = 4;
+	    lines[i].size = 1;
+	    lines[i].col[0] = j;
+	    return;
+	  }
+	else
+	  {
+	    MyError ("SparseMatrix::Elem: Out of memory 3");
+	  }
+      }
+  }
+
+}
diff --git a/contrib/Netgen/libsrc/general/spbita2d.hpp b/contrib/Netgen/libsrc/general/spbita2d.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..db656653b1799e747be24cc50d8ac3352f5b1381
--- /dev/null
+++ b/contrib/Netgen/libsrc/general/spbita2d.hpp
@@ -0,0 +1,56 @@
+#ifndef FILE_SPBITA2D
+#define FILE_SPBITA2D
+
+/**************************************************************************/
+/* File:   spbita2d.hh                                                    */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   01. Jun. 95                                                    */
+/**************************************************************************/
+
+/** 
+   Implementation of sparse 2 dimensional bitarray
+*/
+
+
+class SPARSE_BIT_ARRAY_2D
+  {
+  class linestruct { public: INDEX size; INDEX maxsize; INDEX * col; };
+
+  ///
+  linestruct * lines;
+  ///
+  INDEX height, width;
+
+  public:
+
+  ///
+  SPARSE_BIT_ARRAY_2D (INDEX ah = 0, INDEX aw = 0);
+  ///
+  ~SPARSE_BIT_ARRAY_2D ();
+
+  ///
+  void SetSize (INDEX ah, INDEX aw = 0);
+  ///
+  void DeleteElements ();
+
+  ///
+  int Get (INDEX i, INDEX j) const;
+
+  ///
+  INDEX Height () const { return height; }
+  ///
+  INDEX Width () const { return width; }
+
+  ///
+  void Set (INDEX i, INDEX j);
+  ///
+  int Test (INDEX i, INDEX j) const;
+
+  ///
+  INDEX BitsInLine (INDEX i) const { return lines[i-1].size; }
+  ///
+  INDEX GetIndex (INDEX i, INDEX nr) const { return lines[i-1].col[nr-1]; }
+  };
+
+
+#endif
diff --git a/contrib/Netgen/libsrc/general/stack.hpp b/contrib/Netgen/libsrc/general/stack.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..db8dfad2666817a7694a0edfcceafdf3fdd68f1b
--- /dev/null
+++ b/contrib/Netgen/libsrc/general/stack.hpp
@@ -0,0 +1,112 @@
+#ifndef FILE_STACK
+#define FILE_STACK
+
+/*****************************************************************************/
+/*  File: stack.hh                                                           */
+/*  Author: Wolfram Muehlhuber                                               */
+/*  Date: September 98                                                       */
+/*****************************************************************************/
+
+/*
+  
+  Stack class, based on a resizable array
+
+ */
+
+
+#include "array.hpp"
+
+
+///
+template <class T> class STACK
+{
+public:
+  ///
+  inline STACK (INDEX asize = 0, INDEX ainc = 0);
+  ///
+  inline ~STACK ();
+
+  ///
+  inline void Push (const T & el);
+  ///
+  inline T & Pop ();
+  ///
+  const inline T & Top () const;
+  ///
+  inline int IsEmpty () const;
+  ///
+  inline void MakeEmpty ();
+
+private:
+  ///
+  ARRAY<T> elems;
+  ///
+  INDEX size;
+};
+
+
+
+
+/*
+  
+  Stack class, based on a resizable array
+
+ */
+
+template <class T>
+inline STACK<T> :: STACK (INDEX asize, INDEX ainc)
+  : elems(asize, ainc)
+{
+  size = 0;
+}
+
+
+template <class T>
+inline STACK<T> :: ~STACK ()
+{
+  ;
+}
+
+
+template <class T> 
+inline void STACK<T> :: Push (const T & el)
+{
+  if (size < elems.Size())
+    elems.Elem(++size) = el;
+  else
+    {
+      elems.Append(el);
+      size++;
+    }
+}
+
+
+template <class T> 
+inline T & STACK<T> :: Pop ()
+{
+  return elems.Elem(size--);
+}
+
+
+template <class T>
+const inline T & STACK<T> :: Top () const
+{
+  return elems.Get(size);
+}
+
+template <class T>
+inline int STACK<T> :: IsEmpty () const
+{
+  return (size == 0);
+}
+
+
+template <class T>
+inline void STACK<T> :: MakeEmpty ()
+{
+  size = 0;
+}
+
+
+
+#endif
diff --git a/contrib/Netgen/libsrc/general/stack.icc b/contrib/Netgen/libsrc/general/stack.icc
new file mode 100644
index 0000000000000000000000000000000000000000..c0182a564b73ca334e9ec60a7d73e3635e82a3fc
--- /dev/null
+++ b/contrib/Netgen/libsrc/general/stack.icc
@@ -0,0 +1,67 @@
+/*****************************************************************************/
+/*  File: stack.hh                                                           */
+/*  Author: Wolfram Muehlhuber                                               */
+/*  Date: September 98                                                       */
+/*****************************************************************************/
+
+/*
+  
+  Stack class, based on a resizable array
+
+ */
+
+template <class T>
+inline STACK<T> :: STACK (INDEX asize, INDEX ainc)
+  : elems(asize, ainc)
+{
+  size = 0;
+}
+
+
+template <class T>
+inline STACK<T> :: ~STACK ()
+{
+  ;
+}
+
+
+template <class T> 
+inline void STACK<T> :: Push (const T & el)
+{
+  if (size < elems.Size())
+    elems.Elem(++size) = el;
+  else
+    {
+      elems.Append(el);
+      size++;
+    }
+}
+
+
+template <class T> 
+inline T & STACK<T> :: Pop ()
+{
+  return elems.Elem(size--);
+}
+
+
+template <class T>
+const inline T & STACK<T> :: Top () const
+{
+  return elems.Get(size);
+}
+
+template <class T>
+inline int STACK<T> :: IsEmpty () const
+{
+  return (size == 0);
+}
+
+
+template <class T>
+inline void STACK<T> :: MakeEmpty ()
+{
+  size = 0;
+}
+
+
diff --git a/contrib/Netgen/libsrc/general/symbolta.cpp b/contrib/Netgen/libsrc/general/symbolta.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..bd35ac7cb229c6370d599e0d9e108f794eb0a5fd
--- /dev/null
+++ b/contrib/Netgen/libsrc/general/symbolta.cpp
@@ -0,0 +1,52 @@
+/**************************************************************************/
+/* File:   symbolta.cc                                                    */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   01. Jun. 95                                                    */
+/**************************************************************************/
+
+/* 
+   Abstract data type Symbol Table
+*/
+
+#include <mystdlib.h>
+#include <myadt.hpp>
+
+
+#ifndef FILE_SYMBOLTABLECC
+#define FILE_SYMBOLTABLECC
+// necessary for SGI ????
+
+
+namespace netgen
+{
+  //using namespace netgen;
+
+  BASE_SYMBOLTABLE :: BASE_SYMBOLTABLE ()
+  {
+    ;
+  }
+
+
+  BASE_SYMBOLTABLE :: ~BASE_SYMBOLTABLE()
+  {
+    DelNames();
+  }
+
+
+  void BASE_SYMBOLTABLE :: DelNames()
+  {
+    for (int i = 0; i < names.Size(); i++)
+      delete [] names[i];
+    names.SetSize (0);
+  }
+
+  int BASE_SYMBOLTABLE :: Index (const char * name) const
+  {
+    if (!name) return 0;
+    for (int i = 0; i < names.Size(); i++)
+      if (strcmp (names[i], name) == 0) return i+1;
+    return 0;
+  }
+}
+
+#endif
diff --git a/contrib/Netgen/libsrc/general/symbolta.hpp b/contrib/Netgen/libsrc/general/symbolta.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..38895dee8e740abd1c5d48eb450d4a578d74f286
--- /dev/null
+++ b/contrib/Netgen/libsrc/general/symbolta.hpp
@@ -0,0 +1,158 @@
+#ifndef FILE_SYMBOLTA
+#define FILE_SYMBOLTA
+
+
+/**************************************************************************/
+/* File:   symbolta.hh                                                    */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   01. Jun. 95                                                    */
+/**************************************************************************/
+
+/**
+   Base class for the generic SYMBOLTABLE.
+   An array of identifiers is maintained.
+*/
+class BASE_SYMBOLTABLE
+{
+protected:
+  /// identifiers
+  ARRAY <char*> names;
+  
+public:
+  /// Constructor
+  BASE_SYMBOLTABLE ();
+  ///
+  ~BASE_SYMBOLTABLE ();
+  ///
+  void DelNames ();
+  /// Index of symbol name, returns 0 if not used.
+  int Index (const char * name) const;
+};
+
+
+/** 
+    Abstract data type Symbol Table.
+   
+    To a string an value of the generic type T is associated.
+    The string is not copied into the symbol table class!
+*/
+template <class T>
+class SYMBOLTABLE : public BASE_SYMBOLTABLE
+{
+private:
+  /// Associated data
+  ARRAY <T> data;
+  
+public:
+  /// Creates a symboltable
+  inline SYMBOLTABLE ();
+  /// Returns size of symboltable
+  inline INDEX Size() const;
+  /// Returns reference to element, error if not used
+  inline T & Elem (const char * name);
+  /// Returns reference to i-th element
+  inline T & Elem (int i) 
+  { return data.Elem(i); }
+  /// Returns element, error if not used
+  inline const T & Get (const char * name) const;
+  /// Returns i-th element
+  inline const T & Get (int i) const;
+  /// Returns name of i-th element
+  inline const char* GetName (int i) const;
+  /// Associates el to the string name, overrides if name is used
+  inline void Set (const char * name, const T & el);
+  /// Checks whether name is used
+  inline bool Used (const char * name) const;
+  /// Deletes symboltable
+  inline void DeleteAll ();
+
+  inline T & operator[] (int i) 
+  { return data[i]; }
+  inline const T & operator[] (int i) const
+  { return data[i]; }
+
+private:
+  /// Prevents from copying symboltable by pointer assignment
+  SYMBOLTABLE<T> & operator= (SYMBOLTABLE<T> &);
+};
+
+
+
+
+template <class T>
+inline SYMBOLTABLE<T> :: SYMBOLTABLE () 
+{ 
+  ;
+}
+
+
+template <class T>
+inline INDEX SYMBOLTABLE<T> :: Size() const
+{
+  return data.Size();
+}
+
+template <class T>
+inline T & SYMBOLTABLE<T> :: Elem (const char * name)
+{
+  int i = Index (name);
+  if (i) 
+    return data.Elem (i);
+  else 
+    return data.Elem(1);
+}
+
+template <class T>
+inline const T & SYMBOLTABLE<T> :: Get (const char * name) const
+{
+  int i;
+  i = Index (name);
+  if (i) 
+    return data.Get(i);
+  else 
+    return data.Get(1);
+}
+
+template <class T>
+inline const T & SYMBOLTABLE<T> :: Get (int i) const
+{
+  return data.Get(i);
+}
+
+template <class T>
+inline const char* SYMBOLTABLE<T> :: GetName (int i) const
+{
+  return names.Get(i);
+}
+
+template <class T>
+inline void SYMBOLTABLE<T> :: Set (const char * name, const T & el)
+{
+  int i;
+  i = Index (name);
+  if (i) 
+    data.Set(i, el);
+  else
+    {
+      data.Append (el);
+      char * hname = new char [strlen (name) + 1];
+      strcpy (hname, name);
+      names.Append (hname);
+    }
+}
+
+template <class T>
+inline bool SYMBOLTABLE<T> :: Used (const char * name) const
+{
+  return (Index(name)) ? true : false;
+}
+
+template <class T>
+inline void SYMBOLTABLE<T> :: DeleteAll () 
+{	
+  DelNames();
+  data.DeleteAll();
+}
+
+
+#endif
diff --git a/contrib/Netgen/libsrc/general/table.cpp b/contrib/Netgen/libsrc/general/table.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..b6168374bdb000aa175cc2ed55b540f264cf162a
--- /dev/null
+++ b/contrib/Netgen/libsrc/general/table.cpp
@@ -0,0 +1,193 @@
+/**************************************************************************/
+/* File:   table.cpp                                                      */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   01. Jun. 95                                                    */
+/**************************************************************************/
+
+/* 
+   Abstract data type TABLE
+*/
+
+#include <mystdlib.h>
+#include <myadt.hpp>
+
+namespace netgen
+{
+  //using namespace netgen;
+
+  BASE_TABLE :: BASE_TABLE (int size)
+    : data(size)
+  {
+    for (int i = 0; i < size; i++)
+      {
+	data[i].maxsize = 0;
+	data[i].size = 0;
+	data[i].col = NULL;
+      }
+    oneblock = NULL;
+  }
+
+  BASE_TABLE :: BASE_TABLE (const FlatArray<int> & entrysizes, int elemsize)
+    : data(entrysizes.Size())
+  {
+    int i, cnt = 0;
+    int n = entrysizes.Size();
+
+    for (i = 0; i < n; i++)
+      cnt += entrysizes[i];
+    oneblock = new char[elemsize * cnt];
+    // mem_total_alloc_table += elemsize * cnt;
+
+    cnt = 0;
+    for (i = 0; i < n; i++)
+      {
+	data[i].maxsize = entrysizes[i];
+	data[i].size = 0;
+
+	data[i].col = &oneblock[elemsize * cnt];
+	cnt += entrysizes[i];
+      }
+  }
+
+  BASE_TABLE :: ~BASE_TABLE ()
+  {
+    if (oneblock)
+      delete [] oneblock;
+    else
+      {
+	for (int i = 0; i < data.Size(); i++)
+	  delete [] (char*)data[i].col;
+      }
+  }
+  
+  void BASE_TABLE :: SetSize (int size)
+  {
+    for (int i = 0; i < data.Size(); i++)
+      delete [] (char*)data[i].col;
+    
+    data.SetSize(size);
+    for (int i = 0; i < size; i++)
+      {
+	data[i].maxsize = 0;
+	data[i].size = 0;
+	data[i].col = NULL;
+      }    
+  }
+  
+  void BASE_TABLE :: ChangeSize (int size)
+  {
+    int oldsize = data.Size();
+    if (size == oldsize) 
+      return;
+
+    if (size < oldsize)
+      for (int i = size; i < oldsize; i++)
+	delete [] (char*)data[i].col;
+    
+    data.SetSize(size);
+
+    for (int i = oldsize; i < size; i++)
+      {
+	data[i].maxsize = 0;
+	data[i].size = 0;
+	data[i].col = NULL;
+      }    
+  }
+
+  void BASE_TABLE :: IncSize2 (int i, int elsize)
+  {
+#ifdef DEBUG
+    if (i < 0 || i >= data.Size())
+      {
+	MyError ("BASE_TABLE::Inc: Out of range");
+	return;
+      }
+#endif
+    
+    linestruct & line = data[i];
+    if (line.size == line.maxsize)
+      {
+	void * p = new char [(line.maxsize+5) * elsize];
+      
+	memcpy (p, line.col, line.maxsize * elsize);
+	delete [] (char*)line.col;
+
+	line.col = p;
+	line.maxsize += 5;
+      }
+  
+    line.size++;
+  }
+
+
+
+  /*
+  void BASE_TABLE :: DecSize (int i)
+  {
+#ifdef DEBUG
+    if (i < 0 || i >= data.Size())
+      {
+	MyError ("BASE_TABLE::Dec: Out of range");
+	return;
+      }
+#endif
+
+    linestruct & line = data[i];
+  
+#ifdef DEBUG
+    if (line.size == 0)
+      {
+	MyError ("BASE_TABLE::Dec: EntrySize < 0");
+	return;      
+      }
+#endif
+  
+    line.size--;
+  }
+  */
+
+
+
+  void BASE_TABLE :: AllocateElementsOneBlock (int elemsize)
+  {
+    int cnt = 0;
+    int n = data.Size();
+
+    for (int i = 0; i < n; i++)
+      cnt += data[i].maxsize;
+    oneblock = new char[elemsize * cnt];
+
+    cnt = 0;
+    for (int i = 0; i < n; i++)
+      {
+	data[i].size = 0;
+	data[i].col = &oneblock[elemsize * cnt];
+	cnt += data[i].maxsize;
+      }
+  }
+
+
+
+  int BASE_TABLE :: AllocatedElements () const
+  {
+    int els = 0;
+    for (int i = 0; i < data.Size(); i++)
+      els += data[i].maxsize;
+    return els;
+  }
+  
+  int BASE_TABLE :: UsedElements () const
+  {
+    int els = 0;
+    for (int i = 0; i < data.Size(); i++)
+      els += data[i].size;
+    return els;
+  }
+
+  void BASE_TABLE :: SetElementSizesToMaxSizes ()
+  {
+    for (int i = 0; i < data.Size(); i++)
+      data[i].size = data[i].maxsize;
+  }
+
+}
diff --git a/contrib/Netgen/libsrc/general/table.hpp b/contrib/Netgen/libsrc/general/table.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..f9ed02f18c4c893347a8468f972a86ddb02911a9
--- /dev/null
+++ b/contrib/Netgen/libsrc/general/table.hpp
@@ -0,0 +1,223 @@
+#ifndef FILE_TABLE
+#define FILE_TABLE
+
+/**************************************************************************/
+/* File:   table.hpp                                                      */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   01. Jun. 95                                                    */
+/**************************************************************************/
+
+/// Base class to generic class TABLE.
+class BASE_TABLE
+{
+protected:
+  
+  ///
+  class linestruct
+  {
+  public:
+    ///
+    int size;
+    /// 
+    int maxsize;
+    ///
+    void * col;
+  };
+  
+  ///
+  ARRAY<linestruct> data;
+  char * oneblock;
+
+public:
+  ///
+  BASE_TABLE (int size);
+  ///
+  BASE_TABLE (const FlatArray<int> & entrysizes, int elemsize);
+  ///
+  ~BASE_TABLE ();
+  ///
+  void SetSize (int size);
+  ///
+  void ChangeSize (int size);
+
+  /// increment size of entry i by one, i is 0-based
+  void IncSize (int i, int elsize)
+  {
+    if (data[i].size < data[i].maxsize)
+      data[i].size++;
+    else
+      IncSize2 (i, elsize);
+  }
+  ///
+  void IncSize2 (int i, int elsize);
+
+  //  void DecSize (int i);
+
+  ///
+  void AllocateElementsOneBlock (int elemsize);
+  
+  int AllocatedElements () const;
+  int UsedElements () const;
+
+  void SetElementSizesToMaxSizes ();
+};
+
+
+
+
+
+
+
+/** 
+   Abstract data type TABLE.
+   
+   To an integer i in the range from 1 to size a set of elements of the
+   generic type T is associated. 
+*/
+template <class T, int BASE = 0>
+class TABLE : public BASE_TABLE
+{
+public:
+  /// Creates table.
+  inline TABLE () : BASE_TABLE(0) { ; }
+
+  /// Creates table of size size
+  inline TABLE (int size) : BASE_TABLE (size) { ; }
+
+  /// Creates fixed maximal element size table
+  inline TABLE (const FlatArray<int,BASE> & entrysizes)
+    : BASE_TABLE (FlatArray<int> (entrysizes.Size(), const_cast<int*>(&entrysizes[BASE])), 
+		  sizeof(T))
+  { ; }
+  
+  /// Changes Size of table to size, deletes data
+  inline void SetSize (int size)
+  {
+    BASE_TABLE::SetSize (size);
+  }
+
+  /// Changes Size of table to size, keep data
+  inline void ChangeSize (int size)
+  {
+    BASE_TABLE::ChangeSize (size);
+  }
+
+
+  /// Inserts element acont into row i, BASE-based. Does not test if already used.
+  inline void Add (int i, const T & acont)
+  {
+    IncSize (i-BASE, sizeof (T));
+    ((T*)data[i-BASE].col)[data[i-BASE].size-1] = acont;
+  }
+
+
+  /// Inserts element acont into row i, 1-based. Does not test if already used.
+  inline void Add1 (int i, const T & acont)
+  {
+    IncSize (i-1, sizeof (T));
+    ((T*)data.Elem(i).col)[data.Elem(i).size-1] = acont;
+  }
+  
+  ///
+  void IncSizePrepare (int i)
+  {
+    data[i-BASE].maxsize++;
+  }
+
+
+  /// Inserts element acont into row i. BASE-based. Does not test if already used, assumes to have enough memory
+  inline void AddSave (int i, const T & acont)
+    {
+      ((T*)data[i-BASE].col)[data[i-BASE].size] = acont;
+      data[i-BASE].size++;
+    }
+
+  /// Inserts element acont into row i. 1-based. Does not test if already used, assumes to have mem
+  inline void AddSave1 (int i, const T & acont)
+    {
+      ((T*)data.Elem(i).col)[data.Elem(i).size] = acont;
+      data.Elem(i).size++;
+    }
+
+  /// Inserts element acont into row i. Does not test if already used.
+  inline void AddEmpty (int i)
+  {
+    IncSize (i-BASE, sizeof (T));
+  }
+
+  /** Set the nr-th element in the i-th row to acont.
+    Does not check for overflow. */
+  inline void Set (int i, int nr, const T & acont)
+    { ((T*)data.Get(i).col)[nr-1] = acont; }
+  /** Returns the nr-th element in the i-th row.
+    Does not check for overflow. */
+  inline const T & Get (int i, int nr) const
+    { return ((T*)data.Get(i).col)[nr-1]; }
+
+
+  /** Returns pointer to the first element in row i. */
+  inline const T * GetLine (int i) const
+  {
+    return ((const T*)data.Get(i).col);
+  }
+
+
+  /// Returns size of the table.
+  inline int Size () const
+  {
+    return data.Size();
+  }
+
+  /// Returns size of the i-th row.
+  inline int EntrySize (int i) const
+    { return data.Get(i).size; }
+
+  /*
+  inline void DecEntrySize (int i)
+    { DecSize(i); }
+  */
+  void AllocateElementsOneBlock ()
+    { BASE_TABLE::AllocateElementsOneBlock (sizeof(T)); }
+
+
+  inline void PrintMemInfo (ostream & ost) const
+  {
+    int els = AllocatedElements(); 
+    ost << "table: allocaed " << els 
+	<< " a " << sizeof(T) << " Byts = " 
+	<< els * sizeof(T) 
+	<< " bytes in " << Size() << " bags."
+	<< " used: " << UsedElements()
+	<< endl;
+  }
+
+  /// Access entry.
+  FlatArray<T> operator[] (int i) const
+  { 
+#ifdef DEBUG
+    if (i-BASE < 0 || i-BASE >= data.Size())
+      cout << "table out of range, i = " << i << ", s = " << data.Size() << endl;
+#endif
+
+    return FlatArray<T> (data[i-BASE].size, (T*)data[i-BASE].col);
+  }
+};
+
+
+template <class T, int BASE>
+inline ostream & operator<< (ostream & ost, const TABLE<T,BASE> & table)
+{
+  for (int i = BASE; i < table.Size()+BASE; i++)
+    {
+      ost << i << ": ";
+      FlatArray<T> row = table[i];
+      ost << "(" << row.Size() << ") ";
+      for (int j = 0; j < row.Size(); j++)
+	ost << row[j] << " ";
+      ost << endl;
+    }
+  return ost;
+}
+
+#endif
+
diff --git a/contrib/Netgen/libsrc/general/template.hpp b/contrib/Netgen/libsrc/general/template.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..9fb378a7bc0648623902579ba96984cf5f37cc07
--- /dev/null
+++ b/contrib/Netgen/libsrc/general/template.hpp
@@ -0,0 +1,448 @@
+#ifndef FILE_TEMPLATE
+#define FILE_TEMPLATE
+
+/**************************************************************************/
+/* File:   template.hh                                                    */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   01. Jun. 95                                                    */
+/**************************************************************************/
+
+/*
+   templates, global types, defines and variables
+*/
+
+///	The following value may be adapted to the hardware !
+#ifndef CLOCKS_PER_SEC
+#define CLOCKS_PER_SEC 1000000
+#endif
+
+
+// #include <iostream>
+/** output stream for testing.
+  testout is opened by main */
+extern ostream * testout;
+
+/** use instead of cout */
+extern ostream * mycout;
+
+/** error output stream */
+extern ostream * myerr;
+
+/** Error messages display.
+  Error messages are displayed by this function */
+extern void MyError (const char * ch);
+
+
+/** Rings the bell.
+  Produces nr beeps. */
+extern void MyBeep (int nr = 1);
+
+
+template <class T>
+inline void Swap (T & a, T & b)
+{
+  T temp = a;
+  a = b;
+  b = temp;
+}
+
+/*
+template <class T>
+inline void swap (T & a, T & b)
+{
+  T temp = a;
+  a = b;
+  b = temp;
+}
+*/
+
+
+
+/**
+  INDEX is a typedef for (at least) 4-byte integer
+ */
+typedef int INDEX;
+
+/**
+  BOOL is a typedef for boolean variables
+  */
+// typedef int BOOL;
+
+typedef int ELIND;
+typedef int PIND;
+
+
+class twoint 
+{ 
+public: ///
+  int i1, i2; ///
+  twoint() {};
+  ///
+  twoint(int ii1, int ii2) {i1 = ii1; i2 = ii2;}
+  friend int operator== (const twoint& t1, const twoint& t2);
+  ///
+  void Swap() {int x = i1; i1 = i2; i2 = x;}
+  void Sort() {if (i1 > i2) {Swap();}}
+};
+
+inline int operator== (const twoint& t1, const twoint& t2) 
+{
+  return t1.i1 == t2.i1 && t1.i2 == t2.i2;
+}
+
+class threeint 
+{ 
+public: /// 
+  int i1, i2, i3; ///
+  threeint() {}; 
+  ///
+  threeint(int ii1, int ii2, int ii3) {i1 = ii1; i2 = ii2; i3 = ii3;}
+};
+
+///
+class twodouble
+{
+public:
+  ///
+  double d1, d2;
+  ///
+  twodouble() {d1 = 0; d2 = 0;};
+  ///
+  twodouble(double id1, double id2) {d1 = id1; d2 = id2;}
+  ///
+  void Swap() {double x = d1; d1 = d2; d2 = x;}
+};
+
+class fourint { public: int i1, i2, i3, i4; fourint() {}; };
+
+
+///
+class INDEX_2;
+ostream & operator<<(ostream  & s, const INDEX_2 & i2);
+
+
+class INDEX_2
+{
+  ///
+  INDEX i[2];
+
+public:
+  ///
+  INDEX_2 () { }
+  ///
+  INDEX_2 (INDEX ai1, INDEX ai2)
+    { i[0] = ai1; i[1] = ai2; }
+
+  ///
+  INDEX_2 (const INDEX_2 & in2)
+    { i[0] = in2.i[0]; i[1] = in2.i[1]; }
+
+  ///
+  int operator== (const INDEX_2 & in2) const
+    { return i[0] == in2.i[0] && i[1] == in2.i[1]; }
+
+  ///
+
+
+  INDEX_2 Sort ()
+  {
+    if (i[0] > i[1]) 
+      {
+	INDEX hi = i[0];
+	i[0] = i[1];
+	i[1] = hi;
+      }
+    return *this;
+  }
+
+  static INDEX_2 Sort (int i1, int i2)
+  {
+    if (i1 > i2)
+      return INDEX_2 (i2,i1);
+    else
+      return INDEX_2 (i1,i2);
+  }
+
+
+  ///
+  INDEX & I1 () { return i[0]; }
+  ///
+  INDEX & I2 () { return i[1]; }
+  ///
+  INDEX & I (int j) { return i[j-1]; }
+  ///
+  const INDEX & I1 () const { return i[0]; }
+  ///
+  const INDEX & I2 () const { return i[1]; }
+  ///
+  const INDEX & I (int j) const { return i[j-1]; }
+  ///
+  int & operator[] (int j) { return i[j]; }
+  ///
+  const int & operator[] (int j) const { return i[j]; }
+  ///
+  friend ostream & operator<<(ostream  & s, const INDEX_2 & i2);
+};
+
+
+///
+class INDEX_3
+{
+  ///
+  INDEX i[3];
+
+public:
+  ///
+  INDEX_3 () { }
+  ///
+  INDEX_3 (INDEX ai1, INDEX ai2, INDEX ai3)
+    { i[0] = ai1; i[1] = ai2; i[2] = ai3; }
+
+  ///
+  INDEX_3 (const INDEX_3 & in2)
+    { i[0] = in2.i[0]; i[1] = in2.i[1]; i[2] = in2.i[2]; }
+
+
+  static INDEX_3 Sort (INDEX_3 i3)
+  {
+    return i3.Sort();
+  }
+
+  static INDEX_3 Sort (int i1, int i2, int i3)
+  {
+    if (i1 > i2) Swap (i1, i2);
+    if (i2 > i3) Swap (i2, i3);
+    if (i1 > i2) Swap (i1, i2);
+    return INDEX_3 (i1, i2, i3);
+  }
+
+  INDEX_3 Sort ()
+  {
+    if (i[0] > i[1]) Swap (i[0], i[1]);
+    if (i[1] > i[2]) Swap (i[1], i[2]);
+    if (i[0] > i[1]) Swap (i[0], i[1]);
+    return *this;
+  }
+
+  int operator== (const INDEX_3 & in2) const
+    { return i[0] == in2.i[0] && i[1] == in2.i[1] && i[2] == in2.i[2];}
+
+  ///
+  INDEX & I1 () { return i[0]; }
+  ///
+  INDEX & I2 () { return i[1]; }
+  ///
+  INDEX & I3 () { return i[2]; }
+  ///
+  INDEX & I (int j) { return i[j-1]; }
+  ///
+  const INDEX & I1 () const { return i[0]; }
+  ///
+  const INDEX & I2 () const { return i[1]; }
+  ///
+  const INDEX & I3 () const { return i[2]; }
+  ///
+  const INDEX & I (int j) const { return i[j-1]; }
+  ///
+  int & operator[] (int j) { return i[j]; }
+  ///
+  const int & operator[] (int j) const { return i[j]; }
+
+  ///
+  friend ostream & operator<<(ostream  & s, const INDEX_3 & i3);
+};
+
+
+
+///
+class INDEX_4
+{
+  ///
+  INDEX i[4];
+
+public:
+  ///
+  INDEX_4 () { }
+  ///
+  INDEX_4 (INDEX ai1, INDEX ai2, INDEX ai3, INDEX ai4)
+    { i[0] = ai1; i[1] = ai2; i[2] = ai3; i[3] = ai4; }
+
+  ///
+  INDEX_4 (const INDEX_4 & in2)
+    { i[0] = in2.i[0]; i[1] = in2.i[1]; i[2] = in2.i[2]; i[3] = in2.i[3]; }
+
+  ///
+  void Sort ();
+
+  ///
+  int operator== (const INDEX_4 & in2) const
+    { return 
+	i[0] == in2.i[0] && i[1] == in2.i[1] && 
+	i[2] == in2.i[2] && i[3] == in2.i[3]; }
+
+  ///
+  INDEX & I1 () { return i[0]; }
+  ///
+  INDEX & I2 () { return i[1]; }
+  ///
+  INDEX & I3 () { return i[2]; }
+  ///
+  INDEX & I4 () { return i[3]; }
+  ///
+  INDEX & I (int j) { return i[j-1]; }
+  ///
+  const INDEX & I1 () const { return i[0]; }
+  ///
+  const INDEX & I2 () const { return i[1]; }
+  ///
+  const INDEX & I3 () const { return i[2]; }
+  ///
+  const INDEX & I4 () const { return i[3]; }
+  ///
+  const INDEX & I (int j) const { return i[j-1]; }
+  ///
+  int & operator[] (int j) { return i[j]; }
+  ///
+  const int & operator[] (int j) const { return i[j]; }
+
+  ///
+  friend ostream & operator<<(ostream  & s, const INDEX_4 & i4);
+};
+
+
+
+
+
+
+
+
+/// The sort preserves quads !!!
+class INDEX_4Q
+{
+  ///
+  INDEX i[4];
+
+public:
+  ///
+  INDEX_4Q () { }
+  ///
+  INDEX_4Q (INDEX ai1, INDEX ai2, INDEX ai3, INDEX ai4)
+    { i[0] = ai1; i[1] = ai2; i[2] = ai3; i[3] = ai4; }
+
+  ///
+  INDEX_4Q (const INDEX_4Q & in2)
+    { i[0] = in2.i[0]; i[1] = in2.i[1]; i[2] = in2.i[2]; i[3] = in2.i[3]; }
+
+  ///
+  void Sort ();
+
+  ///
+  int operator== (const INDEX_4Q & in2) const
+    { return 
+	i[0] == in2.i[0] && i[1] == in2.i[1] && 
+	i[2] == in2.i[2] && i[3] == in2.i[3]; }
+
+  ///
+  INDEX & I1 () { return i[0]; }
+  ///
+  INDEX & I2 () { return i[1]; }
+  ///
+  INDEX & I3 () { return i[2]; }
+  ///
+  INDEX & I4 () { return i[3]; }
+  ///
+  INDEX & I (int j) { return i[j-1]; }
+  ///
+  const INDEX & I1 () const { return i[0]; }
+  ///
+  const INDEX & I2 () const { return i[1]; }
+  ///
+  const INDEX & I3 () const { return i[2]; }
+  ///
+  const INDEX & I4 () const { return i[3]; }
+  ///
+  const INDEX & I (int j) const { return i[j-1]; }
+  ///
+  friend ostream & operator<<(ostream  & s, const INDEX_4Q & i4);
+};
+
+
+
+
+
+
+
+
+
+
+
+
+///
+template <class T>
+inline T min2 (T a, T b)
+{
+  ///
+  return (a < b) ? a : b;
+}
+///
+template <class T>
+inline T max2 (T a, T b)
+{
+  ///
+  return (a > b) ? a : b;
+}
+///
+template <class T>
+inline T min3 (T a, T b, T c)
+{
+  ///
+  return (a < b) ? (a < c) ? a : c
+    : (b < c) ? b : c;
+}
+///
+template <class T>
+inline T max3 (T a, T b, T c)
+{
+  ///
+  return (a > b) ? ((a > c) ? a : c)
+    : ((b > c) ? b : c);
+}
+
+///
+
+///
+template <class T>
+inline int sgn (T a)
+{
+  return (a > 0) ? 1 : (   ( a < 0) ? -1 : 0 );
+}
+
+///
+template <class T>
+inline T sqr (const T a)
+{
+  return a * a; 
+}
+
+///
+template <class T>
+inline T pow3 (const T a)
+{
+  return a * a * a; 
+}
+
+
+
+/*
+template <class T>
+void BubbleSort (int size, T * data);
+
+template <class T>
+void MergeSort (int size, T * data, T * help);
+*/
+
+
+
+
+
+#endif
diff --git a/contrib/Netgen/libsrc/gprim/Makefile b/contrib/Netgen/libsrc/gprim/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..608e522844a6a48099c593d915f4e11aa34df466
--- /dev/null
+++ b/contrib/Netgen/libsrc/gprim/Makefile
@@ -0,0 +1,14 @@
+#
+# Makefile for geometric library
+#
+src =  geom2d.cpp geom3d.cpp  \
+	geomtest3d.cpp adtree.cpp transform3d.cpp geomfuncs.cpp
+
+# reftrans.cpp rot3d.cpp
+#
+lib = gprim
+libpath = libsrc/gprim
+#
+#
+include ../makefile.inc
+#
diff --git a/contrib/Netgen/libsrc/gprim/adtree.cpp b/contrib/Netgen/libsrc/gprim/adtree.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..0b5a319707bfce9923fbdec4d58f4eb712605061
--- /dev/null
+++ b/contrib/Netgen/libsrc/gprim/adtree.cpp
@@ -0,0 +1,2165 @@
+#include <mystdlib.h>
+
+
+#include <myadt.hpp>
+// class DenseMatrix;
+#include <gprim.hpp>
+
+namespace netgen
+{
+
+
+  /* ******************************* ADTree ******************************* */
+
+
+  ADTreeNode :: ADTreeNode(int adim)
+  {
+    pi = -1;
+
+    left = NULL;
+    right = NULL;
+    father = NULL;
+    nchilds = 0;
+    dim = adim;
+    data = new float [dim];
+    boxmin = NULL;
+    boxmax = NULL;
+  }
+
+
+
+
+  ADTreeNode :: ~ADTreeNode()
+  {
+    delete data;
+  }
+
+
+  ADTree :: ADTree (int adim, const float * acmin, 
+		    const float * acmax)
+    : ela(0), stack(1000), stackdir(1000)
+  {
+    dim = adim;
+    cmin = new float [dim];
+    cmax = new float [dim];
+    memcpy (cmin, acmin, dim * sizeof(float));
+    memcpy (cmax, acmax, dim * sizeof(float));
+
+    root = new ADTreeNode (dim);
+    root->sep = (cmin[0] + cmax[0]) / 2;
+    root->boxmin = new float [dim];
+    root->boxmax = new float [dim];
+    memcpy (root->boxmin, cmin, dim * sizeof(float));
+    memcpy (root->boxmax, cmax, dim * sizeof(float));
+  }
+
+  ADTree :: ~ADTree ()
+  {
+    ;
+  }
+
+  void ADTree :: Insert (const float * p, int pi)
+  {
+    ADTreeNode *node(NULL);
+    ADTreeNode *next;
+    int dir;
+    int lr(1);
+
+    float * bmin = new float [dim];
+    float * bmax = new float [dim];
+  
+    memcpy (bmin, cmin, dim * sizeof(float));
+    memcpy (bmax, cmax, dim * sizeof(float));
+
+
+    next = root;
+    dir = 0;
+    while (next)
+      {
+	node = next;
+
+	if (node->pi == -1)
+	  {    
+	    memcpy (node->data, p, dim * sizeof(float));
+	    node->pi = pi;
+
+	    if (ela.Size() < pi+1)
+	      ela.SetSize (pi+1);
+	    ela[pi] = node;
+
+	    return;
+	  }
+
+	if (node->sep > p[dir])
+	  {
+	    next = node->left;
+	    bmax[dir] = node->sep;
+	    lr = 0;
+	  }
+	else
+	  {
+	    next = node->right;
+	    bmin[dir] = node->sep;
+	    lr = 1;
+	  }
+
+	dir++;
+	if (dir == dim)
+	  dir = 0;
+      }
+
+
+    next = new ADTreeNode(dim);
+    memcpy (next->data, p, dim * sizeof(float));
+    next->pi = pi;
+    next->sep = (bmin[dir] + bmax[dir]) / 2;
+    next->boxmin = bmin;
+    next->boxmax = bmax;
+
+    if (ela.Size() < pi+1)
+      ela.SetSize (pi+1);
+    ela[pi] = next;
+
+
+    if (lr)
+      node->right = next;
+    else
+      node->left = next;
+    next -> father = node;
+
+    while (node)
+      {
+	node->nchilds++;
+	node = node->father;
+      }
+  }
+
+  void ADTree :: DeleteElement (int pi)
+  {
+    ADTreeNode * node = ela[pi];
+
+    node->pi = -1;
+
+    node = node->father;
+    while (node)
+      {
+	node->nchilds--;
+	node = node->father;
+      }
+  }
+
+
+  void ADTree :: SetCriterion (ADTreeCriterion & acriterion)
+  {
+    criterion = & acriterion;
+  }
+
+
+  void ADTree :: Reset ()
+  {
+    stack.Elem(1) = root;
+    stackdir.Elem(1) = 0;
+    stackindex = 1;
+  }
+
+
+  int ADTree:: Next ()
+  {
+    ADTreeNode *node;
+    int dir;
+
+    if (stackindex == 0)
+      return -1;
+
+    do 
+      {
+	node = stack.Get(stackindex);
+	dir = stackdir.Get(stackindex);
+	stackindex --;
+
+	if (criterion -> Eval(node))
+	  {
+	    int ndir = dir + 1;
+	    if (ndir == dim)
+	      ndir = 0;
+
+	    if (node -> left && criterion -> Eval (node->left))
+	      {
+		stackindex ++;
+		stack.Elem(stackindex) = node -> left;
+		stackdir.Elem(stackindex) = ndir;
+	      }
+	    if (node->right && criterion -> Eval (node -> right))
+	      {
+		stackindex++;
+		stack.Elem(stackindex) = node->right;
+		stackdir.Elem(stackindex) = ndir;
+	      }
+	  
+	    if (node -> pi != -1)
+	      return node->pi;
+	  }
+      }
+    while (stackindex > 0);
+
+    return -1;
+  }
+
+
+  void ADTree :: GetMatch (ARRAY <int> & matches)
+  {
+    int nodenr;
+
+    Reset();
+
+    while ( (nodenr = Next()) != -1)
+      matches.Append (nodenr);
+  }
+
+
+  void ADTree :: PrintRec (ostream & ost, const ADTreeNode * node) const
+  {
+  
+    if (node->data)
+      {
+	ost << node->pi << ": ";
+	ost << node->nchilds << " childs, ";
+	for (int i = 0; i < dim; i++)
+	  ost << node->data[i] << " ";
+	ost << endl;
+      }
+    if (node->left)
+      {
+	ost << "l ";
+	PrintRec (ost, node->left);
+      }
+    if (node->right)
+      {
+	ost << "r ";
+	PrintRec (ost, node->right);
+      }
+  }
+
+
+  /* ******************************* ADTree3 ******************************* */
+
+
+  ADTreeNode3 :: ADTreeNode3()
+  {
+    pi = -1;
+
+    left = NULL;
+    right = NULL;
+    father = NULL;
+    nchilds = 0;
+  }
+
+  void ADTreeNode3 :: DeleteChilds ()
+  {
+    if (left)
+      {
+	left->DeleteChilds();
+	delete left;
+	left = NULL;
+      }
+    if (right)
+      {
+	right->DeleteChilds();
+	delete right;
+	right = NULL;
+      }
+  }
+
+
+  BlockAllocator ADTreeNode3 :: ball(sizeof (ADTreeNode3));
+
+
+  void * ADTreeNode3 :: operator new(size_t s)
+  {
+    return ball.Alloc();
+  }
+
+  void ADTreeNode3 :: operator delete (void * p)
+  {
+    ball.Free (p);
+  }
+
+
+
+
+
+
+
+  ADTree3 :: ADTree3 (const float * acmin, 
+		      const float * acmax)
+    : ela(0)
+  {
+    memcpy (cmin, acmin, 3 * sizeof(float));
+    memcpy (cmax, acmax, 3 * sizeof(float));
+
+    root = new ADTreeNode3;
+    root->sep = (cmin[0] + cmax[0]) / 2;
+  }
+
+  ADTree3 :: ~ADTree3 ()
+  {
+    root->DeleteChilds();
+    delete root;
+  }
+
+
+  void ADTree3 :: Insert (const float * p, int pi)
+  {
+    ADTreeNode3 *node(NULL);
+    ADTreeNode3 *next;
+    int dir;
+    int lr(0);
+
+    float bmin[3];
+    float bmax[3];
+  
+    memcpy (bmin, cmin, 3 * sizeof(float));
+    memcpy (bmax, cmax, 3 * sizeof(float));
+
+    next = root;
+    dir = 0;
+    while (next)
+      {
+	node = next;
+
+	if (node->pi == -1)
+	  {    
+	    memcpy (node->data, p, 3 * sizeof(float));
+	    node->pi = pi;
+
+	    if (ela.Size() < pi+1)
+	      ela.SetSize (pi+1);
+	    ela[pi] = node;
+
+	    return;
+	  }
+
+	if (node->sep > p[dir])
+	  {
+	    next = node->left;
+	    bmax[dir] = node->sep;
+	    lr = 0;
+	  }
+	else
+	  {
+	    next = node->right;
+	    bmin[dir] = node->sep;
+	    lr = 1;
+	  }
+
+	dir++;
+	if (dir == 3)
+	  dir = 0;
+      }
+
+
+    next = new ADTreeNode3;
+    memcpy (next->data, p, 3 * sizeof(float));
+    next->pi = pi;
+    next->sep = (bmin[dir] + bmax[dir]) / 2;
+
+
+    if (ela.Size() < pi+1)
+      ela.SetSize (pi+1);
+    ela[pi] = next;		
+
+
+    if (lr)
+      node->right = next;
+    else
+      node->left = next;
+    next -> father = node;
+
+    while (node)
+      {
+	node->nchilds++;
+	node = node->father;
+      }
+  }
+
+  void ADTree3 :: DeleteElement (int pi)
+  {
+    ADTreeNode3 * node = ela[pi];
+
+    node->pi = -1;
+
+    node = node->father;
+    while (node)
+      {
+	node->nchilds--;
+	node = node->father;
+      }
+  }
+
+  void ADTree3 :: GetIntersecting (const float * bmin, 
+				   const float * bmax,
+				   ARRAY<int> & pis) const
+  {
+    static ARRAY<ADTreeNode3*> stack(1000);
+    static ARRAY<int> stackdir(1000);
+    ADTreeNode3 * node;
+    int dir, stacks;
+
+    stack.SetSize (1000);
+    stackdir.SetSize(1000);
+    pis.SetSize(0);
+
+    stack.Elem(1) = root;
+    stackdir.Elem(1) = 0;
+    stacks = 1;
+
+    while (stacks)
+      {
+	node = stack.Get(stacks);
+	dir = stackdir.Get(stacks); 
+	stacks--;
+
+	if (node->pi != -1)
+	  {
+	    if (node->data[0] >= bmin[0] && node->data[0] <= bmax[0] &&
+		node->data[1] >= bmin[1] && node->data[1] <= bmax[1] &&
+		node->data[2] >= bmin[2] && node->data[2] <= bmax[2])
+
+	      pis.Append (node->pi);
+	  }
+
+
+	int ndir = dir+1;
+	if (ndir == 3)
+	  ndir = 0;
+
+	if (node->left && bmin[dir] <= node->sep)
+	  {
+	    stacks++;
+	    stack.Elem(stacks) = node->left;
+	    stackdir.Elem(stacks) = ndir;
+	  }
+	if (node->right && bmax[dir] >= node->sep)
+	  {
+	    stacks++;
+	    stack.Elem(stacks) = node->right;
+	    stackdir.Elem(stacks) = ndir;
+	  }
+      }
+  }
+
+  void ADTree3 :: PrintRec (ostream & ost, const ADTreeNode3 * node) const
+  {
+  
+    if (node->data)
+      {
+	ost << node->pi << ": ";
+	ost << node->nchilds << " childs, ";
+	for (int i = 0; i < 3; i++)
+	  ost << node->data[i] << " ";
+	ost << endl;
+      }
+    if (node->left)
+      PrintRec (ost, node->left);
+    if (node->right)
+      PrintRec (ost, node->right);
+  }
+
+
+
+
+
+
+
+
+#ifdef ABC
+
+  /* ******************************* ADTree3Div ******************************* */
+
+
+  ADTreeNode3Div :: ADTreeNode3Div()
+  {
+    pi = 0;
+  
+    int i;
+    for (i = 0; i < ADTN_DIV; i++)
+      childs[i] = NULL;
+
+    father = NULL;
+    nchilds = 0;
+    minx = 0;
+    dist = 1;
+  }
+
+  void ADTreeNode3Div :: DeleteChilds ()
+  {
+    int i;
+    for (i = 0; i < ADTN_DIV; i++)
+      if (childs[i])
+	{
+	  childs[i]->DeleteChilds();
+	  delete childs[i];
+	  childs[i] = NULL;
+	}
+  }
+
+
+  BlockAllocator ADTreeNode3Div :: ball(sizeof (ADTreeNode3Div));
+
+  void * ADTreeNode3Div :: operator new(size_t)
+  {
+    return ball.Alloc();
+  }
+
+  void ADTreeNode3Div :: operator delete (void * p)
+  {
+    ball.Free (p);
+  }
+
+
+
+
+
+
+
+  ADTree3Div :: ADTree3Div (const float * acmin, 
+			    const float * acmax)
+    : ela(0)
+  {
+    memcpy (cmin, acmin, 3 * sizeof(float));
+    memcpy (cmax, acmax, 3 * sizeof(float));
+
+    root = new ADTreeNode3Div;
+
+    root->minx = cmin[0];
+    root->dist = (cmax[0] - cmin[0]) / ADTN_DIV;
+
+    //  root->sep = (cmin[0] + cmax[0]) / 2;
+  }
+
+  ADTree3Div :: ~ADTree3Div ()
+  {
+    root->DeleteChilds();
+    delete root;
+  }
+
+
+  void ADTree3Div :: Insert (const float * p, int pi)
+  {
+    ADTreeNode3Div *node;
+    ADTreeNode3Div *next;
+    int dir;
+    int bag;
+  
+    float bmin[3];
+    float bmax[3];
+  
+    memcpy (bmin, cmin, 3 * sizeof(float));
+    memcpy (bmax, cmax, 3 * sizeof(float));
+
+
+    next = root;
+    dir = 0;
+    while (next)
+      {
+	node = next;
+
+	if (!node->pi)
+	  {    
+	    memcpy (node->data, p, 3 * sizeof(float));
+	    node->pi = pi;
+
+	    if (ela.Size() < pi)
+	      ela.SetSize (pi);
+	    ela.Elem(pi) = node;
+
+	    return;
+	  }
+
+	double dx = (bmax[dir] - bmin[dir]) / ADTN_DIV;
+	bag = int ((p[dir]-bmin[dir]) / dx);
+
+	//      (*testout) << "insert, bag = " << bag << endl;
+
+	if (bag < 0) bag = 0;
+	if (bag >= ADTN_DIV) bag = ADTN_DIV-1;
+      
+	double nbmin = bmin[dir] + bag * dx;
+	double nbmax = bmin[dir] + (bag+1) * dx;
+
+	/*      
+		(*testout) << "bmin, max = " << bmin[dir] << "-" << bmax[dir]
+		<< " p = " << p[dir];
+	*/
+	next = node->childs[bag];
+	bmin[dir] = nbmin;
+	bmax[dir] = nbmax;
+
+	//      (*testout) << "new bmin, max = " << bmin[dir] << "-" << bmax[dir] << endl;
+
+      
+	/*      
+		if (node->sep > p[dir])
+		{
+		next = node->left;
+		bmax[dir] = node->sep;
+		lr = 0;
+		}
+		else
+		{
+		next = node->right;
+		bmin[dir] = node->sep;
+		lr = 1;
+		}
+	*/
+
+	dir++;
+	if (dir == 3)
+	  dir = 0;
+      }
+
+
+    next = new ADTreeNode3Div;
+    memcpy (next->data, p, 3 * sizeof(float));
+    next->pi = pi;
+
+    next->minx = bmin[dir];
+    next->dist = (bmax[dir] - bmin[dir]) / ADTN_DIV;
+    //  next->sep = (bmin[dir] + bmax[dir]) / 2;
+
+
+    if (ela.Size() < pi)
+      ela.SetSize (pi);
+    ela.Elem(pi) = next;
+
+    node->childs[bag] = next;
+    next -> father = node;
+
+    while (node)
+      {
+	node->nchilds++;
+	node = node->father;
+      }
+  }
+
+  void ADTree3Div :: DeleteElement (int pi)
+  {
+    ADTreeNode3Div * node = ela.Get(pi);
+
+    node->pi = 0;
+
+    node = node->father;
+    while (node)
+      {
+	node->nchilds--;
+	node = node->father;
+      }
+  }
+
+  void ADTree3Div :: GetIntersecting (const float * bmin, 
+				      const float * bmax,
+				      ARRAY<int> & pis) const
+  {
+    static ARRAY<ADTreeNode3Div*> stack(1000);
+    static ARRAY<int> stackdir(1000);
+    ADTreeNode3Div * node;
+    int dir, i, stacks;
+
+    stack.SetSize (1000);
+    stackdir.SetSize(1000);
+    pis.SetSize(0);
+
+    stack.Elem(1) = root;
+    stackdir.Elem(1) = 0;
+    stacks = 1;
+
+    while (stacks)
+      {
+	node = stack.Get(stacks);
+	dir = stackdir.Get(stacks); 
+	stacks--;
+
+	if (node->pi)
+	  {
+	    if (node->data[0] >= bmin[0] && node->data[0] <= bmax[0] &&
+		node->data[1] >= bmin[1] && node->data[1] <= bmax[1] &&
+		node->data[2] >= bmin[2] && node->data[2] <= bmax[2])
+
+	      pis.Append (node->pi);
+	  }
+
+
+	int ndir = dir+1;
+	if (ndir == 3)
+	  ndir = 0;
+
+	int mini = int ( (bmin[dir] - node->minx) / node->dist );
+	int maxi = int ( (bmax[dir] - node->minx) / node->dist );
+      
+	//      (*testout) << "get int, mini, maxi = " << mini << ", " << maxi << endl;
+	if (mini < 0) mini = 0;
+	if (maxi >= ADTN_DIV) maxi = ADTN_DIV-1;
+
+	for (i = mini; i <= maxi; i++)
+	  if (node->childs[i])
+	    {
+	      stacks++;
+	      stack.Elem(stacks) = node->childs[i];
+	      stackdir.Elem(stacks) = ndir;
+	    }
+
+
+	/*
+	  if (node->left && bmin[dir] <= node->sep)
+	  {
+	  stacks++;
+	  stack.Elem(stacks) = node->left;
+	  stackdir.Elem(stacks) = ndir;
+	  }
+	  if (node->right && bmax[dir] >= node->sep)
+	  {
+	  stacks++;
+	  stack.Elem(stacks) = node->right;
+	  stackdir.Elem(stacks) = ndir;
+	  }
+	*/
+      }
+  }
+
+  void ADTree3Div :: PrintRec (ostream & ost, const ADTreeNode3Div * node) const
+  {
+  
+    if (node->data)
+      {
+	ost << node->pi << ": ";
+	ost << node->nchilds << " childs, ";
+	ost << " from " << node->minx << " - " << node->minx + node->dist*ADTN_DIV << "  ";
+	for (int i = 0; i < 3; i++)
+	  ost << node->data[i] << " ";
+	ost << endl;
+      }
+    int i;
+    for (i = 0; i < ADTN_DIV; i++)
+      if (node->childs[i])
+	PrintRec (ost, node->childs[i]);
+  }
+
+
+
+
+
+
+
+
+
+
+
+
+  /* ******************************* ADTree3M ******************************* */
+
+
+  ADTreeNode3M :: ADTreeNode3M()
+  {
+    int i;
+    for (i = 0; i < ADTN_SIZE; i++)
+      pi[i] = 0;
+
+    left = NULL;
+    right = NULL;
+    father = NULL;
+    nchilds = 0;
+  }
+
+  void ADTreeNode3M :: DeleteChilds ()
+  {
+    if (left)
+      {
+	left->DeleteChilds();
+	delete left;
+	left = NULL;
+      }
+    if (right)
+      {
+	right->DeleteChilds();
+	delete right;
+	right = NULL;
+      }
+  }
+
+
+  BlockAllocator ADTreeNode3M :: ball(sizeof (ADTreeNode3M));
+
+  void * ADTreeNode3M :: operator new(size_t)
+  {
+    return ball.Alloc();
+  }
+
+  void ADTreeNode3M :: operator delete (void * p)
+  {
+    ball.Free (p);
+  }
+
+
+
+
+
+
+
+  ADTree3M :: ADTree3M (const float * acmin, 
+			const float * acmax)
+    : ela(0)
+  {
+    memcpy (cmin, acmin, 3 * sizeof(float));
+    memcpy (cmax, acmax, 3 * sizeof(float));
+
+    root = new ADTreeNode3M;
+    root->sep = (cmin[0] + cmax[0]) / 2;
+  }
+
+  ADTree3M :: ~ADTree3M ()
+  {
+    root->DeleteChilds();
+    delete root;
+  }
+
+
+  void ADTree3M :: Insert (const float * p, int pi)
+  {
+    ADTreeNode3M *node;
+    ADTreeNode3M *next;
+    int dir;
+    int lr;
+    int i;
+    float bmin[3];
+    float bmax[3];
+  
+    memcpy (bmin, cmin, 3 * sizeof(float));
+    memcpy (bmax, cmax, 3 * sizeof(float));
+
+    next = root;
+    dir = 0;
+    while (next)
+      {
+	node = next;
+
+	for (i = 0; i < ADTN_SIZE; i++)
+	  if (!node->pi[i])
+	    {    
+	      memcpy (node->data[i], p, 3 * sizeof(float));
+	      node->pi[i] = pi;
+	    
+	      if (ela.Size() < pi)
+		ela.SetSize (pi);
+	      ela.Elem(pi) = node;
+	    
+	      return;
+	    }
+
+	if (node->sep > p[dir])
+	  {
+	    next = node->left;
+	    bmax[dir] = node->sep;
+	    lr = 0;
+	  }
+	else
+	  {
+	    next = node->right;
+	    bmin[dir] = node->sep;
+	    lr = 1;
+	  }
+
+	dir++;
+	if (dir == 3)
+	  dir = 0;
+      }
+
+
+    next = new ADTreeNode3M;
+    memcpy (next->data[0], p, 3 * sizeof(float));
+    next->pi[0] = pi;
+    next->sep = (bmin[dir] + bmax[dir]) / 2;
+
+
+    if (ela.Size() < pi)
+      ela.SetSize (pi);
+    ela.Elem(pi) = next;
+
+
+    if (lr)
+      node->right = next;
+    else
+      node->left = next;
+    next -> father = node;
+
+    while (node)
+      {
+	node->nchilds++;
+	node = node->father;
+      }
+  }
+
+  void ADTree3M :: DeleteElement (int pi)
+  {
+    ADTreeNode3M * node = ela.Get(pi);
+
+    int i;
+    for (i = 0; i < ADTN_SIZE; i++)
+      if (node->pi[i] == pi)
+	node->pi[i] = 0;
+
+    node = node->father;
+    while (node)
+      {
+	node->nchilds--;
+	node = node->father;
+      }
+  }
+
+  void ADTree3M :: GetIntersecting (const float * bmin, 
+				    const float * bmax,
+				    ARRAY<int> & pis) const
+  {
+    static ARRAY<ADTreeNode3M*> stack(1000);
+    static ARRAY<int> stackdir(1000);
+    ADTreeNode3M * node;
+    int dir, i, stacks;
+
+    stack.SetSize (1000);
+    stackdir.SetSize(1000);
+    pis.SetSize(0);
+
+    stack.Elem(1) = root;
+    stackdir.Elem(1) = 0;
+    stacks = 1;
+
+    while (stacks)
+      {
+	node = stack.Get(stacks);
+	dir = stackdir.Get(stacks); 
+	stacks--;
+
+	int * hpi = node->pi;
+	for (i = 0; i < ADTN_SIZE; i++)
+	  if (hpi[i])
+	    {
+	      float * datai = &node->data[i][0];
+	      if (datai[0] >= bmin[0] && datai[0] <= bmax[0] &&
+		  datai[1] >= bmin[1] && datai[1] <= bmax[1] &&
+		  datai[2] >= bmin[2] && datai[2] <= bmax[2])
+	      
+		pis.Append (node->pi[i]);
+	    }
+
+
+	int ndir = dir+1;
+	if (ndir == 3)
+	  ndir = 0;
+
+	if (node->left && bmin[dir] <= node->sep)
+	  {
+	    stacks++;
+	    stack.Elem(stacks) = node->left;
+	    stackdir.Elem(stacks) = ndir;
+	  }
+	if (node->right && bmax[dir] >= node->sep)
+	  {
+	    stacks++;
+	    stack.Elem(stacks) = node->right;
+	    stackdir.Elem(stacks) = ndir;
+	  }
+      }
+  }
+
+  void ADTree3M :: PrintRec (ostream & ost, const ADTreeNode3M * node) const
+  {
+  
+    if (node->data)
+      {
+	//      ost << node->pi << ": ";
+	ost << node->nchilds << " childs, ";
+	for (int i = 0; i < 3; i++)
+	  ost << node->data[i] << " ";
+	ost << endl;
+      }
+    if (node->left)
+      PrintRec (ost, node->left);
+    if (node->right)
+      PrintRec (ost, node->right);
+  }
+
+
+
+
+
+
+
+
+
+
+
+
+  /* ******************************* ADTree3F ******************************* */
+
+
+  ADTreeNode3F :: ADTreeNode3F()
+  {
+    pi = 0;
+    father = NULL;
+    nchilds = 0;
+    int i;
+    for (i = 0; i < 8; i++)
+      childs[i] = NULL;
+  }
+
+  void ADTreeNode3F :: DeleteChilds ()
+  {
+    int i;
+
+    for (i = 0; i < 8; i++)
+      {
+	if (childs[i])
+	  childs[i]->DeleteChilds();
+	delete childs[i];
+	childs[i] = NULL;
+      }
+  }
+
+
+  BlockAllocator ADTreeNode3F :: ball(sizeof (ADTreeNode3F));
+
+  void * ADTreeNode3F :: operator new(size_t)
+  {
+    return ball.Alloc();
+  }
+
+  void ADTreeNode3F :: operator delete (void * p)
+  {
+    ball.Free (p);
+  }
+
+
+
+
+
+
+
+  ADTree3F :: ADTree3F (const float * acmin, 
+			const float * acmax)
+    : ela(0)
+  {
+    memcpy (cmin, acmin, 3 * sizeof(float));
+    memcpy (cmax, acmax, 3 * sizeof(float));
+
+    root = new ADTreeNode3F;
+    for (int i = 0; i < 3; i++)
+      root->sep[i] = (cmin[i] + cmax[i]) / 2;
+  }
+
+  ADTree3F :: ~ADTree3F ()
+  {
+    root->DeleteChilds();
+    delete root;
+  }
+
+
+  void ADTree3F :: Insert (const float * p, int pi)
+  {
+    ADTreeNode3F *node;
+    ADTreeNode3F *next;
+    int lr;
+
+    float bmin[3];
+    float bmax[3];
+    int i, dir;
+  
+    memcpy (bmin, cmin, 3 * sizeof(float));
+    memcpy (bmax, cmax, 3 * sizeof(float));
+
+
+    next = root;
+    while (next)
+      {
+	node = next;
+      
+	if (!node->pi)
+	  {    
+	    memcpy (node->data, p, 3 * sizeof(float));
+	    node->pi = pi;
+
+	    if (ela.Size() < pi)
+	      ela.SetSize (pi);
+	    ela.Elem(pi) = node;
+
+	    return;
+	  }
+
+	dir = 0;
+	for (i = 0; i < 3; i++)
+	  {
+	    if (node->sep[i] > p[i])
+	      {
+		bmax[i] = node->sep[i];
+	      }
+	    else
+	      {
+		bmin[i] = node->sep[i];
+		dir += (1 << i);
+	      }
+	  }
+	next = node->childs[dir];
+
+	/*
+	  if (node->sep > p[dir])
+	  {
+	  next = node->left;
+	  bmax[dir] = node->sep;
+	  lr = 0;
+	  }
+	  else
+	  {
+	  next = node->right;
+	  bmin[dir] = node->sep;
+	  lr = 1;
+	  }
+	*/
+      }
+
+
+    next = new ADTreeNode3F;
+    memcpy (next->data, p, 3 * sizeof(float));
+    next->pi = pi;
+
+    for (i = 0; i < 3; i++)
+      next->sep[i] = (bmin[i] + bmax[i]) / 2;
+  
+
+    if (ela.Size() < pi)
+      ela.SetSize (pi);
+    ela.Elem(pi) = next;
+
+    node->childs[dir] = next;
+    next->father = node;
+
+    while (node)
+      {
+	node->nchilds++;
+	node = node->father;
+      }
+  }
+
+  void ADTree3F :: DeleteElement (int pi)
+  {
+    ADTreeNode3F * node = ela.Get(pi);
+
+    node->pi = 0;
+
+    node = node->father;
+    while (node)
+      {
+	node->nchilds--;
+	node = node->father;
+      }
+  }
+
+  void ADTree3F :: GetIntersecting (const float * bmin, 
+				    const float * bmax,
+				    ARRAY<int> & pis) const
+  {
+    static ARRAY<ADTreeNode3F*> stack(1000);
+    ADTreeNode3F * node;
+    int dir, i, stacks;
+
+    stack.SetSize (1000);
+    pis.SetSize(0);
+
+    stack.Elem(1) = root;
+    stacks = 1;
+
+    while (stacks)
+      {
+	node = stack.Get(stacks);
+	stacks--;
+
+	if (node->pi)
+	  {
+	    if (node->data[0] >= bmin[0] && node->data[0] <= bmax[0] &&
+		node->data[1] >= bmin[1] && node->data[1] <= bmax[1] &&
+		node->data[2] >= bmin[2] && node->data[2] <= bmax[2])
+
+	      pis.Append (node->pi);
+	  }
+
+      
+	int i1min = (bmin[0] <= node->sep[0]) ? 0 : 1;
+	int i1max = (bmax[0] < node->sep[0]) ? 0 : 1;
+	int i2min = (bmin[1] <= node->sep[1]) ? 0 : 1;
+	int i2max = (bmax[1] < node->sep[1]) ? 0 : 1;
+	int i3min = (bmin[2] <= node->sep[2]) ? 0 : 1;
+	int i3max = (bmax[2] < node->sep[2]) ? 0 : 1;
+
+	int i1, i2, i3;
+	for (i1 = i1min; i1 <= i1max; i1++)
+	  for (i2 = i2min; i2 <= i2max; i2++)
+	    for (i3 = i3min; i3 <= i3max; i3++)
+	      {
+		i = i1+2*i2+4*i3;
+		if (node->childs[i])
+		  {
+		    stacks++;
+		    stack.Elem(stacks) = node->childs[i];
+		  }
+	      }
+      
+	/*
+	  if (node->left && bmin[dir] <= node->sep)
+	  {
+	  stacks++;
+	  stack.Elem(stacks) = node->left;
+	  stackdir.Elem(stacks) = ndir;
+	  }
+	  if (node->right && bmax[dir] >= node->sep)
+	  {
+	  stacks++;
+	  stack.Elem(stacks) = node->right;
+	  stackdir.Elem(stacks) = ndir;
+	  }
+	*/
+      }
+  }
+
+  void ADTree3F :: PrintRec (ostream & ost, const ADTreeNode3F * node) const
+  {
+    int i;
+    if (node->data)
+      {
+	ost << node->pi << ": ";
+	ost << node->nchilds << " childs, ";
+	for (i = 0; i < 3; i++)
+	  ost << node->data[i] << " ";
+	ost << endl;
+      }
+
+    for (i = 0; i < 8; i++)
+      if (node->childs[i])
+	PrintRec (ost, node->childs[i]);
+  }
+
+
+
+
+
+
+
+
+
+
+
+
+
+  /* ******************************* ADTree3FM ******************************* */
+
+
+  ADTreeNode3FM :: ADTreeNode3FM()
+  {
+    father = NULL;
+    nchilds = 0;
+    int i;
+
+    for (i = 0; i < ADTN_SIZE; i++)
+      pi[i] = 0;
+
+    for (i = 0; i < 8; i++)
+      childs[i] = NULL;
+  }
+
+  void ADTreeNode3FM :: DeleteChilds ()
+  {
+    int i;
+
+    for (i = 0; i < 8; i++)
+      {
+	if (childs[i])
+	  childs[i]->DeleteChilds();
+	delete childs[i];
+	childs[i] = NULL;
+      }
+  }
+
+
+  BlockAllocator ADTreeNode3FM :: ball(sizeof (ADTreeNode3FM));
+
+  void * ADTreeNode3FM :: operator new(size_t)
+  {
+    return ball.Alloc();
+  }
+
+  void ADTreeNode3FM :: operator delete (void * p)
+  {
+    ball.Free (p);
+  }
+
+
+
+
+
+
+
+  ADTree3FM :: ADTree3FM (const float * acmin, 
+			  const float * acmax)
+    : ela(0)
+  {
+    memcpy (cmin, acmin, 3 * sizeof(float));
+    memcpy (cmax, acmax, 3 * sizeof(float));
+
+    root = new ADTreeNode3FM;
+    for (int i = 0; i < 3; i++)
+      root->sep[i] = (cmin[i] + cmax[i]) / 2;
+  }
+
+  ADTree3FM :: ~ADTree3FM ()
+  {
+    root->DeleteChilds();
+    delete root;
+  }
+
+
+  void ADTree3FM :: Insert (const float * p, int pi)
+  {
+    ADTreeNode3FM *node;
+    ADTreeNode3FM *next;
+    int lr;
+
+    float bmin[3];
+    float bmax[3];
+    int i, dir;
+  
+    memcpy (bmin, cmin, 3 * sizeof(float));
+    memcpy (bmax, cmax, 3 * sizeof(float));
+
+    next = root;
+    while (next)
+      {
+	node = next;
+      
+	for (i = 0; i < ADTN_SIZE; i++)
+	  if (!node->pi[i])
+	    {    
+	      memcpy (node->data[i], p, 3 * sizeof(float));
+	      node->pi[i] = pi;
+	    
+	      if (ela.Size() < pi)
+		ela.SetSize (pi);
+	      ela.Elem(pi) = node;
+	    
+	      return;
+	    }
+
+	dir = 0;
+	for (i = 0; i < 3; i++)
+	  {
+	    if (node->sep[i] > p[i])
+	      {
+		bmax[i] = node->sep[i];
+	      }
+	    else
+	      {
+		bmin[i] = node->sep[i];
+		dir += (1 << i);
+	      }
+	  }
+	next = node->childs[dir];
+
+	/*
+	  if (node->sep > p[dir])
+	  {
+	  next = node->left;
+	  bmax[dir] = node->sep;
+	  lr = 0;
+	  }
+	  else
+	  {
+	  next = node->right;
+	  bmin[dir] = node->sep;
+	  lr = 1;
+	  }
+	*/
+      }
+
+
+    next = new ADTreeNode3FM;
+    memcpy (next->data[0], p, 3 * sizeof(float));
+    next->pi[0] = pi;
+
+    for (i = 0; i < 3; i++)
+      next->sep[i] = (bmin[i] + bmax[i]) / 2;
+  
+
+    if (ela.Size() < pi)
+      ela.SetSize (pi);
+    ela.Elem(pi) = next;
+
+    node->childs[dir] = next;
+    next->father = node;
+
+    while (node)
+      {
+	node->nchilds++;
+	node = node->father;
+      }
+  }
+
+  void ADTree3FM :: DeleteElement (int pi)
+  {
+    ADTreeNode3FM * node = ela.Get(pi);
+
+    int i;
+    for (i = 0; i < ADTN_SIZE; i++)
+      if (node->pi[i] == pi)
+	node->pi[i] = 0;
+
+    node = node->father;
+    while (node)
+      {
+	node->nchilds--;
+	node = node->father;
+      }
+  }
+
+  void ADTree3FM :: GetIntersecting (const float * bmin, 
+				     const float * bmax,
+				     ARRAY<int> & pis) const
+  {
+    static ARRAY<ADTreeNode3FM*> stack(1000);
+    ADTreeNode3FM * node;
+    int dir, i, stacks;
+
+    stack.SetSize (1000);
+    pis.SetSize(0);
+
+    stack.Elem(1) = root;
+    stacks = 1;
+
+    while (stacks)
+      {
+	node = stack.Get(stacks);
+	stacks--;
+
+	int * hpi = node->pi;
+	for (i = 0; i < ADTN_SIZE; i++)
+	  if (hpi[i])
+	    {
+	      float * datai = &node->data[i][0];
+	      if (datai[0] >= bmin[0] && datai[0] <= bmax[0] &&
+		  datai[1] >= bmin[1] && datai[1] <= bmax[1] &&
+		  datai[2] >= bmin[2] && datai[2] <= bmax[2])
+	      
+		pis.Append (node->pi[i]);
+	    }
+
+	/*
+	  if (node->pi)
+	  {
+	  if (node->data[0] >= bmin[0] && node->data[0] <= bmax[0] &&
+	  node->data[1] >= bmin[1] && node->data[1] <= bmax[1] &&
+	  node->data[2] >= bmin[2] && node->data[2] <= bmax[2])
+
+	  pis.Append (node->pi);
+	  }
+	*/
+      
+	int i1min = (bmin[0] <= node->sep[0]) ? 0 : 1;
+	int i1max = (bmax[0] < node->sep[0]) ? 0 : 1;
+	int i2min = (bmin[1] <= node->sep[1]) ? 0 : 1;
+	int i2max = (bmax[1] < node->sep[1]) ? 0 : 1;
+	int i3min = (bmin[2] <= node->sep[2]) ? 0 : 1;
+	int i3max = (bmax[2] < node->sep[2]) ? 0 : 1;
+
+	int i1, i2, i3;
+	for (i1 = i1min; i1 <= i1max; i1++)
+	  for (i2 = i2min; i2 <= i2max; i2++)
+	    for (i3 = i3min; i3 <= i3max; i3++)
+	      {
+		i = i1+2*i2+4*i3;
+		if (node->childs[i])
+		  {
+		    stacks++;
+		    stack.Elem(stacks) = node->childs[i];
+		  }
+	      }
+      
+	/*
+	  if (node->left && bmin[dir] <= node->sep)
+	  {
+	  stacks++;
+	  stack.Elem(stacks) = node->left;
+	  stackdir.Elem(stacks) = ndir;
+	  }
+	  if (node->right && bmax[dir] >= node->sep)
+	  {
+	  stacks++;
+	  stack.Elem(stacks) = node->right;
+	  stackdir.Elem(stacks) = ndir;
+	  }
+	*/
+      }
+  }
+
+  void ADTree3FM :: PrintRec (ostream & ost, const ADTreeNode3FM * node) const
+  {
+    int i;
+    if (node->data)
+      {
+	ost << node->pi << ": ";
+	ost << node->nchilds << " childs, ";
+	for (i = 0; i < 3; i++)
+	  ost << node->data[i] << " ";
+	ost << endl;
+      }
+
+    for (i = 0; i < 8; i++)
+      if (node->childs[i])
+	PrintRec (ost, node->childs[i]);
+  }
+
+
+
+
+#endif
+
+
+
+
+
+
+  /* ******************************* ADTree6 ******************************* */
+
+
+  ADTreeNode6 :: ADTreeNode6()
+  {
+    pi = -1;
+
+    left = NULL;
+    right = NULL;
+    father = NULL;
+    nchilds = 0;
+  }
+
+  void ADTreeNode6 :: DeleteChilds ()
+  {
+    if (left)
+      {
+	left->DeleteChilds();
+	delete left;
+	left = NULL;
+      }
+    if (right)
+      {
+	right->DeleteChilds();
+	delete right;
+	right = NULL;
+      }
+  }
+
+
+  BlockAllocator ADTreeNode6 :: ball (sizeof (ADTreeNode6));
+  void * ADTreeNode6 :: operator new(size_t)
+  {
+    return ball.Alloc();
+  }
+
+  void ADTreeNode6 :: operator delete (void * p)
+  {
+    ball.Free (p);
+  }
+
+
+
+
+
+  ADTree6 :: ADTree6 (const float * acmin, 
+		      const float * acmax)
+    : ela(0)
+  {
+    memcpy (cmin, acmin, 6 * sizeof(float));
+    memcpy (cmax, acmax, 6 * sizeof(float));
+
+    root = new ADTreeNode6;
+    root->sep = (cmin[0] + cmax[0]) / 2;
+  }
+
+  ADTree6 :: ~ADTree6 ()
+  {
+    root->DeleteChilds();
+    delete root;
+  }
+
+  void ADTree6 :: Insert (const float * p, int pi)
+  {
+    ADTreeNode6 *node(NULL);
+    ADTreeNode6 *next;
+    int dir;
+    int lr(0);
+
+    float bmin[6];
+    float bmax[6];
+
+  
+    memcpy (bmin, cmin, 6 * sizeof(float));
+    memcpy (bmax, cmax, 6 * sizeof(float));
+
+    next = root;
+    dir = 0;
+    while (next)
+      {
+	node = next;
+
+	if (node->pi == -1)
+	  {    
+	    memcpy (node->data, p, 6 * sizeof(float));
+	    node->pi = pi;
+
+	    if (ela.Size() < pi+1)
+	      ela.SetSize (pi+1);
+	    ela[pi] = node;
+
+	    return;
+	  }
+
+	if (node->sep > p[dir])
+	  {
+	    next = node->left;
+	    bmax[dir] = node->sep;
+	    lr = 0;
+	  }
+	else
+	  {
+	    next = node->right;
+	    bmin[dir] = node->sep;
+	    lr = 1;
+	  }
+
+	dir++;
+	if (dir == 6) dir = 0;
+      }
+
+
+    next = new ADTreeNode6;
+    memcpy (next->data, p, 6 * sizeof(float));
+    next->pi = pi;
+    next->sep = (bmin[dir] + bmax[dir]) / 2;
+
+    if (ela.Size() < pi+1)
+      ela.SetSize (pi+1);
+    ela[pi] = next;
+
+    if (lr)
+      node->right = next;
+    else
+      node->left = next;
+    next -> father = node;
+
+    while (node)
+      {
+	node->nchilds++;
+	node = node->father;
+      }
+  }
+
+  void ADTree6 :: DeleteElement (int pi)
+  {
+    ADTreeNode6 * node = ela[pi];
+
+    node->pi = -1;
+
+    node = node->father;
+    while (node)
+      {
+	node->nchilds--;
+	node = node->father;
+      }
+  }
+
+  void ADTree6 :: PrintMemInfo (ostream & ost) const
+  {
+    ost << Elements() << " elements a " << sizeof(ADTreeNode6) 
+	<< " Bytes = "
+	<< Elements() * sizeof(ADTreeNode6) << endl;
+    ost << "maxind = " << ela.Size() << " = " << sizeof(ADTreeNode6*) * ela.Size() << " Bytes" << endl;
+  }
+
+
+
+  class inttn6 {
+  public:
+    int dir;
+    ADTreeNode6 * node;
+  };
+
+
+
+
+  void ADTree6 :: GetIntersecting (const float * bmin, 
+				   const float * bmax,
+				   ARRAY<int> & pis) const
+  {
+    static ARRAY<inttn6> stack(10000);
+
+    stack.SetSize (10000);
+    pis.SetSize(0);
+
+    stack[0].node = root;
+    stack[0].dir = 0;
+    int stacks = 0;
+
+    while (stacks >= 0)
+      {
+	ADTreeNode6 * node = stack[stacks].node;
+	int dir = stack[stacks].dir; 
+
+	stacks--;
+
+	if (node->pi != -1)
+	  {
+	    if (node->data[0] > bmax[0] || 
+		node->data[1] > bmax[1] || 
+		node->data[2] > bmax[2] || 
+		node->data[3] < bmin[3] || 
+		node->data[4] < bmin[4] || 
+		node->data[5] < bmin[5])
+	      ;
+	    else
+	      pis.Append (node->pi);
+	  }
+
+	int ndir = (dir+1) % 6;
+
+	if (node->left && bmin[dir] <= node->sep)
+	  {
+	    stacks++;
+	    stack[stacks].node = node->left;
+	    stack[stacks].dir = ndir;
+	  }
+	if (node->right && bmax[dir] >= node->sep)
+	  {
+	    stacks++;
+	    stack[stacks].node = node->right;
+	    stack[stacks].dir = ndir;
+	  }
+      }
+  }
+
+  void ADTree6 :: PrintRec (ostream & ost, const ADTreeNode6 * node) const
+  {
+  
+    if (node->data)
+      {
+	ost << node->pi << ": ";
+	ost << node->nchilds << " childs, ";
+	for (int i = 0; i < 6; i++)
+	  ost << node->data[i] << " ";
+	ost << endl;
+      }
+    if (node->left)
+      PrintRec (ost, node->left);
+    if (node->right)
+      PrintRec (ost, node->right);
+  }
+
+
+  int ADTree6 :: DepthRec (const ADTreeNode6 * node) const
+  {
+    int ldepth = 0;
+    int rdepth = 0;
+
+    if (node->left)
+      ldepth = DepthRec(node->left);
+    if (node->right)
+      rdepth = DepthRec(node->right);
+    return 1 + max2 (ldepth, rdepth);
+  }
+
+  int ADTree6 :: ElementsRec (const ADTreeNode6 * node) const
+  {
+    int els = 1;
+    if (node->left)
+      els += ElementsRec(node->left);
+    if (node->right)
+      els += ElementsRec(node->right);
+    return els;
+  }
+
+
+
+
+
+
+#ifdef ABC
+
+  /* ******************************* ADTree6F ******************************* */
+
+
+  ADTreeNode6F :: ADTreeNode6F()
+  {
+    pi = 0;
+    father = NULL;
+    nchilds = 0;
+    int i;
+    for (i = 0; i < 64; i++)
+      childs[i] = NULL;
+  }
+
+  void ADTreeNode6F :: DeleteChilds ()
+  {
+    int i;
+
+    for (i = 0; i < 64; i++)
+      {
+	if (childs[i])
+	  childs[i]->DeleteChilds();
+	delete childs[i];
+	childs[i] = NULL;
+      }
+  }
+
+
+  BlockAllocator ADTreeNode6F :: ball(sizeof (ADTreeNode6F));
+
+  void * ADTreeNode6F :: operator new(size_t)
+  {
+    return ball.Alloc();
+  }
+
+  void ADTreeNode6F :: operator delete (void * p)
+  {
+    ball.Free (p);
+  }
+
+
+
+
+
+
+
+  ADTree6F :: ADTree6F (const float * acmin, 
+			const float * acmax)
+    : ela(0)
+  {
+    memcpy (cmin, acmin, 6 * sizeof(float));
+    memcpy (cmax, acmax, 6 * sizeof(float));
+
+    root = new ADTreeNode6F;
+    for (int i = 0; i < 6; i++)
+      root->sep[i] = (cmin[i] + cmax[i]) / 2;
+  }
+
+  ADTree6F :: ~ADTree6F ()
+  {
+    root->DeleteChilds();
+    delete root;
+  }
+
+
+  void ADTree6F :: Insert (const float * p, int pi)
+  {
+    ADTreeNode6F *node;
+    ADTreeNode6F *next;
+    int lr;
+
+    float bmin[6];
+    float bmax[6];
+    int i, dir;
+  
+    memcpy (bmin, cmin, 6 * sizeof(float));
+    memcpy (bmax, cmax, 6 * sizeof(float));
+
+    next = root;
+    while (next)
+      {
+	node = next;
+      
+	if (!node->pi)
+	  {    
+	    memcpy (node->data, p, 6 * sizeof(float));
+	    node->pi = pi;
+
+	    if (ela.Size() < pi)
+	      ela.SetSize (pi);
+	    ela.Elem(pi) = node;
+
+	    return;
+	  }
+
+	dir = 0;
+	for (i = 0; i < 6; i++)
+	  {
+	    if (node->sep[i] > p[i])
+	      {
+		bmax[i] = node->sep[i];
+	      }
+	    else
+	      {
+		bmin[i] = node->sep[i];
+		dir += (1 << i);
+	      }
+	  }
+	next = node->childs[dir];
+
+	/*
+	  if (node->sep > p[dir])
+	  {
+	  next = node->left;
+	  bmax[dir] = node->sep;
+	  lr = 0;
+	  }
+	  else
+	  {
+	  next = node->right;
+	  bmin[dir] = node->sep;
+	  lr = 1;
+	  }
+	*/
+      }
+
+
+    next = new ADTreeNode6F;
+    memcpy (next->data, p, 6 * sizeof(float));
+    next->pi = pi;
+
+    for (i = 0; i < 6; i++)
+      next->sep[i] = (bmin[i] + bmax[i]) / 2;
+  
+
+    if (ela.Size() < pi)
+      ela.SetSize (pi);
+    ela.Elem(pi) = next;
+
+    node->childs[dir] = next;
+    next->father = node;
+
+    while (node)
+      {
+	node->nchilds++;
+	node = node->father;
+      }
+  }
+
+  void ADTree6F :: DeleteElement (int pi)
+  {
+    ADTreeNode6F * node = ela.Get(pi);
+
+    node->pi = 0;
+
+    node = node->father;
+    while (node)
+      {
+	node->nchilds--;
+	node = node->father;
+      }
+  }
+
+  void ADTree6F :: GetIntersecting (const float * bmin, 
+				    const float * bmax,
+				    ARRAY<int> & pis) const
+  {
+    static ARRAY<ADTreeNode6F*> stack(1000);
+    ADTreeNode6F * node;
+    int dir, i, stacks;
+
+    stack.SetSize (1000);
+    pis.SetSize(0);
+
+    stack.Elem(1) = root;
+    stacks = 1;
+
+    while (stacks)
+      {
+	node = stack.Get(stacks);
+	stacks--;
+
+	if (node->pi)
+	  {
+	    if (
+		node->data[0] >= bmin[0] && node->data[0] <= bmax[0] &&
+		node->data[1] >= bmin[1] && node->data[1] <= bmax[1] &&
+		node->data[2] >= bmin[2] && node->data[2] <= bmax[2] &&
+		node->data[3] >= bmin[3] && node->data[3] <= bmax[3] &&
+		node->data[4] >= bmin[4] && node->data[4] <= bmax[4] &&
+		node->data[5] >= bmin[5] && node->data[5] <= bmax[5]
+		)
+
+	      pis.Append (node->pi);
+	  }
+
+      
+	int i1min = (bmin[0] <= node->sep[0]) ? 0 : 1;
+	int i1max = (bmax[0] < node->sep[0]) ? 0 : 1;
+	int i2min = (bmin[1] <= node->sep[1]) ? 0 : 1;
+	int i2max = (bmax[1] < node->sep[1]) ? 0 : 1;
+	int i3min = (bmin[2] <= node->sep[2]) ? 0 : 1;
+	int i3max = (bmax[2] < node->sep[2]) ? 0 : 1;
+
+	int i4min = (bmin[3] <= node->sep[3]) ? 0 : 1;
+	int i4max = (bmax[3] <  node->sep[3]) ? 0 : 1;
+	int i5min = (bmin[4] <= node->sep[4]) ? 0 : 1;
+	int i5max = (bmax[4] <  node->sep[4]) ? 0 : 1;
+	int i6min = (bmin[5] <= node->sep[5]) ? 0 : 1;
+	int i6max = (bmax[5] <  node->sep[5]) ? 0 : 1;
+
+	int i1, i2, i3, i4, i5, i6;
+	for (i1 = i1min; i1 <= i1max; i1++)
+	  for (i2 = i2min; i2 <= i2max; i2++)
+	    for (i3 = i3min; i3 <= i3max; i3++)
+	      for (i4 = i4min; i4 <= i4max; i4++)
+		for (i5 = i5min; i5 <= i5max; i5++)
+		  for (i6 = i6min; i6 <= i6max; i6++)
+		    {
+		      i = i1 + 2*i2 + 4*i3 + 8*i4 + 16*i5 +32*i6;
+		      if (node->childs[i])
+			{
+			  stacks++;
+			  stack.Elem(stacks) = node->childs[i];
+			}
+		    }
+      
+	/*
+	  if (node->left && bmin[dir] <= node->sep)
+	  {
+	  stacks++;
+	  stack.Elem(stacks) = node->left;
+	  stackdir.Elem(stacks) = ndir;
+	  }
+	  if (node->right && bmax[dir] >= node->sep)
+	  {
+	  stacks++;
+	  stack.Elem(stacks) = node->right;
+	  stackdir.Elem(stacks) = ndir;
+	  }
+	*/
+      }
+  }
+
+  void ADTree6F :: PrintRec (ostream & ost, const ADTreeNode6F * node) const
+  {
+    int i;
+    if (node->data)
+      {
+	ost << node->pi << ": ";
+	ost << node->nchilds << " childs, ";
+	for (i = 0; i < 6; i++)
+	  ost << node->data[i] << " ";
+	ost << endl;
+      }
+
+    for (i = 0; i < 64; i++)
+      if (node->childs[i])
+	PrintRec (ost, node->childs[i]);
+  }
+
+
+
+#endif
+
+
+
+  /* ************************************* Point3dTree ********************** */
+
+
+
+  Point3dTree :: Point3dTree (const Point3d & pmin, const Point3d & pmax)
+  {
+    float pmi[3], pma[3];
+    for (int i = 0; i < 3; i++)
+      {
+	pmi[i] = pmin.X(i+1);
+	pma[i] = pmax.X(i+1);
+      }
+    tree = new ADTree3 (pmi, pma);
+  }
+
+  Point3dTree :: ~Point3dTree ()
+  {
+    delete tree;
+  }
+
+
+
+  void Point3dTree :: Insert (const Point3d & p, int pi)
+  {
+    static float pd[3];
+    pd[0] = p.X();
+    pd[1] = p.Y();
+    pd[2] = p.Z();
+    tree->Insert (pd, pi);
+  }
+
+  void Point3dTree :: GetIntersecting (const Point3d & pmin, const Point3d & pmax, 
+				       ARRAY<int> & pis) const
+  {
+    float pmi[3], pma[3];
+    for (int i = 0; i < 3; i++)
+      {
+	pmi[i] = pmin.X(i+1);
+	pma[i] = pmax.X(i+1);
+      }
+    tree->GetIntersecting (pmi, pma, pis);
+  }
+
+
+
+
+
+
+
+
+
+
+  Box3dTree :: Box3dTree (const Point3d & apmin, const Point3d & apmax)
+  {
+    boxpmin = apmin;
+    boxpmax = apmax;
+    float tpmin[6], tpmax[6];
+    for (int i = 0; i < 3; i++)
+      {
+	tpmin[i] = tpmin[i+3] = boxpmin.X(i+1);
+	tpmax[i] = tpmax[i+3] = boxpmax.X(i+1);
+      }
+    tree = new ADTree6 (tpmin, tpmax);
+  }
+
+  Box3dTree :: ~Box3dTree ()
+  {
+    delete tree;
+  }
+
+  void Box3dTree :: Insert (const Point3d & bmin, const Point3d & bmax, int pi)
+  {
+    static float tp[6];
+
+    for (int i = 0; i < 3; i++)
+      {
+	tp[i] = bmin.X(i+1);
+	tp[i+3] = bmax.X(i+1);
+      }
+
+    tree->Insert (tp, pi);
+  }
+
+  void Box3dTree ::GetIntersecting (const Point3d & pmin, const Point3d & pmax, 
+				    ARRAY<int> & pis) const
+  {
+    float tpmin[6];
+    float tpmax[6];
+
+    for (int i = 0; i < 3; i++)
+      {
+	tpmin[i] = boxpmin.X(i+1);
+	tpmax[i] = pmax.X(i+1);
+      
+	tpmin[i+3] = pmin.X(i+1);
+	tpmax[i+3] = boxpmax.X(i+1);
+      }
+
+    tree->GetIntersecting (tpmin, tpmax, pis);
+  }
+
+}
diff --git a/contrib/Netgen/libsrc/gprim/adtree.hpp b/contrib/Netgen/libsrc/gprim/adtree.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..4cac0f2945d90707dd765cc17e78c707674cd822
--- /dev/null
+++ b/contrib/Netgen/libsrc/gprim/adtree.hpp
@@ -0,0 +1,481 @@
+#ifndef FILE_ADTREE
+#define FILE_ADTREE
+
+/* *************************************************************************/
+/* File:   adtree.hh                                                       */
+/* Author: Joachim Schoeberl                                               */
+/* Date:   16. Feb. 98                                                     */
+/* Redesigned by Wolfram Muehlhuber, May 1998                              */
+/* *************************************************************************/
+
+
+
+/**
+  Alternating Digital Tree
+ */
+
+#include "../include/mystdlib.h"
+#include "../include/myadt.hpp"
+
+class ADTreeNode
+{
+public:
+  ADTreeNode *left, *right, *father;
+  int dim;
+  float sep;
+  float *data;
+  float *boxmin;
+  float *boxmax;
+  int pi;
+  int nchilds;
+
+  ADTreeNode (int adim);
+  ~ADTreeNode ();
+
+  friend class ADTree;
+};
+
+
+class ADTreeCriterion
+{
+public:
+  ADTreeCriterion() { }
+  virtual int Eval (const ADTreeNode * node) const = 0;
+};
+
+
+class ADTree
+{
+  int dim;
+  ADTreeNode * root;
+  float *cmin, *cmax;
+  ARRAY<ADTreeNode*> ela;
+  const ADTreeCriterion * criterion; 
+
+  ARRAY<ADTreeNode*> stack;
+  ARRAY<int> stackdir;
+  int stackindex;
+
+public:
+  ADTree (int adim, const float * acmin, 
+	   const float * acmax);
+  ~ADTree ();
+
+  void Insert (const float * p, int pi);
+  // void GetIntersecting (const float * bmin, const float * bmax,
+  //			ARRAY<int> & pis) const;
+  void SetCriterion (ADTreeCriterion & acriterion);
+  void Reset ();
+  int Next ();
+  void GetMatch (ARRAY<int> & matches);
+
+  void DeleteElement (int pi);
+
+
+  void Print (ostream & ost) const
+    { PrintRec (ost, root); }
+
+  void PrintRec (ostream & ost, const ADTreeNode * node) const;
+};
+
+
+
+class ADTreeNode3
+{
+public:
+  ADTreeNode3 *left, *right, *father;
+  float sep;
+  float data[3];
+  int pi;
+  int nchilds;
+
+  ADTreeNode3 ();
+  void DeleteChilds ();
+  friend class ADTree3;
+
+  static BlockAllocator ball;
+  void * operator new(size_t);
+  void operator delete (void *);
+};
+
+
+class ADTree3
+{
+  ADTreeNode3 * root;
+  float cmin[3], cmax[3];
+  ARRAY<ADTreeNode3*> ela;
+
+public:
+  ADTree3 (const float * acmin, 
+	   const float * acmax);
+  ~ADTree3 ();
+
+  void Insert (const float * p, int pi);
+  void GetIntersecting (const float * bmin, const float * bmax,
+			ARRAY<int> & pis) const;
+  
+  void DeleteElement (int pi);
+
+
+  void Print (ostream & ost) const
+    { PrintRec (ost, root); }
+
+  void PrintRec (ostream & ost, const ADTreeNode3 * node) const;
+};
+
+
+/*
+
+// divide each direction
+#define ADTN_DIV 10
+class ADTreeNode3Div
+{
+public:
+  ADTreeNode3Div *father;
+  ADTreeNode3Div *childs[ADTN_DIV];
+
+  float minx, dist;
+  float data[3];
+  int pi;
+  int nchilds;
+
+  ADTreeNode3Div ();
+  void DeleteChilds ();
+  friend class ADTree3Div;
+
+  static BlockAllocator ball;
+  void * operator new(size_t);
+  void operator delete (void *);
+};
+
+
+class ADTree3Div
+{
+  ADTreeNode3Div * root;
+  float cmin[3], cmax[3];
+  ARRAY<ADTreeNode3Div*> ela;
+
+public:
+  ADTree3Div (const float * acmin, 
+	   const float * acmax);
+  ~ADTree3Div ();
+
+  void Insert (const float * p, int pi);
+  void GetIntersecting (const float * bmin, const float * bmax,
+			ARRAY<int> & pis) const;
+  
+  void DeleteElement (int pi);
+
+
+  void Print (ostream & ost) const
+    { PrintRec (ost, root); }
+
+  void PrintRec (ostream & ost, const ADTreeNode3Div * node) const;
+};
+
+
+
+
+#define ADTN_SIZE 10
+
+// multiple entries
+class ADTreeNode3M
+{
+public:
+  ADTreeNode3M *left, *right, *father;
+  float sep;
+  float data[ADTN_SIZE][3];
+  int pi[ADTN_SIZE];
+  int nchilds;
+
+  ADTreeNode3M ();
+  void DeleteChilds ();
+  friend class ADTree3M;
+
+  static BlockAllocator ball;
+  void * operator new(size_t);
+  void operator delete (void *);
+};
+
+
+class ADTree3M
+{
+  ADTreeNode3M * root;
+  float cmin[3], cmax[3];
+  ARRAY<ADTreeNode3M*> ela;
+
+public:
+  ADTree3M (const float * acmin, 
+	   const float * acmax);
+  ~ADTree3M ();
+
+  void Insert (const float * p, int pi);
+  void GetIntersecting (const float * bmin, const float * bmax,
+			ARRAY<int> & pis) const;
+  
+  void DeleteElement (int pi);
+
+
+  void Print (ostream & ost) const
+    { PrintRec (ost, root); }
+
+  void PrintRec (ostream & ost, const ADTreeNode3M * node) const;
+};
+
+
+
+
+
+
+class ADTreeNode3F
+{
+public:
+  ADTreeNode3F *father;
+  ADTreeNode3F *childs[8];
+  float sep[3];
+  float data[3];
+  int pi;
+  int nchilds;
+
+  ADTreeNode3F ();
+  void DeleteChilds ();
+  friend class ADTree3F;
+
+  static BlockAllocator ball;
+  void * operator new(size_t);
+  void operator delete (void *);
+};
+
+// fat tree
+class ADTree3F
+{
+  ADTreeNode3F * root;
+  float cmin[3], cmax[3];
+  ARRAY<ADTreeNode3F*> ela;
+
+public:
+  ADTree3F (const float * acmin, 
+	   const float * acmax);
+  ~ADTree3F ();
+
+  void Insert (const float * p, int pi);
+  void GetIntersecting (const float * bmin, const float * bmax,
+			ARRAY<int> & pis) const;
+  
+  void DeleteElement (int pi);
+
+
+  void Print (ostream & ost) const
+    { PrintRec (ost, root); }
+
+  void PrintRec (ostream & ost, const ADTreeNode3F * node) const;
+};
+
+
+
+
+class ADTreeNode3FM
+{
+public:
+  ADTreeNode3FM *father;
+  ADTreeNode3FM *childs[8];
+  float sep[3];
+  float data[ADTN_SIZE][3];
+  int pi[ADTN_SIZE];
+  int nchilds;
+
+  ADTreeNode3FM ();
+  void DeleteChilds ();
+  friend class ADTree3FM;
+
+  static BlockAllocator ball;
+  void * operator new(size_t);
+  void operator delete (void *);
+};
+
+// fat tree
+class ADTree3FM
+{
+  ADTreeNode3FM * root;
+  float cmin[3], cmax[3];
+  ARRAY<ADTreeNode3FM*> ela;
+
+public:
+  ADTree3FM (const float * acmin, 
+	   const float * acmax);
+  ~ADTree3FM ();
+
+  void Insert (const float * p, int pi);
+  void GetIntersecting (const float * bmin, const float * bmax,
+			ARRAY<int> & pis) const;
+  
+  void DeleteElement (int pi);
+
+
+  void Print (ostream & ost) const
+    { PrintRec (ost, root); }
+
+  void PrintRec (ostream & ost, const ADTreeNode3FM * node) const;
+};
+
+
+
+*/
+
+
+
+
+
+class ADTreeNode6
+{
+public:
+  ADTreeNode6 *left, *right, *father;
+  float sep;
+  float data[6];
+  int pi;
+  int nchilds;
+
+  ADTreeNode6 ();
+  void DeleteChilds ();
+  friend class ADTree6;
+
+  static BlockAllocator ball;
+  void * operator new(size_t);
+  void operator delete (void *);
+};
+
+
+class ADTree6
+{
+  ADTreeNode6 * root;
+  float cmin[6], cmax[6];
+  ARRAY<ADTreeNode6*> ela;
+
+public:
+  ADTree6 (const float * acmin, 
+	   const float * acmax);
+  ~ADTree6 ();
+
+  void Insert (const float * p, int pi);
+  void GetIntersecting (const float * bmin, const float * bmax,
+			ARRAY<int> & pis) const;
+  
+  void DeleteElement (int pi);
+
+  
+  void Print (ostream & ost) const
+  { PrintRec (ost, root); }
+  int Depth () const
+  { return DepthRec (root); }
+  int Elements () const
+  { return ElementsRec (root); }
+
+  void PrintRec (ostream & ost, const ADTreeNode6 * node) const;
+  int DepthRec (const ADTreeNode6 * node) const;
+  int ElementsRec (const ADTreeNode6 * node) const;
+
+  void PrintMemInfo (ostream & ost) const;
+};
+
+
+
+
+/*
+
+class ADTreeNode6F
+{
+public:
+  ADTreeNode6F * father;
+  ADTreeNode6F * childs[64];
+  
+  float sep[6];
+  float data[6];
+  int pi;
+  int nchilds;
+
+  ADTreeNode6F ();
+  void DeleteChilds ();
+  friend class ADTree6F;
+
+  static BlockAllocator ball;
+  void * operator new(size_t);
+  void operator delete (void *);
+};
+
+
+class ADTree6F
+{
+  ADTreeNode6F * root;
+  float cmin[6], cmax[6];
+  ARRAY<ADTreeNode6F*> ela;
+
+public:
+  ADTree6F (const float * acmin, 
+	   const float * acmax);
+  ~ADTree6F ();
+
+  void Insert (const float * p, int pi);
+  void GetIntersecting (const float * bmin, const float * bmax,
+			ARRAY<int> & pis) const;
+  
+  void DeleteElement (int pi);
+
+
+  void Print (ostream & ost) const
+    { PrintRec (ost, root); }
+  int Depth () const
+    { return DepthRec (root); }
+
+  void PrintRec (ostream & ost, const ADTreeNode6F * node) const;
+  int DepthRec (const ADTreeNode6F * node) const;
+};
+
+
+
+
+
+
+
+*/
+
+
+
+
+
+class Point3dTree 
+{
+  ADTree3 * tree;
+
+public:
+  Point3dTree (const Point3d & pmin, const Point3d & pmax);
+  ~Point3dTree ();
+  void Insert (const Point3d & p, int pi);
+  void DeleteElement (int pi) 
+    { tree->DeleteElement(pi); }
+  void GetIntersecting (const Point3d & pmin, const Point3d & pmax, 
+			ARRAY<int> & pis) const;
+  const ADTree3 & Tree() const { return *tree; };
+};
+
+
+
+class Box3dTree
+{
+  ADTree6 * tree;
+  Point3d boxpmin, boxpmax;
+public:
+  Box3dTree (const Point3d & apmin, const Point3d & apmax);
+  ~Box3dTree ();
+  void Insert (const Point3d & bmin, const Point3d & bmax, int pi);
+  void Insert (const Box<3> & box, int pi)
+  {
+    Insert (box.PMin(), box.PMax(), pi);
+  }
+  void DeleteElement (int pi) 
+    { tree->DeleteElement(pi); }
+  void GetIntersecting (const Point3d & pmin, const Point3d & pmax, 
+			ARRAY<int> & pis) const;
+
+  const ADTree6 & Tree() const { return *tree; };
+};
+#endif
diff --git a/contrib/Netgen/libsrc/gprim/geom2d.cpp b/contrib/Netgen/libsrc/gprim/geom2d.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..34263348cc327ba2a652e6d7ec6c44c5af96018f
--- /dev/null
+++ b/contrib/Netgen/libsrc/gprim/geom2d.cpp
@@ -0,0 +1,489 @@
+#include <mystdlib.h>
+
+#include <myadt.hpp>
+#include <gprim.hpp>
+
+#ifndef M_PI
+#define M_PI        3.14159265358979323846
+#endif
+
+namespace netgen
+{
+
+ostream & operator<<(ostream  & s, const Point2d & p)
+{
+  return s << "(" << p.px << ", " << p.py << ")";
+}
+
+ostream & operator<<(ostream  & s, const Vec2d & v)
+{
+  return s << "(" << v.vx << ", " << v.vy << ")";
+}
+
+#ifdef none
+ostream & operator<<(ostream  & s, const Line2d & l)
+  {
+  return s << l.p1 << "-" << l.p2;
+}
+
+ostream & operator<<(ostream  & s, const TRIANGLE2D & t)
+{
+  return s << t.p1 << "-" << t.p2 << "-" << t.p3;
+}
+#endif
+
+
+double Fastatan2 (double x, double y)
+{
+  if (y > 0)
+    {
+      if (x > 0)
+	return y / (x+y);
+      else
+	return 1 - x / (y-x);
+    }
+  else if (y < 0)
+    {
+      if (x < 0)
+	return 2 + y / (x+y);
+      else
+	return 3 - x / (y-x);
+    }
+  else 
+    {
+      if (x >= 0)
+	return 0;
+      else
+	return 2;
+    }
+}
+
+
+double Angle (const Vec2d & v)
+{
+  if (v.X() == 0 && v.Y() == 0)
+    return 0;
+    
+  double ang = atan2 (v.Y(), v.X());
+  if (ang < 0) ang+= 2 * M_PI;
+  return ang;
+}
+
+double FastAngle (const Vec2d & v)
+{
+  return Fastatan2 (v.X(), v.Y());
+}
+
+double Angle (const Vec2d & v1, const Vec2d & v2)
+{
+  double ang = Angle(v2) - Angle(v1);
+  if (ang < 0) ang += 2 * M_PI;
+  return ang;
+}
+
+double FastAngle (const Vec2d & v1, const Vec2d & v2)
+{
+  double ang = FastAngle(v2) - FastAngle(v1);
+  if (ang < 0) ang += 4;
+  return ang;
+}
+
+/*
+int CW (const Point2d & p1,const Point2d & p2,const Point2d & p3)
+{
+  return Cross (p2 - p1, p3 - p2) < 0;
+}
+
+int CCW (const Point2d & p1,const Point2d & p2,const Point2d & p3)
+{
+  return Cross (p2 - p1, p3 - p2) > 0;
+}
+*/
+
+double  Dist2(const Line2d & g, const Line2d & h )
+  {
+  double   dd = 0.0, d1,d2,d3,d4;
+  Point2d  cp = CrossPoint(g,h);
+  
+  if ( Parallel(g,h) || !IsOnLine(g,cp) || !IsOnLine(h,cp) )
+    {
+      d1 = Dist2(g.P1(),h.P1());
+      d2 = Dist2(g.P1(),h.P2());
+      d3 = Dist2(g.P2(),h.P1());
+      d4 = Dist2(g.P2(),h.P2());
+      if (d1<d2)  d2 = d1;
+      if (d3<d4)  d4 = d3;
+      dd = ( d2 < d4 ) ? d2 : d4;
+    }
+  return dd;
+}
+
+
+Point2d CrossPoint (const Line2d & l1, const Line2d & l2)
+  {
+  double den = Cross (l1.Delta(), l2.Delta());
+  double num = Cross ( (l2.P1() - l1.P1()), l2.Delta());
+
+  if (den == 0)
+    return l1.P1();
+  else
+    return l1.P1() + (num/den) * l1.Delta();
+}
+
+
+int CrossPointBarycentric (const Line2d & l1, const Line2d & l2,
+			   double & lam1, double & lam2)
+{
+  // p = l1.1 + lam1 (l1.2-l1.1) = l2.1 + lam2 (l2.2-l2.1)
+  double a11 = l1.p2.X() - l1.p1.X();
+  double a21 = l1.p2.Y() - l1.p1.Y();
+  double a12 = -(l2.p2.X() - l2.p1.X());
+  double a22 = -(l2.p2.Y() - l2.p1.Y());
+
+  double b1 = l2.p1.X() - l1.p1.X();
+  double b2 = l2.p1.Y() - l1.p1.Y();
+  
+  double det = a11*a22 - a12 * a21;
+  if (det == 0)
+    return 1;
+    
+  lam1 = (a22 * b1 - a12 * b2) / det;
+  lam2 = (a11 * b2 - a21 * b1) / det;
+  return 0;
+}
+
+
+
+
+int Parallel (const Line2d & l1, const Line2d & l2, double peps)
+  {
+  double p = fabs (Cross (l1.Delta(), l2.Delta()));
+  //  (*mycout) << endl << p << "  " <<  l1.Length() << "  " << l2.Length() << endl;
+  return p <= peps * l1.Length() * l2.Length();
+}
+
+int IsOnLine (const Line2d & l, const Point2d & p, double heps)
+  {
+  double c1 = (p - l.P1()) * l.Delta();
+  double c2 = (p - l.P2()) * l.Delta();
+  double d = fabs (Cross ( (p - l.P1()), l.Delta()));
+  double len2 = l.Length2();
+
+  return c1 >= -heps * len2 && c2 <= heps * len2 && d <= heps * len2;
+}
+
+#ifdef none
+int IsOnLine (const PLine2d & l, const Point2d & p, double heps)
+  {
+  double c1 = (p - l.P1()) * l.Delta();
+  double c2 = (p - l.P2()) * l.Delta();
+  double d = fabs (Cross ( (p - l.P1()), l.Delta()));
+  double len2 = l.Length2();
+
+  return c1 >= -heps * len2 && c2 <= heps * len2 && d <= heps * len2;
+}
+
+int IsOnLongLine (const Line2d & l, const Point2d & p)
+  {
+  double d = fabs (Cross ( (p - l.P1()), l.Delta()));
+  return d <= EPSGEOM * l.Length();
+}
+
+int Hit (const Line2d & l1, const Line2d & l2, double heps)
+  {
+  double den =  Cross ( (l1.P2() - l1.P1()), (l2.P1() - l2.P2()));
+  double num1 = Cross ( (l2.P1() - l1.P1()), (l2.P1() - l2.P2()));
+  double num2 = Cross ( (l1.P2() - l1.P1()), (l2.P1() - l1.P1()));
+  num1 *= sgn (den);
+  num2 *= sgn (den);
+  den = fabs (den);
+
+  int ch = (-den * heps <= num1 && num1 <= den * (1 + heps) &&
+	    -den * heps <= num2 && num2 <= den * (1 + heps));
+  return ch;
+}
+
+
+void Line2d :: GetNormal (Line2d & n) const
+{
+  double 	ax  = P2().X()-P1().X(),
+    ay  = P2().Y()-P1().Y();
+  Point2d 	mid(P1().X()+.5*ax, P1().Y()+.5*ay);
+ 
+ n=Line2d(mid,Point2d(mid.X()+ay,mid.Y()-ax)) ;
+}
+
+Vec2d Line2d :: NormalDelta () const
+{
+ Line2d tmp;
+ GetNormal(tmp);
+ return tmp.Delta();
+}
+
+int TRIANGLE2D :: IsOn (const Point2d & p) const
+  {
+  return IsOnLine (Line2d (p1, p2), p) ||
+         IsOnLine (Line2d (p1, p3), p) ||
+         IsOnLine (Line2d (p2, p3), p);
+  }
+
+
+int TRIANGLE2D :: IsIn (const Point2d & p) const
+{
+  return ::CW(p, p1, p2) == ::CW(p, p2, p3) &&
+         ::CW(p, p1, p2) == ::CW(p, p3, p1);
+}
+
+
+
+int PTRIANGLE2D :: IsOn (const Point2d & p) const
+{
+  return IsOnLine (Line2d (*p1, *p2), p) ||
+         IsOnLine (Line2d (*p1, *p3), p) ||
+         IsOnLine (Line2d (*p2, *p3), p);
+}
+
+
+int PTRIANGLE2D :: IsIn (const Point2d & p) const
+{
+  return ::CW(p, *p1, *p2) == ::CW(p, *p2, *p3) &&
+         ::CW(p, *p1, *p2) == ::CW(p, *p3, *p1);
+}
+
+#endif
+
+
+
+
+
+
+Polygon2d :: Polygon2d ()
+{
+  ;
+}
+
+Polygon2d :: ~Polygon2d ()
+{
+  ;
+}
+
+void Polygon2d :: AddPoint (const Point2d & p)
+{ 
+  points.Append(p); 
+}
+
+
+double Polygon2d :: HArea () const
+{
+  int i;
+  double ar = 0;
+  for (i = 1; i <= points.Size(); i++)
+    {
+      const Point2d & p1 = points.Get(i);
+      const Point2d & p2 = points.Get(i%points.Size()+1);
+      ar += 
+	(p2.X()-p1.X()) * p1.Y() -
+	(p2.Y()-p1.Y()) * p1.X();
+    }
+  return ar/2;
+  /*
+  CURSOR c;
+  double ar = 0;
+  Point2d * p1, * p2, p0 = Point2d(0, 0);
+  Vec2d v1, v2 = Vec2d(1, 0);
+
+  p2 = points[points.Last()];
+  for (c = points.First(); c != points.Head(); c++)
+    {
+    p1 = p2;
+    p2 = points[c];
+    ar += Cross ( (*p2-*p1), (*p1 - p0));
+    }
+  return ar / 2;
+  */
+}
+
+
+int Polygon2d :: IsOn (const Point2d & p) const
+{
+  int i;
+  for (i = 1; i <= points.Size(); i++)
+    {
+      const Point2d & p1 = points.Get(i);
+      const Point2d & p2 = points.Get(i%points.Size()+1);
+      if (IsOnLine (Line2d(p1, p2), p)) return 1;
+    }
+  return 0;
+  /*
+  CURSOR c;
+  Point2d * p1, * p2;
+  
+  p2 = points[points.Last()];
+  for (c = points.First(); c != points.Head(); c++)
+    {
+      p1 = p2;
+      p2 = points[c];
+      if (IsOnLine (Line2d(*p1, *p2), p)) return 1;
+    }
+  return 0;
+  */
+}
+
+
+int Polygon2d :: IsIn (const Point2d & p) const
+{
+  int i;
+  double sum = 0, ang;
+  for (i = 1; i <= points.Size(); i++)
+    {
+      const Point2d & p1 = points.Get(i);
+      const Point2d & p2 = points.Get(i%points.Size()+1);
+      ang = Angle ( (p1 - p), (p2 - p) );
+      if (ang > M_PI) ang -= 2 * M_PI;
+      sum += ang;
+    }
+  return fabs(sum) > M_PI;
+  /*
+  CURSOR c;
+  Point2d * p1, * p2;
+  double sum = 0, ang;
+
+  p2 = points[points.Last()];
+  for (c = points.First(); c != points.Head(); c++)
+    {
+    p1 = p2;
+    p2 = points[c];
+    ang = Angle ( (*p1 - p), (*p2 - p) );
+    if (ang > M_PI) ang -= 2 * M_PI;
+    sum += ang;
+    }
+
+  return fabs(sum) > M_PI;
+  */
+}
+
+int Polygon2d :: IsConvex () const
+  {
+    /*
+  Point2d *p, *pold, *pnew;
+  char cw;
+  CURSOR c;
+
+  if (points.Length() < 3) return 0;
+
+  c = points.Last();
+  p = points[c];
+  c--;
+  pold = points[c];
+  pnew = points[points.First()];
+  cw = ::CW (*pold, *p, *pnew);
+
+  for (c = points.First(); c != points.Head(); c++)
+    {
+    pnew = points[c];
+    if (cw != ::CW (*pold, *p, *pnew))
+      return 0;
+    pold = p;
+    p = pnew;
+    }
+    */
+    return 0;
+  }
+
+
+int Polygon2d :: IsStarPoint (const Point2d & p) const
+  {
+    /*
+  Point2d *pnew, *pold;
+  char cw;
+  CURSOR c;
+
+  if (points.Length() < 3) return 0;
+
+  pold = points[points.Last()];
+  pnew = points[points.First()];
+
+  cw = ::CW (p, *pold, *pnew);
+
+  for (c = points.First(); c != points.Head(); c++)
+    {
+    pnew = points[c];
+    if (cw != ::CW (p, *pold, *pnew))
+      return 0;
+    pold = pnew;
+    }
+  return 1;
+    */
+    return 0;
+  }
+
+
+Point2d Polygon2d :: Center () const
+  {
+    /*
+  double ai, a = 0, x = 0, y = 0;
+  Point2d * p, *p2;
+  Point2d p0 = Point2d(0, 0);
+  CURSOR c;
+
+  p2 = points[points.Last()];
+
+  for (c = points.First(); c != points.Head(); c++)
+    {
+    p = points[c];
+    ai = Cross (*p2 - p0, *p - p0);
+    x += ai / 3 * (p2->X() + p->X());
+    y += ai / 3 * (p2->Y() + p->Y());
+    a+= ai;
+    p2 = p;
+    }
+  if (a != 0)
+    return Point2d (x / a, y / a);
+  else
+    return Point2d (0, 0);
+    */
+    return Point2d (0, 0);
+  }
+
+
+
+Point2d Polygon2d :: EqualAreaPoint () const
+  {
+    /*
+  double a11 = 0, a12 = 0, a21= 0, a22 = 0;
+  double b1 = 0, b2 = 0, dx, dy;
+  double det;
+  Point2d * p, *p2;
+  CURSOR c;
+
+  p = points[points.Last()];
+
+  for (c = points.First(); c != points.Head(); c++)
+    {
+    p2 = p;
+    p = points[c];
+
+    dx = p->X() - p2->X();
+    dy = p->Y() - p2->Y();
+
+    a11 += sqr (dy);
+    a12 -= dx * dy;
+    a21 -= dx * dy;
+    a22 += sqr (dx);
+    b1 -= dy * (p->X() * p2->Y() - p2->X() * p->Y());
+    b2 -= dx * (p->Y() * p2->X() - p2->Y() * p->X());
+    }
+
+  det = a11 * a22 - a21 * a12;
+
+  if (det != 0)
+    return Point2d ( (b1 * a22 - b2 * a12) / det,
+                     (a11 * b2 - a21 * b1) / det);
+  else
+    return Point2d (0, 0);
+*/
+    return Point2d (0, 0);
+  }
+
+
+}
diff --git a/contrib/Netgen/libsrc/gprim/geom2d.hpp b/contrib/Netgen/libsrc/gprim/geom2d.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..0c4c616fac8686b8d54b9d79cb81f5778124cf01
--- /dev/null
+++ b/contrib/Netgen/libsrc/gprim/geom2d.hpp
@@ -0,0 +1,883 @@
+#ifndef FILE_GEOM2D
+#define FILE_GEOM2D
+
+/* *************************************************************************/
+/* File:   geom2d.hh                                                       */
+/* Author: Joachim Schoeberl                                               */
+/* Date:   5. Aug. 95                                                      */
+/* *************************************************************************/
+
+
+
+/* Geometric Algorithms */
+
+#define EPSGEOM 1E-5
+
+
+// extern void MyError (const char * ch);
+
+class Point2d;
+class Vec2d;
+
+class LINE2D;
+class Line2d;
+class PLine2d;
+class TRIANGLE2D;
+class PTRIANGLE2D;
+
+
+inline Vec2d operator- (const Point2d & p1, const Point2d & p2);
+inline Point2d operator- (const Point2d & p1, const Vec2d & v);
+inline Point2d operator+ (const Point2d & p1, const Vec2d & v);
+inline Point2d Center (const Point2d & p1, const Point2d & p2);
+
+inline void PpSmV (const Point2d & p1, double s, const Vec2d & v, Point2d & p2);
+inline void PmP (const Point2d & p1, const Point2d & p2, Vec2d & v);
+ostream & operator<<(ostream  & s, const Point2d & p);
+inline Vec2d operator- (const Point2d & p1, const Point2d & p2);
+inline Point2d operator- (const Point2d & p1, const Vec2d & v);
+inline Point2d operator+ (const Point2d & p1, const Vec2d & v);
+inline Vec2d operator- (const Vec2d & p1, const Vec2d & v);
+inline Vec2d operator+ (const Vec2d & p1, const Vec2d & v);
+inline Vec2d operator* (double scal, const Vec2d & v);
+double Angle (const Vec2d & v);
+double FastAngle (const Vec2d & v);
+double Angle (const Vec2d & v1, const Vec2d & v2);
+double FastAngle (const Vec2d & v1, const Vec2d & v2);
+ostream & operator<<(ostream  & s, const Vec2d & v);
+double Dist2(const Line2d & g, const Line2d & h );		// GH
+int Near (const Point2d & p1, const Point2d & p2, const double eps);
+
+int Parallel (const Line2d & l1, const Line2d & l2, double peps = EPSGEOM);
+int IsOnLine (const Line2d & l, const Point2d & p, double heps = EPSGEOM);
+int IsOnLongLine (const Line2d & l, const Point2d & p);
+int Hit (const Line2d & l1, const Line2d & l2, double heps = EPSGEOM);
+ostream & operator<<(ostream  & s, const Line2d & l);
+Point2d CrossPoint (const PLine2d & l1, const PLine2d & l2);
+int Parallel (const PLine2d & l1, const PLine2d & l2, double peps = EPSGEOM);
+int IsOnLine (const PLine2d & l, const Point2d & p, double heps = EPSGEOM);
+int IsOnLongLine (const PLine2d & l, const Point2d & p);
+int Hit (const PLine2d & l1, const Line2d & l2, double heps = EPSGEOM);
+ostream & operator<<(ostream  & s, const Line2d & l);
+ostream & operator<<(ostream  & s, const TRIANGLE2D & t); 
+ostream & operator<<(ostream & s, const PTRIANGLE2D & t);
+
+///
+class Point2d
+{
+  ///
+  friend class Vec2d;
+
+protected:
+  ///
+  double px, py;
+
+public:
+  ///
+  Point2d() { /* px = py = 0; */ }
+  ///
+  Point2d(double ax, double ay) { px = ax; py = ay; }
+  ///
+  Point2d(const Point2d & p2) { px = p2.px; py = p2.py; }
+
+  Point2d (const Point<2> & p2)
+  {
+    px = p2(0);
+    py = p2(1);
+  }
+  ///
+  Point2d & operator= (const Point2d & p2)
+    { px = p2.px; py = p2.py; return *this; }
+    
+  ///
+  int operator== (const Point2d & p2) const			// GH
+    { return (px == p2.px  &&  py == p2.py) ; }
+
+  ///
+  double & X() { return px; }
+  ///
+  double & Y() { return py; }
+  ///
+  double X() const { return px; }
+  ///
+  double Y() const { return py; }
+
+  operator Point<2> () const
+  {
+    return Point<2> (px, py);
+  }
+
+
+  ///
+  friend inline Vec2d operator- (const Point2d & p1, const Point2d & p2);
+  ///
+  friend inline Point2d operator- (const Point2d & p1, const Vec2d & v);
+  ///
+  friend inline Point2d operator+ (const Point2d & p1, const Vec2d & v);
+
+  ///
+  friend inline Point2d Center (const Point2d & p1, const Point2d & p2);
+
+  const Point2d & SetToMin (const Point2d & p2)
+    {
+      if (p2.px < px) px = p2.px;
+      if (p2.py < py) py = p2.py;
+      return *this;
+    }
+
+
+  ///
+  const Point2d & SetToMax (const Point2d & p2)
+    {
+      if (p2.px > px) px = p2.px;
+      if (p2.py > py) py = p2.py;
+      return *this;
+    }
+
+  ///
+  friend double Dist (const Point2d & p1, const Point2d & p2)
+    { return sqrt ( (p1.px - p2.px) * (p1.px - p2.px) +
+		    (p1.py - p2.py) * (p1.py - p2.py) ); }
+  //    { return sqrt ( sqr (p1.X()-p2.X()) + sqr (p1.Y()-p2.Y()) ); }
+
+  ///
+  friend double Dist2 (const Point2d & p1, const Point2d & p2)
+    { return ( (p1.px - p2.px) * (p1.px - p2.px) +
+	       (p1.py - p2.py) * (p1.py - p2.py) ); }
+  //    { return sqr (p1.X()-p2.X()) + sqr (p1.Y()-p2.Y()) ; }
+
+
+  /**
+    Points clock-wise ?
+    Are the points (p1, p2, p3) clock-wise ?
+    */
+  friend inline int CW (const Point2d & p1, const Point2d & p2, const Point2d & p3)
+    {
+      //      return Cross (p2 - p1, p3 - p2) < 0;      
+      return
+	(p2.px - p1.px) * (p3.py - p2.py) - 
+	(p2.py - p1.py) * (p3.px - p2.px) < 0;
+    }
+  /**
+    Points counter-clock-wise ?
+    Are the points (p1, p2, p3) counter-clock-wise ?
+    */
+  friend inline bool CCW (const Point2d & p1, const Point2d & p2, const Point2d & p3)
+    {
+      //      return Cross (p2 - p1, p3 - p2) > 0;
+      return
+	(p2.px - p1.px) * (p3.py - p2.py) - 
+	(p2.py - p1.py) * (p3.px - p2.px) > 0;
+    }  /**
+    Points counter-clock-wise ?
+    Are the points (p1, p2, p3) counter-clock-wise ?
+    */
+  friend inline bool CCW (const Point2d & p1, const Point2d & p2, const Point2d & p3, double eps)
+    {
+      //      return Cross (p2 - p1, p3 - p2) > 0;
+      double ax = p2.px - p1.px;
+      double ay = p2.py - p1.py;
+      double bx = p3.px - p2.px;
+      double by = p3.py - p2.py;
+
+      return ax*by - ay*bx > eps*eps*max2(ax*ax+ay*ay,bx*bx+by*by);
+    }
+
+  ///
+  friend inline void PpSmV (const Point2d & p1, double s, const Vec2d & v, Point2d & p2);
+  ///
+  friend inline void PmP (const Point2d & p1, const Point2d & p2, Vec2d & v);
+
+  ///
+  friend ostream & operator<<(ostream  & s, const Point2d & p);
+};
+
+
+inline int Near (const Point2d & p1, const Point2d & p2, 
+	  const double eps = 1e-4 )
+{ 
+  return  Dist2(p1,p2) <= eps*eps; 
+}
+
+
+
+
+
+
+///
+class Vec2d
+  {
+protected:
+  ///
+  double vx, vy;
+
+public:
+  ///
+    Vec2d() { /* vx = vy = 0; */ }
+    ///
+    Vec2d(double ax, double ay)
+    { vx = ax; vy = ay; }
+    ///
+    Vec2d(const Vec2d & v2) { vx = v2.vx; vy = v2.vy; }
+
+    ///
+    explicit Vec2d(const Vec<2> & v2) { vx = v2(0); vy = v2(1); }
+
+    ///
+    Vec2d(const Point2d & p1, const Point2d & p2)
+    { vx = p2.px - p1.px; vy = p2.py - p1.py; }
+    
+  ///
+  Vec2d & operator= (const Vec2d & p2)
+    { vx = p2.vx; vy = p2.vy; return *this; }
+
+  ///
+  double & X() { return vx; }
+  ///
+  double & Y() { return vy; }
+  ///
+  double X() const { return vx; }
+  ///
+  double Y() const { return vy; }
+
+  ///
+  double Length() const { return sqrt (vx * vx + vy * vy); }
+  ///
+  double Length2() const { return vx * vx + vy * vy; }
+
+  void GetNormal (Vec2d & n) const { n.vx=-vy; n.vy=vx; }		// GH
+
+  ///
+  inline Vec2d & operator+= (const Vec2d & v2);
+  ///
+  inline Vec2d & operator-= (const Vec2d & v2);
+  ///
+  inline Vec2d & operator*= (double s);
+  ///
+  inline Vec2d & operator/= (double s);
+
+  ///
+  friend inline Vec2d operator- (const Point2d & p1, const Point2d & p2);
+  ///
+  friend inline Point2d operator- (const Point2d & p1, const Vec2d & v);
+  ///
+  friend inline Point2d operator+ (const Point2d & p1, const Vec2d & v);
+  ///
+  friend inline Vec2d operator- (const Vec2d & p1, const Vec2d & v);
+  ///
+  friend inline Vec2d operator+ (const Vec2d & p1, const Vec2d & v);
+  ///
+  friend inline Vec2d operator* (double scal, const Vec2d & v);
+
+  ///
+  friend double operator* (const Vec2d & v1, const Vec2d & v2)
+    { return v1.X() * v2.X() + v1.Y() * v2.Y(); }
+
+
+  ///
+  friend double Cross (const Vec2d & v1, const Vec2d & v2)
+    { return double(v1.X()) * double(v2.Y()) -
+             double(v1.Y()) * double(v2.X()); }
+
+  ///
+  friend inline void PpSmV (const Point2d & p1, double s, const Vec2d & v, Point2d & p2);
+  ///
+  friend inline void PmP (const Point2d & p1, const Point2d & p2, Vec2d & v);
+
+///						Angle in [0,2*PI)
+
+  ///
+  friend double Angle (const Vec2d & v);
+  ///
+  friend double FastAngle (const Vec2d & v);
+  ///
+  friend double Angle (const Vec2d & v1, const Vec2d & v2);
+  ///
+  friend double FastAngle (const Vec2d & v1, const Vec2d & v2);
+
+  ///
+  friend ostream & operator<<(ostream  & s, const Vec2d & v);
+  };
+
+
+
+///
+class Line2d
+  {
+protected:
+  ///
+  Point2d p1, p2;
+
+public:
+  ///
+  Line2d() : p1(), p2() { };
+  ///
+  Line2d(const Point2d & ap1, const Point2d & ap2)
+    { p1 = ap1; p2 = ap2; }
+
+  ///
+  Line2d & operator= (const Line2d & l2)
+    { p1 = l2.p1; p2 = l2.p2; return *this;}
+
+  ///
+  Point2d & P1() { return p1; }
+  ///
+  Point2d & P2() { return p2; }
+  ///
+  const Point2d & P1() const { return p1; }
+  ///
+  const Point2d & P2() const { return p2; }
+
+  ///
+  double XMax() const { return max2 (p1.X(), p2.X()); }
+  ///
+  double YMax() const { return max2 (p1.Y(), p2.Y()); }
+  ///
+  double XMin() const { return min2 (p1.X(), p2.X()); }
+  ///
+  double YMin() const { return min2 (p1.Y(), p2.Y()); }
+
+  ///
+  Vec2d Delta () const { return Vec2d (p2.X()-p1.X(), p2.Y()-p1.Y()); }
+  ///
+  double Length () const { return Delta().Length(); }
+  ///
+  double Length2 () const
+        { return sqr (p1.X() - p2.X()) +
+                 sqr (p1.Y() - p2.Y()); }
+
+  void GetNormal (Line2d & n) const;					// GH
+  Vec2d NormalDelta () const;						// GH
+
+  /// square of the distance between two 2d-lines.
+  friend double Dist2(const Line2d & g, const Line2d & h );		// GH
+
+  ///
+  friend Point2d CrossPoint (const Line2d & l1, const Line2d & l2);
+    /// returns 1 iff parallel
+    friend int CrossPointBarycentric (const Line2d & l1, const Line2d & l2,
+				      double & lam1, double & lam2);
+
+  ///
+  friend int Parallel (const Line2d & l1, const Line2d & l2, double peps);
+  ///
+  friend int IsOnLine (const Line2d & l, const Point2d & p, double heps);
+  ///
+  friend int IsOnLongLine (const Line2d & l, const Point2d & p);
+  ///
+  friend int Hit (const Line2d & l1, const Line2d & l2, double heps);
+
+  ///
+  friend ostream & operator<<(ostream  & s, const Line2d & l);
+  };
+
+
+#ifdef NONE
+///
+class PLine2d
+  {
+protected:
+  ///
+  Point2d const * p1, *p2;
+
+public:
+  ///
+  PLine2d() { };
+  ///
+  PLine2d(Point2d const * ap1, Point2d const * ap2)
+    { p1 = ap1; p2 = ap2; }
+
+  ///
+  PLine2d & operator= (const PLine2d & l2)
+    { p1 = l2.p1; p2 = l2.p2; return *this;}
+
+  ///
+  const Point2d *& P1() { return p1; }
+  ///
+  const Point2d *& P2() { return p2; }
+  ///
+  const Point2d & P1() const { return *p1; }
+  ///
+  const Point2d & P2() const { return *p2; }
+
+  ///
+  double XMax() const { return max2 (p1->X(), p2->X()); }
+  ///
+  double YMax() const { return max2 (p1->Y(), p2->Y()); }
+  ///
+  double XMin() const { return min2 (p1->X(), p2->X()); }
+  ///
+  double YMin() const { return min2 (p1->Y(), p2->Y()); }
+
+
+  ///
+  Vec2d Delta () const { return Vec2d (p2->X()-p1->X(), p2->Y()-p1->Y()); }
+  ///
+  double Length () const { return Delta().Length(); }
+  ///
+  double Length2 () const
+        { return sqr (p1->X() - p2->X()) +
+                 sqr (p1->Y() - p2->Y()); }
+
+
+    
+  ///
+  friend Point2d CrossPoint (const PLine2d & l1, const PLine2d & l2);
+  ///
+  friend int Parallel (const PLine2d & l1, const PLine2d & l2, double peps);
+  ///
+  friend int IsOnLine (const PLine2d & l, const Point2d & p, double heps);
+  ///
+  friend int IsOnLongLine (const PLine2d & l, const Point2d & p);
+  ///
+  friend int Hit (const PLine2d & l1, const Line2d & l2, double heps);
+
+  ///
+  friend ostream & operator<<(ostream  & s, const Line2d & l);
+  };
+
+
+
+///
+class ILINE
+  {
+  ///
+  INDEX i[2];
+
+  public:
+  ///
+  ILINE() {};
+  ///
+  ILINE(INDEX i1, INDEX i2) { i[0] = i1; i[1] = i2; }
+  ///
+  ILINE(const ILINE & l) { i[0] = l.i[0]; i[1] = l.i[1]; }
+
+  ///
+  ILINE & operator= (const ILINE & l)
+    { i[0] = l.i[0]; i[1] = l.i[1]; return *this; }
+
+  ///
+  const INDEX & I(int ai) const { return i[ai-1]; }
+  ///
+  const INDEX & X() const { return i[0]; }
+  ///
+  const INDEX & Y() const { return i[1]; }
+  ///
+  const INDEX & I1() const { return i[0]; }
+  ///
+  const INDEX & I2() const { return i[1]; }
+
+  ///
+  INDEX & I(int ai) { return i[ai-1]; }
+  ///
+  INDEX & X() { return i[0]; }
+  ///
+  INDEX & Y() { return i[1]; }
+  ///
+  INDEX & I1() { return i[0]; }
+  ///
+  INDEX & I2() { return i[1]; }
+  };
+
+
+
+
+///
+class TRIANGLE2D
+  {
+private:
+  ///
+  Point2d p1, p2, p3;
+
+public:
+  ///
+  TRIANGLE2D() { };
+  ///
+  TRIANGLE2D (const Point2d & ap1, const Point2d & ap2,
+              const Point2d & ap3)
+    { p1 = ap1; p2 = ap2; p3 = ap3;}
+
+  ///
+  TRIANGLE2D & operator= (const TRIANGLE2D & t2)
+    { p1 = t2.p1; p2 = t2.p2; p3 = t2.p3; return *this; }
+
+  ///
+  Point2d & P1() { return p1; }
+  ///
+  Point2d & P2() { return p2; }
+  ///
+  Point2d & P3() { return p3; }
+  ///
+  const Point2d & P1() const { return p1; }
+  ///
+  const Point2d & P2() const { return p2; }
+  ///
+  const Point2d & P3() const { return p3; }
+
+  ///
+  double XMax() const { return max3 (p1.X(), p2.X(), p3.X()); }
+  ///
+  double YMax() const { return max3 (p1.Y(), p2.Y(), p3.Y()); }
+  ///
+  double XMin() const { return min3 (p1.X(), p2.X(), p3.X()); }
+  ///
+  double YMin() const { return min3 (p1.Y(), p2.Y(), p3.Y()); }
+
+  ///
+  inline Point2d Center () const
+   { return Point2d( (p1.X()+p2.X()+p3.X())/3, (p1.Y()+p2.Y()+p3.Y())/3); }
+
+  ///
+  int Regular() const;
+  /// 
+  int CW () const;
+  ///
+  int CCW () const;
+
+  ///
+  int IsOn (const Point2d & p) const;
+  ///
+  int IsIn (const Point2d & p) const;
+  ///
+  friend ostream & operator<<(ostream  & s, const TRIANGLE2D & t);
+  };
+
+
+///
+class PTRIANGLE2D
+  {
+private:
+  ///
+  Point2d const *p1, *p2, *p3;
+
+public:
+  ///
+  PTRIANGLE2D() { };
+  ///
+  PTRIANGLE2D (const Point2d * ap1, const Point2d * ap2,
+              const Point2d * ap3)
+    { p1 = ap1; p2 = ap2; p3 = ap3;}
+
+  ///
+  PTRIANGLE2D & operator= (const PTRIANGLE2D & t2)
+    { p1 = t2.p1; p2 = t2.p2; p3 = t2.p3; return *this; }
+
+  ///
+  const Point2d *& P1() { return p1; }
+  ///
+  const Point2d *& P2() { return p2; }
+  ///
+  const Point2d *& P3() { return p3; }
+  ///
+  const Point2d * P1() const { return p1; }
+  ///
+  const Point2d * P2() const { return p2; }
+  ///
+  const Point2d * P3() const { return p3; }
+
+  ///
+  double XMax() const { return max3 (p1->X(), p2->X(), p3->X()); }
+  ///
+  double YMax() const { return max3 (p1->Y(), p2->Y(), p3->Y()); }
+  ///
+  double XMin() const { return min3 (p1->X(), p2->X(), p3->X()); }
+  ///
+  double YMin() const { return min3 (p1->Y(), p2->Y(), p3->Y()); }
+
+  ///
+  Point2d Center () const
+   { return Point2d( (p1->X()+p2->X()+p3->X())/3, (p1->Y()+p2->Y()+p3->Y())/3); }
+
+
+  ///
+  int Regular() const;
+  ///
+  int CW () const;
+  ///
+  int CCW () const;
+
+  ///
+  int IsOn (const Point2d & p) const;
+  ///
+  int IsIn (const Point2d & p) const;
+  ///
+  friend ostream & operator<<(ostream & s, const PTRIANGLE2D & t);
+  };
+#endif
+
+
+
+class Polygon2d
+{
+protected:
+  ARRAY<Point2d> points;
+  
+public:
+  Polygon2d ();
+  ~Polygon2d ();
+  
+  void AddPoint (const Point2d & p);
+  int GetNP() const { return points.Size(); }
+  void GetPoint (int i, Point2d & p) const
+  { p = points.Get(i); }
+  void GetLine (int i, Point2d & p1, Point2d & p2) const
+  { p1 = points.Get(i); p2 = points.Get(i%points.Size()+1); }
+
+  double Area () const { return fabs (HArea()); }
+  int CW () const { return HArea() > 0; }
+  int CCW () const { return HArea() < 0; }
+  
+  int IsOn (const Point2d & p) const;
+  int IsIn (const Point2d & p) const;
+
+  int IsConvex () const;
+
+  int IsStarPoint (const Point2d & p) const;
+  Point2d Center() const;
+  Point2d EqualAreaPoint () const;
+private:
+  double HArea () const;
+};
+
+
+/** Cheap approximation to atan2.
+  A monotone function of atan2(x,y) is computed.
+ */
+extern double Fastatan2 (double x, double y);
+
+
+inline Vec2d & Vec2d :: operator+= (const Vec2d & v2)
+  {
+  vx += v2.vx;
+  vy += v2.vy;
+  return *this;
+  }
+
+inline Vec2d & Vec2d :: operator-= (const Vec2d & v2)
+  {
+  vx -= v2.vx;
+  vy -= v2.vy;
+  return *this;
+  }
+
+inline Vec2d & Vec2d :: operator*= (double s)
+  {
+  vx *= s;
+  vy *= s;
+  return *this;
+  }
+
+
+inline Vec2d & Vec2d :: operator/= (double s)
+{
+  if (s != 0)
+    {
+      vx /= s;
+      vy /= s;
+    }
+  else
+    {
+      MyError ("Vec2d::operator /=: Division by zero");
+    }
+  return *this;
+}
+
+
+
+inline Vec2d operator- (const Point2d & p1, const Point2d & p2)
+  {
+  return Vec2d (p1.X() - p2.X(), p1.Y() - p2.Y());
+  }
+
+
+inline Point2d operator- (const Point2d & p1, const Vec2d & v)
+  {
+  return Point2d (p1.X() - v.X(), p1.Y() - v.Y());
+  }
+
+
+inline Point2d operator+ (const Point2d & p1, const Vec2d & v)
+  {
+  return Point2d (p1.X() + v.X(), p1.Y() + v.Y());
+  }
+
+
+inline Point2d Center (const Point2d & p1, const Point2d & p2)
+  {
+  return Point2d ((p1.X() + p2.X()) / 2, (p1.Y() + p2.Y()) / 2);
+  }
+
+
+inline Vec2d operator- (const Vec2d & v1, const Vec2d & v2)
+  {
+  return Vec2d (v1.X() - v2.X(), v1.Y() - v2.Y());
+  }
+
+
+inline Vec2d operator+ (const Vec2d & v1, const Vec2d & v2)
+  {
+  return Vec2d (v1.X() + v2.X(), v1.Y() + v2.Y());
+  }
+
+
+inline Vec2d operator* (double scal, const Vec2d & v)
+  {
+  return Vec2d (scal * v.X(), scal * v.Y());
+  }
+
+
+inline void PpSmV (const Point2d & p1, double s,
+                   const Vec2d & v, Point2d & p2)
+  {
+  p2.X() = p1.X() + s * v.X();
+  p2.Y() = p1.Y() + s * v.Y();
+  }
+
+
+inline void PmP (const Point2d & p1, const Point2d & p2, Vec2d & v)
+  {
+  v.X() = p1.X() - p2.X();
+  v.Y() = p1.Y() - p2.Y();
+  }
+
+
+
+
+
+#ifdef none
+inline int TRIANGLE2D :: Regular() const
+    {
+    return fabs(Cross ( p2 - p1, p3 - p2)) > EPSGEOM;
+    }
+
+
+inline int TRIANGLE2D :: CW () const
+    {
+    return Cross ( p2 - p1, p3 - p2) < 0;
+    }
+
+
+inline int TRIANGLE2D :: CCW () const
+    {
+    return Cross ( p2 - p1, p3 - p2) > 0;
+    }
+
+
+
+
+inline int PTRIANGLE2D :: Regular() const
+    {
+    return fabs(Cross ( *p2 - *p1, *p3 - *p2)) > EPSGEOM;
+    }
+
+
+inline int PTRIANGLE2D :: CW () const
+    {
+    return Cross ( *p2 - *p1, *p3 - *p2) < 0;
+    }
+
+
+inline int PTRIANGLE2D :: CCW () const
+    {
+    return Cross ( *p2 - *p1, *p3 - *p2) > 0;
+    }
+
+
+#endif
+
+
+///
+class Mat2d
+{
+protected:
+  ///
+  double coeff[4];
+
+public:
+  ///
+  Mat2d() { coeff[0] = coeff[1] = coeff[2] = coeff[3] = 0; }
+  ///
+  Mat2d(double a11, double a12, double a21, double a22)
+    { coeff[0] = a11; coeff[1] = a12; coeff[2] = a21; coeff[3] = a22; }
+  ///
+  Mat2d(const Mat2d & m2)
+    { for (int i = 0; i < 4; i++) coeff[i] = m2.Get(i); }
+
+  ///
+  double & Elem (INDEX i, INDEX j) { return coeff[2*(i-1)+j-1]; }
+  ///
+  double & Elem (INDEX i) {return coeff[i]; }
+  ///
+  double Get (INDEX i, INDEX j) const { return coeff[2*(i-1)+j-1]; }
+  ///
+  double Get (INDEX i) const {return coeff[i]; }
+
+  ///  
+  double Det () const { return coeff[0] * coeff[3] - coeff[1] * coeff[2]; }
+
+  ///
+  void Mult (const Vec2d & v, Vec2d & prod) const;
+  ///
+  void MultTrans (const Vec2d & v , Vec2d & prod) const;
+  ///
+  void Solve (const Vec2d & rhs, Vec2d & x) const;
+  /// Solves mat * x = rhs, but using a positive definite matrix instead of mat
+  void SolvePositiveDefinite (const Vec2d & rhs, Vec2d & x) const;
+  /// add a term \alpha * v * v^T
+  void AddDiadicProduct (double alpha, Vec2d & v);
+};
+
+
+
+inline void Mat2d :: Mult (const Vec2d & v, Vec2d & prod) const
+{
+  prod.X() = coeff[0] * v.X() + coeff[1] * v.Y();
+  prod.Y() = coeff[2] * v.X() + coeff[3] * v.Y();
+}
+
+
+inline  void Mat2d :: MultTrans (const Vec2d & v, Vec2d & prod) const
+{
+  prod.X() = coeff[0] * v.X() + coeff[2] * v.Y();
+  prod.Y() = coeff[1] * v.X() + coeff[3] * v.Y();
+}
+
+
+
+inline void Mat2d :: Solve (const Vec2d & rhs, Vec2d & x) const
+{
+  double det = Det();
+  
+  if (det == 0)
+    MyError ("Mat2d::Solve: zero determinant");
+  else
+    {
+      x.X() = (coeff[3] * rhs.X() - coeff[1] * rhs.Y()) / det;
+      x.Y() = (-coeff[2] * rhs.X() + coeff[0] * rhs.Y()) / det;
+    }
+}
+
+
+inline void Mat2d :: SolvePositiveDefinite (const Vec2d & rhs, Vec2d & x) const
+{
+  double a = max2(coeff[0], 1e-8);
+  double b = coeff[1] / a;
+  double c = coeff[2] / a;
+  double d = max2(coeff[3] - a *b * c, 1e-8);
+
+  x.X() = (rhs.X() - b * rhs.Y()) / a;
+  x.Y() = rhs.Y() / d - c * x.X();
+}
+
+
+inline void Mat2d :: AddDiadicProduct (double alpha, Vec2d & v)
+{
+  coeff[0] += alpha * v.X() * v.X();
+  coeff[1] += alpha * v.X() * v.Y();
+  coeff[2] += alpha * v.Y() * v.X();
+  coeff[3] += alpha * v.Y() * v.Y();
+}
+
+
+
+#endif
diff --git a/contrib/Netgen/libsrc/gprim/geom3d.cpp b/contrib/Netgen/libsrc/gprim/geom3d.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..71970ffee39d81ca921f7f3d08c8030ed0e8905a
--- /dev/null
+++ b/contrib/Netgen/libsrc/gprim/geom3d.cpp
@@ -0,0 +1,731 @@
+#include <algorithm>
+#include <mystdlib.h>
+
+#include <myadt.hpp>
+#include <gprim.hpp>
+
+namespace netgen
+{
+ostream & operator<<(ostream  & s, const Point3d & p)
+  {
+  return s << "(" << p.x[0] << ", " << p.x[1] << ", " << p.x[2] << ")";
+  }
+
+ostream & operator<<(ostream  & s, const Vec3d & v)
+  {
+  return s << "(" << v.x[0] << ", " << v.x[1] << ", " << v.x[2] << ")";
+  }
+
+double Angle (const Vec3d & v1, const Vec3d & v2)
+{
+  double co = (v1 * v2) / (v1.Length() * v2.Length());
+  if (co > 1) co = 1;
+  if (co < -1) co = -1;
+  return acos ( co );
+}
+
+
+void Vec3d :: GetNormal (Vec3d & n) const
+  {
+  if (fabs (X()) > fabs (Z()))
+    {
+    n.X() = -Y();
+    n.Y() = X();
+    n.Z() = 0;
+    }
+  else
+    {
+    n.X() = 0;
+    n.Y() = Z();
+    n.Z() = -Y();
+    }
+  double len = n.Length();
+  if (len == 0)
+    {
+    n.X() = 1;
+    n.Y() = n.Z() = 0;
+    }
+  else
+    n /= len;
+  }
+
+/*
+ostream & operator<<(ostream  & s, const ROTDenseMatrix3D & r)
+  {
+  return s << "{ (" << r.txx << ", " << r.txy << ", " << r.txz << ") , ("
+                    << r.tyx << ", " << r.tyy << ", " << r.tyz << ") , ("
+                    << r.tzx << ", " << r.tzy << ", " << r.tzz << ") }";
+  }
+*/
+
+/*
+Vec3d operator- (const Point3d & p1, const Point3d & p2)
+  {
+  return Vec3d (p1.X() - p2.X(), p1.Y() - p2.Y(),p1.Z() - p2.Z());
+  }
+
+Point3d operator- (const Point3d & p1, const Vec3d & v)
+  {
+  return Point3d (p1.X() - v.X(), p1.Y() - v.Y(),p1.Z() - v.Z());
+  }
+
+Point3d operator+ (const Point3d & p1, const Vec3d & v)
+  {
+  return Point3d (p1.X() + v.X(), p1.Y() + v.Y(),p1.Z() + v.Z());
+  }
+
+Vec3d operator- (const Vec3d & v1, const Vec3d & v2)
+  {
+  return Vec3d (v1.X() - v2.X(), v1.Y() - v2.Y(),v1.Z() - v2.Z());
+  }
+
+Vec3d operator+ (const Vec3d & v1, const Vec3d & v2)
+  {
+  return Vec3d (v1.X() + v2.X(), v1.Y() + v2.Y(),v1.Z() + v2.Z());
+  }
+
+Vec3d operator* (double scal, const Vec3d & v)
+  {
+  return Vec3d (scal * v.X(), scal * v.Y(), scal * v.Z());
+  }
+*/
+/*
+double operator* (const Vec3d & v1, const Vec3d & v2)
+  {
+  return v1.X() * v2.X() + v1.Y() * v2.Y() + v1.Z() * v2.Z();
+  }
+
+double Cross (const Vec3d & v1, const Vec3d & v2)
+  {
+  return v1.X() * v2.Y() - v1.Y() * v2.X();
+  }
+*/
+
+/*
+void ROTDenseMatrix3D :: CalcRotMat(double ag, double bg, double lg, double size2, Vec3d r)
+  {
+  size = size2;
+  txx=size * ( cos(bg) * cos(lg) );
+  txy=size * ( cos(bg) * sin(lg) );
+  txz=size * (-sin(bg)           );
+
+  tyx=size * ( sin(ag) * sin(bg) * cos(lg) - cos(ag) * sin(lg) );
+  tyy=size * ( sin(ag) * sin(bg) * sin(lg) + cos(ag) * cos(lg) );
+  tyz=size * ( sin(ag) * cos(bg)                               );
+
+  tzx=size * ( cos(ag) * sin(bg) * cos(lg) + sin(ag) * sin(lg) );
+  tzy=size * ( cos(ag) * sin(bg) * sin(lg) - sin(ag) * cos(lg) );
+  tzz=size * ( cos(ag) * cos(bg)                               );
+
+  deltaR=r;
+  }
+ROTDenseMatrix3D :: ROTDenseMatrix3D(double ag, double bg, double lg, double size2, Vec3d r)
+  {CalcRotMat(ag, bg, lg, size2, r); }
+
+ROTDenseMatrix3D :: ROTDenseMatrix3D(Vec3d rot2)
+  {
+  Vec3d r2(0,0,0);
+  CalcRotMat(rot2.X(), rot2.Y(), rot2.Z(), 1, r2);
+  }
+
+ROTDenseMatrix3D ROTDenseMatrix3D :: INV()
+  {
+  ROTDenseMatrix3D rinv(txx/sqr(size),tyx/sqr(size),tzx/sqr(size),
+                   txy/sqr(size),tyy/sqr(size),tzy/sqr(size),
+                   txz/sqr(size),tyz/sqr(size),tzz/sqr(size),
+                   1/size,deltaR);
+  return rinv;
+  }
+
+Vec3d operator* (const ROTDenseMatrix3D & r, const Vec3d & v)
+  {
+  return Vec3d (r.XX() * v.X() + r.XY() * v.Y() + r.XZ() * v.Z(),
+                r.YX() * v.X() + r.YY() * v.Y() + r.YZ() * v.Z(),
+                r.ZX() * v.X() + r.ZY() * v.Y() + r.ZZ() * v.Z() );
+  }
+
+Point3d operator* (const ROTDenseMatrix3D & r, const Point3d & p)
+  {
+  return Point3d (r.XX() * p.X() + r.XY() * p.Y() + r.XZ() * p.Z(),
+                  r.YX() * p.X() + r.YY() * p.Y() + r.YZ() * p.Z(),
+                  r.ZX() * p.X() + r.ZY() * p.Y() + r.ZZ() * p.Z() );
+  }
+*/
+
+
+
+
+
+
+
+Box3d :: Box3d ( double aminx, double amaxx,
+                 double aminy, double amaxy,
+                 double aminz, double amaxz )
+{
+  minx[0] = aminx; maxx[0] = amaxx;
+  minx[1] = aminy; maxx[1] = amaxy;
+  minx[2] = aminz; maxx[2] = amaxz;
+}
+
+Box3d :: Box3d ( const Box3d & b2 )
+{
+  for (int i = 0; i < 3; i++)
+    {
+      minx[i] = b2.minx[i];
+      maxx[i] = b2.maxx[i];
+    }
+}
+
+Box3d :: Box3d ( const Box<3> & b2 )
+{
+  for (int i = 0; i < 3; i++)
+    {
+      minx[i] = b2.PMin()(i);
+      maxx[i] = b2.PMax()(i);
+    }
+}
+
+
+/*
+int Box3d :: Intersect (const Box3d & box2) const
+{
+  int i;
+  for (i = 0; i <= 2; i++)
+    if (minx[i] > box2.maxx[i] || maxx[i] < box2.minx[i])
+      return 0;
+  return 1;
+}
+*/
+
+/*
+void Box3d :: SetPoint (const Point3d & p)
+{
+  minx[0] = maxx[0] = p.X();
+  minx[1] = maxx[1] = p.Y();
+  minx[2] = maxx[2] = p.Z();
+}
+
+void Box3d :: AddPoint (const Point3d & p)
+{
+  if (p.X() < minx[0]) minx[0] = p.X();
+  if (p.X() > maxx[0]) maxx[0] = p.X();
+  if (p.Y() < minx[1]) minx[1] = p.Y();
+  if (p.Y() > maxx[1]) maxx[1] = p.Y();
+  if (p.Z() < minx[2]) minx[2] = p.Z();
+  if (p.Z() > maxx[2]) maxx[2] = p.Z();
+}
+*/
+
+void Box3d :: GetPointNr (int i, Point3d & point) const
+{
+  i--;
+  point.X() = (i & 1) ? maxx[0] : minx[0];
+  point.Y() = (i & 2) ? maxx[1] : minx[1];
+  point.Z() = (i & 4) ? maxx[2] : minx[2];
+}
+
+
+void Box3d :: Increase (double d)
+{
+  for (int i = 0; i <= 2; i++)
+    {
+      minx[i] -= d;
+      maxx[i] += d;
+    }
+}
+
+void Box3d :: IncreaseRel (double /* rel */)
+{
+  for (int i = 0; i <= 2; i++)
+    {
+      double d = 0.5 * (maxx[i] - minx[i]);
+      minx[i] -= d;
+      maxx[i] += d;
+    }
+}
+
+
+Box3d :: Box3d (const Point3d& p1, const Point3d& p2)
+{
+  minx[0] = min2 (p1.X(), p2.X());
+  minx[1] = min2 (p1.Y(), p2.Y());
+  minx[2] = min2 (p1.Z(), p2.Z());
+  maxx[0] = max2 (p1.X(), p2.X());
+  maxx[1] = max2 (p1.Y(), p2.Y());
+  maxx[2] = max2 (p1.Z(), p2.Z());
+}
+
+const Box3d& Box3d :: operator+=(const Box3d& b)
+{
+  minx[0] = min2 (minx[0], b.minx[0]);
+  minx[1] = min2 (minx[1], b.minx[1]);
+  minx[2] = min2 (minx[2], b.minx[2]);
+  maxx[0] = max2 (maxx[0], b.maxx[0]);
+  maxx[1] = max2 (maxx[1], b.maxx[1]);
+  maxx[2] = max2 (maxx[2], b.maxx[2]);
+
+  return *this;
+}
+
+Point3d Box3d :: MaxCoords() const
+{
+  return Point3d(maxx[0], maxx[1], maxx[2]);
+}
+
+Point3d Box3d :: MinCoords() const
+{
+  return Point3d(minx[0], minx[1], minx[2]);
+}
+
+/*
+void Box3d :: CreateNegMinMaxBox()
+{
+  minx[0] = MAXDOUBLE;
+  minx[1] = MAXDOUBLE;
+  minx[2] = MAXDOUBLE;
+  maxx[0] = MINDOUBLE;
+  maxx[1] = MINDOUBLE;
+  maxx[2] = MINDOUBLE;
+
+}
+*/
+
+void Box3d :: WriteData(ofstream& fout) const
+{
+  for(int i = 0; i < 3; i++)
+    {
+      fout << minx[i] << " " << maxx[i] << " ";
+    }
+  fout << "\n";
+}
+
+void Box3d :: ReadData(ifstream& fin)
+{
+  for(int i = 0; i < 3; i++)
+    {
+      fin >> minx[i];
+      fin >> maxx[i];
+    }
+}
+
+
+
+
+Box3dSphere :: Box3dSphere ( double aminx, double amaxx,
+			     double aminy, double amaxy,
+			     double aminz, double amaxz )
+  : Box3d (aminx, amaxx, aminy, amaxy, aminz, amaxz)
+{
+  CalcDiamCenter ();
+}
+
+
+void Box3dSphere :: CalcDiamCenter ()
+{
+  diam = sqrt( sqr (maxx[0] - minx[0]) +
+	       sqr (maxx[1] - minx[1]) + 
+	       sqr (maxx[2] - minx[2]));
+  
+  c.X() = 0.5 * (minx[0] + maxx[0]);
+  c.Y() = 0.5 * (minx[1] + maxx[1]);
+  c.Z() = 0.5 * (minx[2] + maxx[2]);
+  
+  inner = min2 ( min2 (maxx[0] - minx[0], maxx[1] - minx[1]), maxx[2] - minx[2]) / 2;
+}
+
+
+void Box3dSphere :: GetSubBox (int i, Box3dSphere & sbox) const
+{
+  i--;
+  if (i & 1)
+    {
+      sbox.minx[0] = c.X();
+      sbox.maxx[0] = maxx[0];
+    }
+  else
+    {
+      sbox.minx[0] = minx[0];
+      sbox.maxx[0] = c.X();
+    }
+  if (i & 2)
+    {
+      sbox.minx[1] = c.Y();
+      sbox.maxx[1] = maxx[1];
+    }
+  else
+    {
+      sbox.minx[1] = minx[1];
+      sbox.maxx[1] = c.Y();
+    }
+  if (i & 4)
+    {
+      sbox.minx[2] = c.Z();
+      sbox.maxx[2] = maxx[2];
+    }
+  else
+    {
+      sbox.minx[2] = minx[2];
+      sbox.maxx[2] = c.Z();
+    }
+  
+  //  sbox.CalcDiamCenter ();
+
+  sbox.c.X() = 0.5 * (sbox.minx[0] + sbox.maxx[0]);
+  sbox.c.Y() = 0.5 * (sbox.minx[1] + sbox.maxx[1]);
+  sbox.c.Z() = 0.5 * (sbox.minx[2] + sbox.maxx[2]);
+  sbox.diam = 0.5 * diam;
+  sbox.inner = 0.5 * inner;
+}
+
+
+
+
+/*
+double Determinant (const Vec3d & col1,
+		    const Vec3d & col2,
+		    const Vec3d & col3)
+{
+  return
+    col1.x[0] * ( col2.x[1] * col3.x[2] - col2.x[2] * col3.x[1]) +
+    col1.x[1] * ( col2.x[2] * col3.x[0] - col2.x[0] * col3.x[2]) +
+    col1.x[2] * ( col2.x[0] * col3.x[1] - col2.x[1] * col3.x[0]);
+}
+*/
+
+void Transpose (Vec3d & v1, Vec3d & v2, Vec3d & v3)
+{
+  Swap (v1.Y(), v2.X());
+  Swap (v1.Z(), v3.X());
+  Swap (v2.Z(), v3.Y());
+}
+
+
+int SolveLinearSystem (const Vec3d & col1, const Vec3d & col2,
+		       const Vec3d & col3, const Vec3d & rhs,
+		       Vec3d & sol)
+{
+  // changed by MW
+  double matrix[3][3];
+  double locrhs[3];
+  int retval = 0;
+
+  for(int i=0; i<3; i++)
+    {
+      matrix[i][0] = col1.X(i+1);
+      matrix[i][1] = col2.X(i+1);
+      matrix[i][2] = col3.X(i+1);
+      locrhs[i] = rhs.X(i+1);
+    }
+
+  for(int i=0; i<2; i++)
+    {
+      int pivot = i;
+      double maxv = fabs(matrix[i][i]);
+      for(int j=i+1; j<3; j++)
+	if(fabs(matrix[j][i]) > maxv)
+	  {
+	    maxv = fabs(matrix[j][i]);
+	    pivot = j;
+	  }
+
+      if(fabs(maxv) > 1e-40)
+	{
+	  if(pivot != i)
+	    {
+	      swap(matrix[i][0],matrix[pivot][0]);
+	      swap(matrix[i][1],matrix[pivot][1]);
+	      swap(matrix[i][2],matrix[pivot][2]);
+	      swap(locrhs[i],locrhs[pivot]);
+	    }
+	  for(int j=i+1; j<3; j++)
+	    {
+	      double fac = matrix[j][i] / matrix[i][i];
+	      
+	      for(int k=i+1; k<3; k++)
+		matrix[j][k] -= fac*matrix[i][k];
+	      locrhs[j] -= fac*locrhs[i];
+	    }
+	}
+      else
+	retval = 1;
+    }
+
+  if(fabs(matrix[2][2]) < 1e-40)
+    retval = 1;
+
+  if(retval != 0)
+    return retval;
+  
+
+  for(int i=2; i>=0; i--)
+    {
+      double sum = locrhs[i];
+      for(int j=2; j>i; j--)
+	sum -= matrix[i][j]*sol.X(j+1);
+
+      sol.X(i+1) = sum/matrix[i][i];
+    }
+
+  return 0;
+  
+  
+  
+
+
+  /*
+  double det = Determinant (col1, col2, col3);
+  if (fabs (det) < 1e-40)
+    return 1;
+  
+  sol.X() = Determinant (rhs, col2, col3) / det;
+  sol.Y() = Determinant (col1, rhs, col3) / det;
+  sol.Z() = Determinant (col1, col2, rhs) / det;
+
+  return 0;
+  */
+  /*
+  Vec3d cr;
+  Cross (col1, col2, cr);
+  double det = cr * col3;
+
+  if (fabs (det) < 1e-40)
+    return 1;
+
+  if (fabs(cr.Z()) > 1e-12)
+    {
+      // solve for 3. component
+      sol.Z() = (cr * rhs) / det;
+      
+      // 2x2 system for 1. and 2. component
+      double res1 = rhs.X() - sol.Z() * col3.X();
+      double res2 = rhs.Y() - sol.Z() * col3.Y();
+      
+      sol.X() = (col2.Y() * res1 - col2.X() * res2) / cr.Z();
+      sol.Y() = (col1.X() * res2 - col1.Y() * res1) / cr.Z();
+  
+    }
+  else
+    {
+      det = Determinant (col1, col2, col3);
+      if (fabs (det) < 1e-40)
+	return 1;
+      
+      sol.X() = Determinant (rhs, col2, col3) / det;
+      sol.Y() = Determinant (col1, rhs, col3) / det;
+      sol.Z() = Determinant (col1, col2, rhs) / det;
+    }
+
+  return 0;
+  */
+}
+
+
+int SolveLinearSystemLS (const Vec3d & col1,
+			 const Vec3d & col2,
+			 const Vec2d & rhs,
+			 Vec3d & sol)
+{
+  double a11 = col1 * col1;
+  double a12 = col1 * col2;
+  double a22 = col2 * col2;
+  
+  double det = a11 * a22 - a12 * a12;
+
+  if (det*det <= 1e-24 * a11 * a22)
+    {
+      sol = Vec3d (0, 0, 0);
+      return 1;
+    }
+  
+  Vec2d invrhs;
+  invrhs.X() = ( a22 * rhs.X() - a12 * rhs.Y()) / det;
+  invrhs.Y() = (-a12 * rhs.X() + a11 * rhs.Y()) / det;
+
+  sol.X() = invrhs.X() * col1.X() + invrhs.Y() * col2.X();
+  sol.Y() = invrhs.X() * col1.Y() + invrhs.Y() * col2.Y();
+  sol.Z() = invrhs.X() * col1.Z() + invrhs.Y() * col2.Z();
+
+  return 0;
+
+  /*
+  Vec3d inv1, inv2;
+  int err = 
+    PseudoInverse (col1, col2, inv1, inv2);
+
+   sol = rhs.X() * inv1 + rhs.Y() * inv2;
+   return err;
+  */
+}
+
+int SolveLinearSystemLS2 (const Vec3d & col1,
+			 const Vec3d & col2,
+			 const Vec2d & rhs,
+			 Vec3d & sol, double & x, double & y)
+{
+  double a11 = col1 * col1;
+  double a12 = col1 * col2;
+  double a22 = col2 * col2;
+  
+  double det = a11 * a22 - a12 * a12;
+
+  if (fabs (det) <= 1e-12 * col1.Length() * col2.Length() || 
+      col1.Length2() == 0 || col2.Length2() == 0)
+    {
+      sol = Vec3d (0, 0, 0);
+      x = 0; y = 0;
+      return 1;
+    }
+  
+  Vec2d invrhs;
+  invrhs.X() = ( a22 * rhs.X() - a12 * rhs.Y()) / det;
+  invrhs.Y() = (-a12 * rhs.X() + a11 * rhs.Y()) / det;
+
+  sol.X() = invrhs.X() * col1.X() + invrhs.Y() * col2.X();
+  sol.Y() = invrhs.X() * col1.Y() + invrhs.Y() * col2.Y();
+  sol.Z() = invrhs.X() * col1.Z() + invrhs.Y() * col2.Z();
+
+  x = invrhs.X();
+  y = invrhs.Y();
+
+  return 0;
+
+  /*
+  Vec3d inv1, inv2;
+  int err = 
+    PseudoInverse (col1, col2, inv1, inv2);
+
+   sol = rhs.X() * inv1 + rhs.Y() * inv2;
+   return err;
+  */
+}
+
+int PseudoInverse (const Vec3d & col1,
+		   const Vec3d & col2,
+		   Vec3d & inv1,
+		   Vec3d & inv2)
+{
+  double a11 = col1 * col1;
+  double a12 = col1 * col2;
+  double a22 = col2 * col2;
+  
+  double det = a11 * a22 - a12 * a12;
+
+  if (fabs (det) < 1e-12 * col1.Length() * col2.Length())
+    {
+      inv1 = Vec3d (0, 0, 0);
+      inv2 = Vec3d (0, 0, 0);
+      return 1;
+    }
+
+  double ia11 = a22 / det;
+  double ia12 = -a12 / det;
+  double ia22 = a11 / det;
+
+  inv1 = ia11 * col1 + ia12 * col2;
+  inv2 = ia12 * col1 + ia22 * col2;
+
+  return 0;
+}
+
+
+
+
+QuadraticFunction3d :: 
+QuadraticFunction3d (const Point3d & p, const Vec3d & v)
+{
+  Vec3d hv(v);
+  hv /= (hv.Length() + 1e-12);
+  Vec3d t1, t2;
+  hv.GetNormal (t1);
+  Cross (hv, t1, t2);
+  
+  double t1p = t1.X() * p.X() + t1.Y() * p.Y() + t1.Z() * p.Z();
+  double t2p = t2.X() * p.X() + t2.Y() * p.Y() + t2.Z() * p.Z();
+  c0 = sqr (t1p) + sqr (t2p);
+  cx = -2 * (t1p * t1.X() + t2p * t2.X());
+  cy = -2 * (t1p * t1.Y() + t2p * t2.Y());
+  cz = -2 * (t1p * t1.Z() + t2p * t2.Z());
+
+  cxx = t1.X() * t1.X() + t2.X() * t2.X();
+  cyy = t1.Y() * t1.Y() + t2.Y() * t2.Y();
+  czz = t1.Z() * t1.Z() + t2.Z() * t2.Z();
+
+  cxy = 2 * t1.X() * t1.Y() + 2 * t2.X() * t2.Y();
+  cxz = 2 * t1.X() * t1.Z() + 2 * t2.X() * t2.Z();
+  cyz = 2 * t1.Y() * t1.Z() + 2 * t2.Y() * t2.Z();
+
+  /*
+  (*testout) << "c0 = " << c0
+	     << " clin = " << cx << " " << cy << " " << cz 
+	     << " cq = " << cxx << " " << cyy << " " << czz
+	     << cxy << " " << cyz << " " << cyz << endl;
+  */
+}
+
+// QuadraticFunction3d gqf (Point3d (0,0,0), Vec3d (1, 0, 0));
+
+
+
+
+
+void referencetransform :: Set (const Point3d & p1, const Point3d & p2,
+                                const Point3d & p3, double ah)
+{
+  ex = p2 - p1;
+  ex /= ex.Length();
+  ey = p3 - p1;
+  ey -= (ex * ey) * ex;
+  ey /= ey.Length();
+  ez = Cross (ex, ey);
+  rp = p1;
+  h = ah;
+
+  exh = ah * ex;
+  eyh = ah * ey;
+  ezh = ah * ez;
+  ah = 1 / ah;
+  ex_h = ah * ex;
+  ey_h = ah * ey;
+  ez_h = ah * ez;
+}
+
+void referencetransform :: ToPlain (const Point3d & p, Point3d & pp) const
+{
+  Vec3d v;
+  v = p - rp;
+  pp.X() = (ex_h * v);
+  pp.Y() = (ey_h * v);
+  pp.Z() = (ez_h * v);
+}
+
+void referencetransform :: ToPlain (const ARRAY<Point3d> & p,
+                                    ARRAY<Point3d> & pp) const
+{
+  Vec3d v;
+  int i;
+
+  pp.SetSize (p.Size());
+  for (i = 1; i <= p.Size(); i++)
+    {
+      v = p.Get(i) - rp;
+      pp.Elem(i).X() = (ex_h * v);
+      pp.Elem(i).Y() = (ey_h * v);
+      pp.Elem(i).Z() = (ez_h * v);
+    }
+}
+
+void referencetransform :: FromPlain (const Point3d & pp, Point3d & p) const
+{
+  Vec3d v;
+  //  v = (h * pp.X()) * ex + (h * pp.Y()) * ey + (h * pp.Z()) * ez;
+  //  p = rp + v;
+  v.X() = pp.X() * exh.X() + pp.Y() * eyh.X() + pp.Z() * ezh.X();
+  v.Y() = pp.X() * exh.Y() + pp.Y() * eyh.Y() + pp.Z() * ezh.Y();
+  v.Z() = pp.X() * exh.Z() + pp.Y() * eyh.Z() + pp.Z() * ezh.Z();
+  p.X() = rp.X() + v.X();
+  p.Y() = rp.Y() + v.Y();
+  p.Z() = rp.Z() + v.Z();
+}
+
+
+}
diff --git a/contrib/Netgen/libsrc/gprim/geom3d.hpp b/contrib/Netgen/libsrc/gprim/geom3d.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..c5e8eecbda12398f6cf2a18ed8735db500df2f08
--- /dev/null
+++ b/contrib/Netgen/libsrc/gprim/geom3d.hpp
@@ -0,0 +1,731 @@
+#ifndef FILE_GEOM3D
+#define FILE_GEOM3D
+
+/* *************************************************************************/
+/* File:   geom3d.hh                                                       */
+/* Author: Joachim Schoeberl                                               */
+/* Date:   5. Aug. 95                                                      */
+/* *************************************************************************/
+
+
+
+
+extern void MyError (const char * ch);
+
+class Point3d;
+class Vec3d;
+
+inline Vec3d operator- (const Point3d & p1, const Point3d & p2);
+inline Point3d operator- (const Point3d & p1, const Vec3d & v);
+inline Point3d operator+ (const Point3d & p1, const Vec3d & v);
+Point3d & Add (double d, const Vec3d & v);
+Point3d & Add2 (double d, const Vec3d & v,
+			 double d2, const Vec3d & v2);
+inline Point3d Center (const Point3d & p1, const Point3d & p2);
+inline Point3d Center (const Point3d & p1, const Point3d & p2, const Point3d & p3);
+inline Point3d Center (const Point3d & p1, const Point3d & p2, 
+				const Point3d & p3, const Point3d & p4);
+ostream & operator<<(ostream  & s, const Point3d & p);
+inline Vec3d operator- (const Vec3d & p1, const Vec3d & v);
+inline Vec3d operator+ (const Vec3d & p1, const Vec3d & v);
+inline Vec3d operator* (double scal, const Vec3d & v);
+inline double operator* (const Vec3d & v1, const Vec3d & v2);
+inline Vec3d Cross (const Vec3d & v1, const Vec3d & v2);
+inline void Cross (const Vec3d & v1, const Vec3d & v2, Vec3d & prod);
+double Angle (const Vec3d & v);
+double FastAngle (const Vec3d & v);
+double Angle (const Vec3d & v1, const Vec3d & v2);
+double FastAngle (const Vec3d & v1, const Vec3d & v2);
+ostream & operator<<(ostream  & s, const Vec3d & v);
+void Transpose (Vec3d & v1, Vec3d & v2, Vec3d & v3);
+int SolveLinearSystem (const Vec3d & col1,
+		       const Vec3d & col2,
+		       const Vec3d & col3,
+		       const Vec3d & rhs,
+		       Vec3d & sol);
+int SolveLinearSystemLS (const Vec3d & col1,
+			 const Vec3d & col2,
+			 const Vec2d & rhs,
+			 Vec3d & sol);
+int SolveLinearSystemLS2 (const Vec3d & col1,
+			  const Vec3d & col2,
+			  const Vec2d & rhs, 
+			  Vec3d & sol,
+			  double & x, double & y);
+int PseudoInverse (const Vec3d & col1,
+		   const Vec3d & col2,
+		   Vec3d & inv1,
+		   Vec3d & inv2);
+double Determinant (const Vec3d & col1,
+		    const Vec3d & col2,
+		    const Vec3d & col3);
+
+/// Point in R3
+class Point3d
+{
+protected:
+  ///
+  double x[3];
+  
+public:
+  ///
+  Point3d () { x[0] = x[1] = x[2] = 0; }
+  ///
+  Point3d(double ax, double ay, double az) 
+    { x[0] = ax; x[1] = ay; x[2] = az; }
+  ///
+  Point3d(double ax[3])
+    { x[0] = ax[0]; x[1] = ax[1]; x[2] = ax[2]; }
+
+  ///
+  Point3d(const Point3d & p2) 
+    { x[0] = p2.x[0]; x[1] = p2.x[1]; x[2] = p2.x[2]; }
+
+  Point3d (const Point<3> & p2)
+  {
+    for (int i = 0; i < 3; i++)
+      x[i] = p2(i);
+  }
+  
+  ///
+  Point3d & operator= (const Point3d & p2)
+    { x[0] = p2.x[0]; x[1] = p2.x[1]; x[2] = p2.x[2]; return *this; }
+  
+  ///
+  int operator== (const Point3d& p) const
+    { return (x[0] == p.x[0] && x[1] == p.x[1] && x[2] == p.x[2]); }
+  
+  ///
+  double & X() { return x[0]; }
+  ///
+  double & Y() { return x[1]; }
+  ///
+  double & Z() { return x[2]; }
+  ///
+  double X() const { return x[0]; }
+  ///
+  double Y() const { return x[1]; }
+  ///
+  double Z() const { return x[2]; }
+  ///
+  double & X(int i) { return x[i-1]; }
+  ///
+  double X(int i) const { return x[i-1]; }
+  ///
+  const Point3d & SetToMin (const Point3d & p2)
+    {
+      if (p2.x[0] < x[0]) x[0] = p2.x[0];
+      if (p2.x[1] < x[1]) x[1] = p2.x[1];
+      if (p2.x[2] < x[2]) x[2] = p2.x[2];
+      return *this;
+    }
+
+  ///
+  const Point3d & SetToMax (const Point3d & p2)
+    {
+      if (p2.x[0] > x[0]) x[0] = p2.x[0];
+      if (p2.x[1] > x[1]) x[1] = p2.x[1];
+      if (p2.x[2] > x[2]) x[2] = p2.x[2];
+      return *this;
+    }
+
+  ///
+  friend inline Vec3d operator- (const Point3d & p1, const Point3d & p2);
+  ///
+  friend inline Point3d operator- (const Point3d & p1, const Vec3d & v);
+  ///
+  friend inline Point3d operator+ (const Point3d & p1, const Vec3d & v);
+  ///
+  inline Point3d & operator+= (const Vec3d & v);
+  inline Point3d & operator-= (const Vec3d & v);
+  ///
+  inline Point3d & Add (double d, const Vec3d & v);
+  ///
+  inline Point3d & Add2 (double d, const Vec3d & v,
+			 double d2, const Vec3d & v2);
+  ///
+  friend inline double Dist (const Point3d & p1, const Point3d & p2)
+    { return sqrt (  (p1.x[0]-p2.x[0]) * (p1.x[0]-p2.x[0]) + 
+		     (p1.x[1]-p2.x[1]) * (p1.x[1]-p2.x[1]) +
+                     (p1.x[2]-p2.x[2]) * (p1.x[2]-p2.x[2])); }
+  ///
+  inline friend double Dist2 (const Point3d & p1, const Point3d & p2)
+    { return  (  (p1.x[0]-p2.x[0]) * (p1.x[0]-p2.x[0]) + 
+		 (p1.x[1]-p2.x[1]) * (p1.x[1]-p2.x[1]) +
+		 (p1.x[2]-p2.x[2]) * (p1.x[2]-p2.x[2])); }
+
+  ///
+  friend inline Point3d Center (const Point3d & p1, const Point3d & p2);
+  ///
+  friend inline Point3d Center (const Point3d & p1, const Point3d & p2, const Point3d & p3);
+  ///
+  friend inline Point3d Center (const Point3d & p1, const Point3d & p2, 
+				const Point3d & p3, const Point3d & p4);
+  ///
+  friend ostream & operator<<(ostream  & s, const Point3d & p);
+  
+  ///
+  friend class Vec3d;
+  ///
+  friend class Box3d;
+
+
+  operator Point<3> () const
+  {
+    return Point<3> (x[0], x[1], x[2]);
+  }
+};
+
+
+///
+class Vec3d
+{
+protected:
+  ///
+  double x[3];
+
+public:
+  ///
+  inline Vec3d() { x[0] = x[1] = x[2] = 0; }
+  ///
+  inline Vec3d(double ax, double ay, double az)
+    { x[0] = ax; x[1] = ay; x[2] = az; }
+  ///
+  Vec3d(double ax[3])
+    { x[0] = ax[0]; x[1] = ax[1]; x[2] = ax[2]; }
+  ///
+  inline Vec3d(const Vec3d & v2) 
+    { x[0] = v2.x[0]; x[1] = v2.x[1]; x[2] = v2.x[2]; }
+  ///
+  inline Vec3d(const Point3d & p1, const Point3d & p2)
+    { 
+      x[0] = p2.x[0] - p1.x[0];
+      x[1] = p2.x[1] - p1.x[1];
+      x[2] = p2.x[2] - p1.x[2]; 
+    }
+  ///
+  inline Vec3d(const Point3d & p1)
+    { 
+      x[0] = p1.x[0];
+      x[1] = p1.x[1];
+      x[2] = p1.x[2];
+    }
+  
+  Vec3d (const Vec<3> & v2)
+  {
+    for (int i = 0; i < 3; i++)
+      x[i] = v2(i);
+  }
+
+  operator Vec<3> () const
+  {
+    return Vec<3> (x[0], x[1], x[2]);
+  }
+
+
+  Vec3d & operator= (const Vec3d & v2)
+    { x[0] = v2.x[0]; x[1] = v2.x[1]; x[2] = v2.x[2]; return *this; }
+  ///
+  Vec3d & operator= (double val)
+    { x[0] = x[1] = x[2] = val; return *this; }
+  ///
+  double & X() { return x[0]; }
+  ///
+  double & Y() { return x[1]; }
+  ///
+  double & Z() { return x[2]; }
+  ///
+  double & X(int i) { return x[i-1]; }
+
+  ///
+  double X() const { return x[0]; }
+  ///
+  double Y() const { return x[1]; }
+  ///
+  double Z() const { return x[2]; }
+  ///
+  double X(int i) const { return x[i-1]; }
+
+  ///
+  double Length() const 
+    { return sqrt (x[0] * x[0] + x[1] * x[1] + x[2] * x[2]); }
+  ///
+  double Length2() const 
+    { return x[0] * x[0] + x[1] * x[1] + x[2] * x[2]; }
+
+  ///
+  Vec3d & operator+= (const Vec3d & v2);
+  ///
+  Vec3d & operator-= (const Vec3d & v2);
+  ///
+  Vec3d & operator*= (double s);
+  ///
+  Vec3d & operator/= (double s);
+  ///
+  inline Vec3d & Add (double d, const Vec3d & v);
+  ///
+  inline Vec3d & Add2 (double d, const Vec3d & v,
+			 double d2, const Vec3d & v2);
+
+  ///
+  friend inline Vec3d operator- (const Point3d & p1, const Point3d & p2);
+  ///
+  friend inline Point3d operator- (const Point3d & p1, const Vec3d & v);
+  ///
+  friend inline Point3d operator+ (const Point3d & p1, const Vec3d & v);
+  ///
+  friend inline Vec3d operator- (const Vec3d & p1, const Vec3d & v);
+  ///
+  friend inline Vec3d operator+ (const Vec3d & p1, const Vec3d & v);
+  ///
+  friend inline Vec3d operator* (double scal, const Vec3d & v);
+
+  ///
+  friend inline double operator* (const Vec3d & v1, const Vec3d & v2);
+  ///
+  friend inline Vec3d Cross (const Vec3d & v1, const Vec3d & v2);
+  ///
+  friend inline void Cross (const Vec3d & v1, const Vec3d & v2, Vec3d & prod);
+
+  /// Returns one normal-vector to n
+  void GetNormal (Vec3d & n) const;
+  ///
+  friend double Angle (const Vec3d & v);
+  ///
+  friend double FastAngle (const Vec3d & v);
+  ///
+  friend double Angle (const Vec3d & v1, const Vec3d & v2);
+  ///
+  friend double FastAngle (const Vec3d & v1, const Vec3d & v2);
+
+  void Normalize() 
+  {
+    double len = (x[0] * x[0] + x[1] * x[1] + x[2] * x[2]);
+    if (len == 0) return;
+    len = sqrt (len);
+    x[0] /= len; x[1] /= len; x[2] /= len;
+  }
+
+  ///
+  friend ostream & operator<<(ostream  & s, const Vec3d & v);
+
+  ///
+  friend class Point3d;
+  friend void Transpose (Vec3d & v1, Vec3d & v2, Vec3d & v3);
+  friend int SolveLinearSystem (const Vec3d & col1,
+				const Vec3d & col2,
+				const Vec3d & col3,
+				const Vec3d & rhs,
+				Vec3d & sol);
+  friend int SolveLinearSystemLS (const Vec3d & col1,
+				  const Vec3d & col2,
+				  const Vec2d & rhs,
+				  Vec3d & sol);
+  friend int SolveLinearSystemLS2 (const Vec3d & col1,
+				   const Vec3d & col2,
+				   const Vec2d & rhs, 
+				   Vec3d & sol,
+				   double & x, double & y);
+  friend int PseudoInverse (const Vec3d & col1,
+			    const Vec3d & col2,
+			    Vec3d & inv1,
+			    Vec3d & inv2);
+  friend double Determinant (const Vec3d & col1,
+			     const Vec3d & col2,
+			     const Vec3d & col3);
+};
+
+
+
+class QuadraticFunction3d
+{
+  double c0, cx, cy, cz;
+  double cxx, cyy, czz, cxy, cxz, cyz;
+
+public:
+  QuadraticFunction3d (const Point3d & p, const Vec3d & v);
+  double Eval (const Point3d & p)
+    {
+      return 
+	c0 
+	+ p.X() * (cx + cxx * p.X() + cxy * p.Y() + cxz * p.Z())
+	+ p.Y() * (cy + cyy * p.Y() + cyz * p.Z())
+	+ p.Z() * (cz + czz * p.Z());
+    }
+};
+
+
+
+inline Point3d Center (const Point3d & p1, const Point3d & p2)
+{
+  return Point3d (0.5 * (p1.x[0] + p2.x[0]),
+		  0.5 * (p1.x[1] + p2.x[1]),
+		  0.5 * (p1.x[2] + p2.x[2]));
+}
+
+
+inline Point3d Center (const Point3d & p1, const Point3d & p2,
+                       const Point3d & p3)
+{
+  return Point3d (1.0/3.0 * (p1.x[0] + p2.x[0] + p3.x[0]),
+		  1.0/3.0 * (p1.x[1] + p2.x[1] + p3.x[1]),
+		  1.0/3.0 * (p1.x[2] + p2.x[2] + p3.x[2]));
+}
+
+inline Point3d Center (const Point3d & p1, const Point3d & p2,
+                       const Point3d & p3, const Point3d & p4)
+{
+  return Point3d (0.25 * (p1.x[0] + p2.x[0] + p3.x[0] + p4.x[0]),
+		  0.25 * (p1.x[1] + p2.x[1] + p3.x[1] + p4.x[1]),
+		  0.25 * (p1.x[2] + p2.x[2] + p3.x[2] + p4.x[2]));
+}
+
+
+
+inline Vec3d & Vec3d :: operator+= (const Vec3d & v2)
+{
+  x[0] += v2.x[0];
+  x[1] += v2.x[1];
+  x[2] += v2.x[2];
+  return *this;
+}
+
+inline Vec3d & Vec3d :: operator-= (const Vec3d & v2)
+{
+  x[0] -= v2.x[0];
+  x[1] -= v2.x[1];
+  x[2] -= v2.x[2];
+  return *this;
+}
+
+
+inline Vec3d & Vec3d :: operator*= (double s)
+{
+  x[0] *= s;
+  x[1] *= s;
+  x[2] *= s;
+  return *this;
+}
+
+
+inline Vec3d & Vec3d :: operator/= (double s)
+{
+  if (s != 0)
+    {
+      x[0] /= s;
+      x[1] /= s;
+      x[2] /= s;
+    }
+#ifdef DEBUG
+  else
+    {
+      cerr << "Vec div by 0, v = " << (*this) << endl;
+      //      MyError ("Vec3d::operator /=: Divisioin by zero");
+    }
+#endif
+  return *this;
+}
+
+inline Vec3d & Vec3d::Add (double d, const Vec3d & v)
+{
+  x[0] += d * v.x[0]; 
+  x[1] += d * v.x[1]; 
+  x[2] += d * v.x[2];
+  return *this;
+}
+
+inline Vec3d & Vec3d::Add2 (double d, const Vec3d & v,
+			    double d2, const Vec3d & v2)
+{
+  x[0] += d * v.x[0] + d2 * v2.x[0]; 
+  x[1] += d * v.x[1] + d2 * v2.x[1]; 
+  x[2] += d * v.x[2] + d2 * v2.x[2]; 
+  return *this;
+}
+
+
+
+
+
+
+
+
+inline Vec3d operator- (const Point3d & p1, const Point3d & p2)
+{
+  return Vec3d (p1.x[0] - p2.x[0], p1.x[1] - p2.x[1],p1.x[2] - p2.x[2]);
+}
+
+
+inline Point3d operator- (const Point3d & p1, const Vec3d & v)
+{
+  return Point3d (p1.x[0] - v.x[0], p1.x[1] - v.x[1],p1.x[2] - v.x[2]);
+}
+
+
+inline Point3d operator+ (const Point3d & p1, const Vec3d & v)
+{
+  return Point3d (p1.x[0] + v.x[0], p1.x[1] + v.x[1],p1.x[2] + v.x[2]);
+}
+
+inline Point3d & Point3d::operator+= (const Vec3d & v) 
+{
+  x[0] += v.x[0]; 
+  x[1] += v.x[1]; 
+  x[2] += v.x[2];
+  return *this;
+}
+
+inline Point3d & Point3d::operator-= (const Vec3d & v) 
+{
+  x[0] -= v.x[0]; 
+  x[1] -= v.x[1]; 
+  x[2] -= v.x[2];
+  return *this;
+}
+
+inline Point3d & Point3d::Add (double d, const Vec3d & v)
+{
+  x[0] += d * v.x[0]; 
+  x[1] += d * v.x[1]; 
+  x[2] += d * v.x[2];
+  return *this;
+}
+
+inline Point3d & Point3d::Add2 (double d, const Vec3d & v,
+				double d2, const Vec3d & v2)
+{
+  x[0] += d * v.x[0] + d2 * v2.x[0]; 
+  x[1] += d * v.x[1] + d2 * v2.x[1]; 
+  x[2] += d * v.x[2] + d2 * v2.x[2]; 
+  return *this;
+}
+
+
+inline Vec3d operator- (const Vec3d & v1, const Vec3d & v2)
+{
+  return Vec3d (v1.x[0] - v2.x[0], v1.x[1] - v2.x[1],v1.x[2] - v2.x[2]);
+}
+
+
+inline Vec3d operator+ (const Vec3d & v1, const Vec3d & v2)
+{
+  return Vec3d (v1.x[0] + v2.x[0], v1.x[1] + v2.x[1],v1.x[2] + v2.x[2]);
+}
+
+
+inline Vec3d operator* (double scal, const Vec3d & v)
+{
+  return Vec3d (scal * v.x[0], scal * v.x[1], scal * v.x[2]);
+}
+
+
+
+inline double operator* (const Vec3d & v1, const Vec3d & v2)
+{
+  return v1.x[0] * v2.x[0] + v1.x[1] * v2.x[1] + v1.x[2] * v2.x[2];
+}
+
+
+
+inline Vec3d Cross (const Vec3d & v1, const Vec3d & v2)
+{
+  return Vec3d
+    ( v1.x[1] * v2.x[2] - v1.x[2] * v2.x[1],
+      v1.x[2] * v2.x[0] - v1.x[0] * v2.x[2],
+      v1.x[0] * v2.x[1] - v1.x[1] * v2.x[0]);
+}
+
+inline void Cross (const Vec3d & v1, const Vec3d & v2, Vec3d & prod)
+{
+  prod.x[0] = v1.x[1] * v2.x[2] - v1.x[2] * v2.x[1];
+  prod.x[1] = v1.x[2] * v2.x[0] - v1.x[0] * v2.x[2];
+  prod.x[2] = v1.x[0] * v2.x[1] - v1.x[1] * v2.x[0];
+}
+
+inline double Determinant (const Vec3d & col1,
+			   const Vec3d & col2,
+			   const Vec3d & col3)
+{
+  return
+    col1.x[0] * ( col2.x[1] * col3.x[2] - col2.x[2] * col3.x[1]) +
+    col1.x[1] * ( col2.x[2] * col3.x[0] - col2.x[0] * col3.x[2]) +
+    col1.x[2] * ( col2.x[0] * col3.x[1] - col2.x[1] * col3.x[0]);
+}
+
+
+///
+class Box3d
+{
+protected:
+  ///
+  double minx[3], maxx[3];
+
+public:
+  ///
+  Box3d () { };
+  ///
+  Box3d ( double aminx, double amaxx,
+          double aminy, double amaxy,
+          double aminz, double amaxz );
+  ///
+  Box3d ( const Box3d & b2 );
+  ///
+  Box3d (const Point3d& p1, const Point3d& p2);
+  ///
+  Box3d (const Box<3> & b2);
+  ///
+  double MinX () const { return minx[0]; }
+  ///
+  double MaxX () const { return maxx[0]; }
+  ///
+  double MinY () const { return minx[1]; }
+  ///
+  double MaxY () const { return maxx[1]; }
+  ///
+  double MinZ () const { return minx[2]; }
+  ///
+  double MaxZ () const { return maxx[2]; }
+
+  ///
+  double Mini (int i) const { return minx[i-1]; }
+  ///
+  double Maxi (int i) const { return maxx[i-1]; }
+
+  ///
+  Point3d PMin () const { return Point3d(minx[0], minx[1], minx[2]); }
+  ///
+  Point3d PMax () const { return Point3d(maxx[0], maxx[1], maxx[2]); }
+
+  ///
+  void GetPointNr (int i, Point3d & point) const;
+  /// increase Box at each side with dist 
+  void Increase (double dist);
+  /// increase Box by factor rel
+  void IncreaseRel (double rel);
+  /// return 1 if closures are intersecting
+  int Intersect (const Box3d & box2) const
+  {
+    if (minx[0] > box2.maxx[0] || maxx[0] < box2.minx[0] ||
+	minx[1] > box2.maxx[1] || maxx[1] < box2.minx[1] ||
+	minx[2] > box2.maxx[2] || maxx[2] < box2.minx[2])
+      return 0;
+    return 1;
+  }
+  /// return 1 if point p in closure
+  int IsIn (const Point3d & p) const
+    {
+      if (minx[0] <= p.x[0] && maxx[0] >= p.x[0] &&
+	  minx[1] <= p.x[1] && maxx[1] >= p.x[1] &&
+	  minx[2] <= p.x[2] && maxx[2] >= p.x[2])
+	return 1;
+      return 0;
+    }
+  ///
+  inline void SetPoint (const Point3d & p)
+    {
+      minx[0] = maxx[0] = p.X();
+      minx[1] = maxx[1] = p.Y();
+      minx[2] = maxx[2] = p.Z();    
+    }
+
+  ///
+  inline void AddPoint (const Point3d & p)
+    {
+      if (p.x[0] < minx[0]) minx[0] = p.x[0];
+      if (p.x[0] > maxx[0]) maxx[0] = p.x[0];
+      if (p.x[1] < minx[1]) minx[1] = p.x[1];
+      if (p.x[1] > maxx[1]) maxx[1] = p.x[1];
+      if (p.x[2] < minx[2]) minx[2] = p.x[2];
+      if (p.x[2] > maxx[2]) maxx[2] = p.x[2];
+    }
+
+  ///
+  const Box3d& operator+=(const Box3d& b);
+
+  ///
+  Point3d MaxCoords() const;
+  ///
+  Point3d MinCoords() const;
+
+  /// Make a negative sized box;
+  //  void CreateNegMinMaxBox();
+  
+  ///
+  Point3d CalcCenter () const { return Point3d(0.5*(minx[0] + maxx[0]),
+					       0.5*(minx[1] + maxx[1]),
+					       0.5*(minx[2] + maxx[2])); }
+  ///
+  double CalcDiam () const { return sqrt(sqr(maxx[0]-minx[0])+
+					 sqr(maxx[1]-minx[1])+
+					 sqr(maxx[2]-minx[2])); }
+
+  ///
+  void WriteData(ofstream& fout) const;
+  ///
+  void ReadData(ifstream& fin);
+};
+
+
+class Box3dSphere : public Box3d
+{
+protected:
+  ///
+  double diam, inner;
+  ///
+  Point3d c;
+public:
+  ///
+  Box3dSphere () { };
+  ///
+  Box3dSphere ( double aminx, double amaxx,
+		double aminy, double amaxy,
+		double aminz, double amaxz);
+  ///
+  const Point3d & Center () const { return c; }
+
+  ///
+  double Diam () const { return diam; }
+  ///
+  double Inner () const { return inner; }
+  ///
+  void GetSubBox (int i, Box3dSphere & sbox) const;
+
+  // private:
+  ///
+  void CalcDiamCenter ();
+};
+
+
+
+
+///
+class referencetransform
+{
+  ///
+  Vec3d ex, ey, ez;
+  ///
+  Vec3d exh, eyh, ezh;
+  ///
+  Vec3d ex_h, ey_h, ez_h;
+  ///
+  Point3d rp;
+  ///
+  double h;
+
+public:
+
+  ///
+  void Set (const Point3d & p1, const Point3d & p2,
+            const Point3d & p3, double ah);
+
+  ///
+  void ToPlain (const Point3d & p, Point3d & pp) const;
+  ///
+  void ToPlain (const ARRAY<Point3d> & p, ARRAY<Point3d> & pp) const;
+  ///
+  void FromPlain (const Point3d & pp, Point3d & p) const;
+};
+
+
+
+#endif
diff --git a/contrib/Netgen/libsrc/gprim/geomfuncs.cpp b/contrib/Netgen/libsrc/gprim/geomfuncs.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..b2ac83824a8908e1e2a5be3417ad5e79057f3f72
--- /dev/null
+++ b/contrib/Netgen/libsrc/gprim/geomfuncs.cpp
@@ -0,0 +1,111 @@
+#include <mystdlib.h>
+
+#include <myadt.hpp>
+#include <gprim.hpp>
+
+namespace netgen
+{
+
+  /*
+  // template <>
+inline void CalcInverse (const Mat<2,2> & m, Mat<2,2> & inv)
+{
+  double det = m(0,0) * m(1,1) - m(0,1) * m(1,0);
+  if (det == 0) 
+    {
+      inv = 0;
+      return;
+    }
+
+  double idet = 1.0 / det;
+  inv(0,0) =  idet * m(1,1);
+  inv(0,1) = -idet * m(0,1);
+  inv(1,0) = -idet * m(1,0);
+  inv(1,1) =  idet * m(0,0);
+}
+  */
+
+
+
+  // template <>
+void CalcInverse (const Mat<3,3> & m, Mat<3,3> & inv)
+{
+  double det = Det (m);
+  if (det == 0) 
+    {
+      inv = 0;
+      return;
+    }
+
+  double idet = 1.0 / det;
+  inv(0,0) =  idet * (m(1,1) * m(2,2) - m(1,2) * m(2,1));
+  inv(1,0) = -idet * (m(1,0) * m(2,2) - m(1,2) * m(2,0));
+  inv(2,0) =  idet * (m(1,0) * m(2,1) - m(1,1) * m(2,0));
+
+  inv(0,1) = -idet * (m(0,1) * m(2,2) - m(0,2) * m(2,1));
+  inv(1,1) =  idet * (m(0,0) * m(2,2) - m(0,2) * m(2,0));
+  inv(2,1) = -idet * (m(0,0) * m(2,1) - m(0,1) * m(2,0));
+
+  inv(0,2) =  idet * (m(0,1) * m(1,2) - m(0,2) * m(1,1));
+  inv(1,2) = -idet * (m(0,0) * m(1,2) - m(0,2) * m(1,0));
+  inv(2,2) =  idet * (m(0,0) * m(1,1) - m(0,1) * m(1,0));
+}
+
+/*
+// template <>
+void CalcInverse (const Mat<2,3> & m, Mat<3,2> & inv)
+{
+  Mat<2,2> a = m * Trans (m);
+  Mat<2,2> ainv;
+  CalcInverse (a, ainv);
+  inv = Trans (m) * ainv;
+}
+*/
+
+
+
+double Det (const Mat<2,2> & m) 
+{
+  return  m(0,0) * m(1,1) - m(0,1) * m(1,0);
+}
+
+double Det (const Mat<3,3> & m) 
+{
+  return 
+    m(0,0) * m(1,1) * m(2,2)
+    + m(1,0) * m(2,1) * m(0,2)
+    + m(2,0) * m(0,1) * m(1,2)
+    - m(0,0) * m(2,1) * m(1,2)
+    - m(1,0) * m(0,1) * m(2,2)
+    - m(2,0) * m(1,1) * m(0,2);
+}
+
+
+void EigenValues (const Mat<3,3> & m, Vec<3> & ev)
+{
+  const double pi = 3.141592;
+  double a, b, c, d;
+  double p, q;
+  double arg;
+
+  a = -1.;
+  b = m(0,0) + m(1,1) + m(2,2);
+  c = -( m(0,0)*m(2,2) + m(1,1)*m(2,2) + m(0,0)*m(1,1) - sqr(m(0,1)) - sqr(m(0,2)) - sqr(m(1,2)) );
+  d = Det (m);
+  p = 3.*a*c - sqr(b);
+  q = 27.*sqr(a)*d - 9.*a*b*c + 2.*sqr(b)*b;
+
+
+  arg = acos((-q/2)/sqrt(-(p*p*p)));
+
+
+  ev(0) = (2. * sqrt(-p) * cos(arg/3.) - b) / 3.*a;
+  ev(1) = (-2. * sqrt(-p) * cos(arg/3.+pi/3) - b) / 3.*a;
+  ev(2) = (-2. * sqrt(-p) * cos(arg/3.-pi/3)- b) / 3.*a;
+
+
+
+}
+
+
+}
diff --git a/contrib/Netgen/libsrc/gprim/geomfuncs.hpp b/contrib/Netgen/libsrc/gprim/geomfuncs.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..4c8a51ee439ad968c895736e42a4f4199b253463
--- /dev/null
+++ b/contrib/Netgen/libsrc/gprim/geomfuncs.hpp
@@ -0,0 +1,157 @@
+#ifndef FILE_GEOMFUNCS
+#define FILE_GEOMFUNCS
+
+/* *************************************************************************/
+/* File:   geomfuncs.hpp                                                   */
+/* Author: Joachim Schoeberl                                               */
+/* Date:   20. Jul. 02                                                     */
+/* *************************************************************************/
+
+
+template <int D>
+inline double Abs (const Vec<D> & v)
+{
+  double sum = 0;
+  for (int i = 0; i < D; i++)
+    sum += v(i) * v(i);
+  return sqrt (sum);
+}
+
+
+template <int D>
+inline double Abs2 (const Vec<D> & v)
+{
+  double sum = 0;
+  for (int i = 0; i < D; i++)
+    sum += v(i) * v(i);
+  return sum;
+}
+
+
+
+template <int D>
+inline double Dist (const Point<D> & a, const Point<D> & b)
+{
+  return Abs (a-b);
+}
+
+template <int D>
+inline double Dist2 (const Point<D> & a, const Point<D> & b)
+{
+  return Abs2 (a-b);
+}
+
+
+template <int D>
+inline Point<D> Center (const Point<D> & a, const Point<D> & b)
+{
+  Point<D> res;
+  for (int i = 0; i < D; i++)
+    res(i) = 0.5 * (a(i) + b(i));
+  return res;
+}
+
+template <int D>
+inline Point<D> Center (const Point<D> & a, const Point<D> & b, const Point<D> & c)
+{
+  Point<D> res;
+  for (int i = 0; i < D; i++)
+    res(i) = (1.0/3.0) * (a(i) + b(i) + c(i));
+  return res;
+}
+
+template <int D>
+inline Point<D> Center (const Point<D> & a, const Point<D> & b, const Point<D> & c, const Point<D> & d)
+{
+  Point<D> res;
+  for (int i = 0; i < D; i++)
+    res(i) = (1.0/4.0) * (a(i) + b(i) + c(i) + d(i));
+  return res;
+}
+
+
+
+inline Vec<3> Cross (const Vec<3> & v1, const Vec<3> & v2)
+{
+  return Vec<3> 
+    ( v1(1) * v2(2) - v1(2) * v2(1),
+      v1(2) * v2(0) - v1(0) * v2(2),
+      v1(0) * v2(1) - v1(1) * v2(0) );
+}
+
+
+inline double Determinant (const Vec<3> & col1,
+			   const Vec<3> & col2,
+			   const Vec<3> & col3)
+{
+  return
+    col1(0) * ( col2(1) * col3(2) - col2(2) * col3(1)) +
+    col1(1) * ( col2(2) * col3(0) - col2(0) * col3(2)) +
+    col1(2) * ( col2(0) * col3(1) - col2(1) * col3(0));
+}
+
+
+
+template <>
+inline  Vec<2> Vec<2> :: GetNormal () const
+{
+  return Vec<2> (-x[1], x[0]);
+}
+
+template <>
+inline  Vec<3> Vec<3> :: GetNormal () const
+{
+  if (fabs (x[0]) > fabs (x[2]))
+    return Vec<3> (-x[1], x[0], 0);
+  else
+    return Vec<3> (0, x[2], -x[1]);
+}
+
+
+
+// template <int H, int W>
+inline void CalcInverse (const Mat<2,2> & m, Mat<2,2> & inv)
+{
+  double det = m(0,0) * m(1,1) - m(0,1) * m(1,0);
+  if (det == 0) 
+    {
+      inv = 0;
+      return;
+    }
+
+  double idet = 1.0 / det;
+  inv(0,0) =  idet * m(1,1);
+  inv(0,1) = -idet * m(0,1);
+  inv(1,0) = -idet * m(1,0);
+  inv(1,1) =  idet * m(0,0);
+}
+
+void CalcInverse (const Mat<3,3> & m, Mat<3,3> & inv);
+
+inline void CalcInverse (const Mat<2,3> & m, Mat<3,2> & inv)
+{
+  Mat<2,2> a = m * Trans (m);
+  Mat<2,2> ainv;
+  CalcInverse (a, ainv);
+  inv = Trans (m) * ainv;
+}
+
+void CalcInverse (const Mat<3,2> & m, Mat<2,3> & inv);
+
+inline void CalcInverse (const Mat<3,2> & m, Mat<2,3> & inv)
+{
+  Mat<2,2> a = Trans (m) * m;
+  Mat<2,2> ainv;
+  CalcInverse (a, ainv);
+  inv = ainv * Trans (m);
+}
+
+
+double Det (const Mat<2,2> & m);
+double Det (const Mat<3,3> & m);
+
+// eigenvalues of a symmetric matrix
+void EigenValues (const Mat<3,3> & m, Vec<3> & ev);
+void EigenValues (const Mat<2,2> & m, Vec<3> & ev);
+
+#endif
diff --git a/contrib/Netgen/libsrc/gprim/geomobjects.hpp b/contrib/Netgen/libsrc/gprim/geomobjects.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..87c38d9bffb2cacb984d747d34707ae9c827e1dc
--- /dev/null
+++ b/contrib/Netgen/libsrc/gprim/geomobjects.hpp
@@ -0,0 +1,359 @@
+#ifndef FILE_OBJECTS
+#define FILE_OBJECTS
+
+/* *************************************************************************/
+/* File:   geomobjects.hpp                                                 */
+/* Author: Joachim Schoeberl                                               */
+/* Date:   20. Jul. 02                                                     */
+/* *************************************************************************/
+
+
+
+template <int D> class Vec;
+template <int D> class Point;
+
+
+template <int D>
+class Point
+{
+
+protected:
+  double x[D];
+
+public:
+  Point () { ; }
+  Point (double ax) { x[0] = ax; }
+  Point (double ax, double ay) { x[0] = ax; x[1] = ay; }
+  Point (double ax, double ay, double az)
+  { x[0] = ax; x[1] = ay; x[2] = az; }
+  Point (double ax, double ay, double az, double au)
+  { x[0] = ax; x[1] = ay; x[2] = az; x[3] = au;}
+
+  Point (const Point<D> & p2)
+  { for (int i = 0; i < D; i++) x[i] = p2.x[i]; }
+
+  explicit Point (const Vec<D> & v)
+  { for (int i = 0; i < D; i++) x[i] = v(i); }
+
+
+  Point & operator= (const Point<D> & p2)
+  {
+    for (int i = 0; i < D; i++) x[i] = p2.x[i]; 
+    return *this;
+  }
+
+  Point & operator= (double val)
+  {
+    for (int i = 0; i < D; i++) x[i] = val;
+    return *this;
+  }
+
+  double & operator() (int i) { return x[i]; }
+  const double & operator() (int i) const { return x[i]; }
+
+  operator const double* () const { return x; }
+};
+
+
+
+
+
+template <int D>
+class Vec
+{
+
+protected:
+  double x[D];
+
+public:
+  Vec () { ; } // for (int i = 0; i < D; i++) x[i] = 0; }
+  Vec (double ax) { for (int i = 0; i < D; i++) x[i] = ax; }
+  Vec (double ax, double ay) { x[0] = ax; x[1] = ay; }
+  Vec (double ax, double ay, double az)
+  { x[0] = ax; x[1] = ay; x[2] = az; }
+  Vec (double ax, double ay, double az, double au)
+  { x[0] = ax; x[1] = ay; x[2] = az; x[3] = au; }
+
+  Vec (const Vec<D> & p2)
+  { for (int i = 0; i < D; i++) x[i] = p2.x[i]; }
+
+  explicit Vec (const Point<D> & p)
+  { for (int i = 0; i < D; i++) x[i] = p(i); }
+
+  Vec (const Vec<D> & p1, const Vec<D> & p2)
+  { for(int i=0; i<D; i++) x[i] = p2(i)-p1(1); }
+  
+
+
+  Vec & operator= (const Vec<D> & p2)
+  {
+    for (int i = 0; i < D; i++) x[i] = p2.x[i]; 
+    return *this;
+  }
+
+  Vec & operator= (double s)
+  {
+    for (int i = 0; i < D; i++) x[i] = s;
+    return *this;
+  }
+
+  double & operator() (int i) { return x[i]; }
+  const double & operator() (int i) const { return x[i]; }
+
+  operator const double* () const { return x; }
+
+  double Length () const
+  {
+    double l = 0;
+    for (int i = 0; i < D; i++)
+      l += x[i] * x[i];
+    return sqrt (l);
+  }
+
+  double Length2 () const
+  {
+    double l = 0;
+    for (int i = 0; i < D; i++)
+      l += x[i] * x[i];
+    return l;
+  }
+
+  const Vec<D> & Normalize ()
+  {
+    double l = Length();
+    if (l != 0)
+      for (int i = 0; i < D; i++)
+	x[i] /= l;
+    return *this;
+  }
+
+  Vec<D> GetNormal () const;
+};
+
+
+
+
+
+template <int H, int W=H>
+class Mat
+{
+
+protected:
+  double x[H*W];
+
+public:
+  Mat () { ; }
+  Mat (const Mat & b)
+  { for (int i = 0; i < H*W; i++) x[i] = b.x[i]; }
+  
+  Mat & operator= (double s)
+  {
+    for (int i = 0; i < H*W; i++) x[i] = s;
+    return *this;
+  }
+
+  Mat & operator= (const Mat & b)
+  {
+    for (int i = 0; i < H*W; i++) x[i] = b.x[i]; 
+    return *this;
+  }
+
+  double & operator() (int i, int j) { return x[i*W+j]; }
+  const double & operator() (int i, int j) const { return x[i*W+j]; }
+  double & operator() (int i) { return x[i]; }
+  const double & operator() (int i) const { return x[i]; }
+
+  Vec<H> Col (int i) const
+  {
+    Vec<H> hv; 
+    for (int j = 0; j < H; j++)
+      hv(j) = x[j*W+i];
+    return hv; 
+  }
+
+  Vec<W> Row (int i) const
+  {
+    Vec<W> hv; 
+    for (int j = 0; j < W; j++)
+      hv(j) = x[i*W+j];
+    return hv; 
+  }
+
+  void Solve (const Vec<H> & rhs, Vec<W> & sol) const
+  {
+    Mat<W,H> inv;
+    CalcInverse (*this, inv);
+    sol = inv * rhs;
+  }
+};
+
+
+
+
+template <int D>
+class Box
+{
+protected:
+  Point<D> pmin, pmax;
+public:
+  Box () { ; }
+  Box ( const Point<D> & p1, const Point<D> & p2)
+  {
+    for (int i = 0; i < D; i++)
+      {
+	pmin(i) = min2(p1(i), p2(i));
+	pmax(i) = max2(p1(i), p2(i));
+      }
+  }
+
+  enum EB_TYPE { EMPTY_BOX = 1 };
+  Box ( EB_TYPE et ) 
+  {
+    pmin = Point<3> (1e99, 1e99, 1e99);
+    pmax = Point<3> (-1e99, -1e99, -1e99);
+  }
+
+  const Point<D> & PMin () const { return pmin; }
+  const Point<D> & PMax () const { return pmax; }
+  
+  void Set (const Point<D> & p)
+  { pmin = pmax = p; }
+
+  void Add (const Point<D> & p)
+  { 
+    for (int i = 0; i < D; i++)
+      {
+	if (p(i) < pmin(i)) pmin(i) = p(i);
+	else if (p(i) > pmax(i)) pmax(i) = p(i);
+      }
+  }
+
+  Point<D> Center () const 
+  { 
+    Point<D> c;
+    for (int i = 0; i < D; i++)
+      c(i) = 0.5 * (pmin(i)+pmax(i)); 
+    return c;
+  }
+  double Diam () const { return Abs (pmax-pmin); }
+
+  Point<D> GetPointNr (int nr) const
+  {
+    Point<D> p;
+    for (int i = 0; i < D; i++)
+      {
+	p(i) = (nr & 1) ? pmax(i) : pmin(i);
+	nr >>= 1;
+      }
+    return p;
+  }
+
+
+  bool Intersect (const Box<D> & box2) const
+  {
+    for (int i = 0; i < D; i++)
+      if (pmin(i) > box2.pmax(i) ||
+	  pmax(i) < box2.pmin(i)) return 0;
+    return 1;
+  }
+
+
+  bool IsIn (const Point<D> & p) const
+  {
+    for (int i = 0; i < D; i++)
+      if (p(i) < pmin(i) || p(i) > pmax(i)) return 0;
+    return 1;
+  }
+
+
+  void Increase (double dist)
+  {
+    for (int i = 0; i < D; i++)
+      {
+	pmin(i) -= dist;
+	pmax(i) += dist;
+      }
+  }
+};
+
+
+
+
+template <int D>
+class BoxSphere : public Box<D>
+{
+protected:
+  ///
+  Point<D> c;
+  ///
+  double diam;
+  ///
+  double inner;
+public:
+  ///
+  BoxSphere () { };
+ ///
+  BoxSphere (const Box<D> & box) 
+  : Box<D> (box) 
+  { 
+    CalcDiamCenter();
+  };
+
+  ///
+  BoxSphere ( Point<D> apmin, Point<D> apmax )
+    : Box<D> (apmin, apmax)
+  {
+    CalcDiamCenter();
+  }
+
+  ///
+  const Point<D> & Center () const { return c; }
+  ///
+  double Diam () const { return diam; }
+  ///
+  double Inner () const { return inner; }
+
+
+  ///
+  void GetSubBox (int nr, BoxSphere & sbox) const
+  {
+    for (int i = 0; i < D; i++)
+      {
+	if (nr & 1)
+	  {
+	    sbox.pmin(i) = c(i);
+	    sbox.pmax(i) = this->pmax(i);
+	  }
+	else
+	  {
+	    sbox.pmin(i) = this->pmin(i);
+	    sbox.pmax(i) = c(i);
+	  }
+	sbox.c(i) = 0.5 * (sbox.pmin(i) + sbox.pmax(i));
+	nr >>= 1;
+      }
+    sbox.diam = 0.5 * diam;
+    sbox.inner = 0.5 * inner;
+  }
+
+
+  ///
+  void CalcDiamCenter ()
+  {
+    c = Box<D>::Center ();
+    diam = Dist (this->pmin, this->pmax);
+
+    inner = this->pmax(0) - this->pmin(0);
+    for (int i = 1; i < D; i++)
+      if (this->pmax(i) - this->pmin(i) < inner)
+	inner = this->pmax(i) - this->pmin(i);
+  }
+
+};
+
+
+
+
+
+
+#endif
diff --git a/contrib/Netgen/libsrc/gprim/geomops.hpp b/contrib/Netgen/libsrc/gprim/geomops.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..755f35a87886bf237e01893549f4dd5d6cc04aae
--- /dev/null
+++ b/contrib/Netgen/libsrc/gprim/geomops.hpp
@@ -0,0 +1,391 @@
+#ifndef FILE_GEOMOPS
+#define FILE_GEOMOPS
+
+/* *************************************************************************/
+/* File:   geomops.hpp                                                     */
+/* Author: Joachim Schoeberl                                               */
+/* Date:   20. Jul. 02                                                     */
+/* *************************************************************************/
+
+
+/*
+
+Point - Vector operations
+
+ */
+
+
+template <int D>
+inline Vec<D> operator+ (const Vec<D> & a, const Vec<D> & b)
+{
+  Vec<D> res;
+  for (int i = 0; i < D; i++)
+    res(i) = a(i) + b(i);
+  return res;
+}
+
+
+
+template <int D>
+inline Point<D> operator+ (const Point<D> & a, const Vec<D> & b)
+{
+  Point<D> res;
+  for (int i = 0; i < D; i++)
+    res(i) = a(i) + b(i);
+  return res;
+}
+
+
+
+template <int D>
+inline Vec<D> operator- (const Point<D> & a, const Point<D> & b)
+{
+  Vec<D> res;
+  for (int i = 0; i < D; i++)
+    res(i) = a(i) - b(i);
+  return res;
+}
+
+template <int D>
+inline Point<D> operator- (const Point<D> & a, const Vec<D> & b)
+{
+  Point<D> res;
+  for (int i = 0; i < D; i++)
+    res(i) = a(i) - b(i);
+  return res;
+}
+
+template <int D>
+inline Vec<D> operator- (const Vec<D> & a, const Vec<D> & b)
+{
+  Vec<D> res;
+  for (int i = 0; i < D; i++)
+    res(i) = a(i) - b(i);
+  return res;
+}
+
+
+
+template <int D>
+inline Vec<D> operator* (double s, const Vec<D> & b)
+{
+  Vec<D> res;
+  for (int i = 0; i < D; i++)
+    res(i) = s * b(i);
+  return res;
+}
+
+
+template <int D>
+inline double operator* (const Vec<D> & a, const Vec<D> & b)
+{
+  double sum = 0;
+  for (int i = 0; i < D; i++)
+    sum += a(i) * b(i);
+  return sum;
+}
+
+
+
+template <int D>
+inline Vec<D> operator- (const Vec<D> & b)
+{
+  Vec<D> res;
+  for (int i = 0; i < D; i++)
+    res(i) = -b(i);
+  return res;
+}
+
+
+template <int D>
+inline Point<D> & operator+= (Point<D> & a, const Vec<D> & b)
+{
+  for (int i = 0; i < D; i++)
+    a(i) += b(i);
+  return a;
+}
+
+template <int D>
+inline Vec<D> & operator+= (Vec<D> & a, const Vec<D> & b)
+{
+  for (int i = 0; i < D; i++)
+    a(i) += b(i);
+  return a;
+}
+
+
+template <int D>
+inline Point<D> & operator-= (Point<D> & a, const Vec<D> & b)
+{
+  for (int i = 0; i < D; i++)
+    a(i) -= b(i);
+  return a;
+}
+
+template <int D>
+inline Vec<D> & operator-= (Vec<D> & a, const Vec<D> & b)
+{
+  for (int i = 0; i < D; i++)
+    a(i) -= b(i);
+  return a;
+}
+
+
+
+template <int D>
+inline Vec<D> & operator*= (Vec<D> & a, double s)
+{
+  for (int i = 0; i < D; i++)
+    a(i) *= s;
+  return a;
+}
+
+
+template <int D>
+inline Vec<D> & operator/= (Vec<D> & a, double s)
+{
+  for (int i = 0; i < D; i++)
+    a(i) /= s;
+  return a;
+}
+
+
+
+
+// Matrix - Vector operations
+
+/*
+template <int H, int W>
+inline Vec<H> operator* (const Mat<H,W> & m, const Vec<W> & v)
+{
+  Vec<H> res;
+  for (int i = 0; i < H; i++)
+    {
+      res(i) = 0;
+      for (int j = 0; j < W; j++)
+	res(i) += m(i,j) * v(j);
+    }
+  return res;
+}
+*/
+
+// thanks to VC60 partial template specialization features !!!
+
+inline Vec<2> operator* (const Mat<2,2> & m, const Vec<2> & v)
+{
+  Vec<2> res;
+  for (int i = 0; i < 2; i++)
+    {
+      res(i) = 0;
+      for (int j = 0; j < 2; j++)
+	res(i) += m(i,j) * v(j);
+    }
+  return res;
+}
+
+inline Vec<2> operator* (const Mat<2,3> & m, const Vec<3> & v)
+{
+  Vec<2> res;
+  for (int i = 0; i < 2; i++)
+    {
+      res(i) = 0;
+      for (int j = 0; j < 3; j++)
+	res(i) += m(i,j) * v(j);
+    }
+  return res;
+}
+
+
+inline Vec<3> operator* (const Mat<3,2> & m, const Vec<2> & v)
+{
+  Vec<3> res;
+  for (int i = 0; i < 3; i++)
+    {
+      res(i) = 0;
+      for (int j = 0; j < 2; j++)
+	res(i) += m(i,j) * v(j);
+    }
+  return res;
+}
+
+
+inline Vec<3> operator* (const Mat<3,3> & m, const Vec<3> & v)
+{
+  Vec<3> res;
+  for (int i = 0; i < 3; i++)
+    {
+      res(i) = 0;
+      for (int j = 0; j < 3; j++)
+	res(i) += m(i,j) * v(j);
+    }
+  return res;
+}
+
+
+
+
+
+
+
+/*
+template <int H1, int W1, int H2, int W2>
+inline Mat<H1,W2> operator* (const Mat<H1,W1> & a, const Mat<H2,W2> & b)
+{
+  Mat<H1,W2> m;
+  for (int i = 0; i < H1; i++)
+    for (int j = 0; j < W2; j++)
+      {
+	double sum = 0;
+	for (int k = 0; k < W1; k++)
+	  sum += a(i,k) * b(k, j);
+	m(i,j) = sum; 
+      }
+  return m;
+}
+*/
+
+inline Mat<2,2> operator* (const Mat<2,2> & a, const Mat<2,2> & b)
+{
+  Mat<2,2> m;
+  for (int i = 0; i < 2; i++)
+    for (int j = 0; j < 2; j++)
+      {
+	double sum = 0;
+	for (int k = 0; k < 2; k++)
+	  sum += a(i,k) * b(k, j);
+	m(i,j) = sum; 
+      }
+  return m;
+}
+
+inline Mat<2,2> operator* (const Mat<2,3> & a, const Mat<3,2> & b)
+{
+  Mat<2,2> m;
+  for (int i = 0; i < 2; i++)
+    for (int j = 0; j < 2; j++)
+      {
+	double sum = 0;
+	for (int k = 0; k < 3; k++)
+	  sum += a(i,k) * b(k, j);
+	m(i,j) = sum; 
+      }
+  return m;
+}
+
+
+inline Mat<3,2> operator* (const Mat<3,2> & a, const Mat<2,2> & b)
+{
+  Mat<3,2> m;
+  for (int i = 0; i < 3; i++)
+    for (int j = 0; j < 2; j++)
+      {
+	double sum = 0;
+	for (int k = 0; k < 2; k++)
+	  sum += a(i,k) * b(k, j);
+	m(i,j) = sum; 
+      }
+  return m;
+}
+
+
+
+inline Mat<2,3> operator* (const Mat<2,2> & a, const Mat<2,3> & b)
+{
+  Mat<2,3> m;
+  for (int i = 0; i < 2; i++)
+    for (int j = 0; j < 3; j++)
+      {
+	double sum = 0;
+	for (int k = 0; k < 2; k++)
+	  sum += a(i,k) * b(k, j);
+	m(i,j) = sum; 
+      }
+  return m;
+}
+
+
+inline Mat<3,3> operator* (const Mat<3,3> & a, const Mat<3,3> & b)
+{
+  Mat<3,3> m;
+  for (int i = 0; i < 3; i++)
+    for (int j = 0; j < 3; j++)
+      {
+	double sum = 0;
+	for (int k = 0; k < 3; k++)
+	  sum += a(i,k) * b(k, j);
+	m(i,j) = sum; 
+      }
+  return m;
+}
+
+
+
+
+
+
+
+
+template <int H, int W>
+inline Mat<W,H> Trans (const Mat<H,W> & m)
+{
+  Mat<W,H> res;
+  for (int i = 0; i < H; i++)
+    for (int j = 0; j < W; j++)
+      res(j,i) = m(i,j);
+  return res;
+}
+
+
+
+
+
+
+
+
+
+
+
+template <int D>
+inline ostream & operator<< (ostream & ost, const Vec<D> & a)
+{
+  ost << "(";
+  for (int i = 0; i < D-1; i++)
+    ost << a(i) << ", ";
+  ost << a(D-1) << ")";
+  return ost;
+}
+
+template <int D>
+inline ostream & operator<< (ostream & ost, const Point<D> & a)
+{
+  ost << "(";
+  for (int i = 0; i < D-1; i++)
+    ost << a(i) << ", ";
+  ost << a(D-1) << ")";
+  return ost;
+}
+
+template <int D>
+inline ostream & operator<< (ostream & ost, const Box<D> & b)
+{
+  ost << b.PMin() << " - " << b.PMax();
+  return ost;
+}
+
+template <int H, int W>
+inline ostream & operator<< (ostream & ost, const Mat<H,W> & m)
+{
+  ost << "(";
+  for (int i = 0; i < H; i++)
+    {
+      for (int j = 0; j < W; j++)
+	ost << m(i,j) << "   ";
+      ost << endl;
+    }
+  return ost;
+}
+
+
+
+
+#endif
diff --git a/contrib/Netgen/libsrc/gprim/geomtest3d.cpp b/contrib/Netgen/libsrc/gprim/geomtest3d.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..20a3be0b349734219799ab428cfd11286e9fcaed
--- /dev/null
+++ b/contrib/Netgen/libsrc/gprim/geomtest3d.cpp
@@ -0,0 +1,1150 @@
+#include <mystdlib.h>
+#include <myadt.hpp>
+
+#include <linalg.hpp>
+#include <gprim.hpp>
+
+namespace netgen
+{
+int
+IntersectTriangleLine (const Point<3> ** tri, const Point<3> ** line)
+{
+  Vec3d vl(*line[0], *line[1]);
+  Vec3d vt1(*tri[0], *tri[1]);
+  Vec3d vt2(*tri[0], *tri[2]);
+  Vec3d vrs(*tri[0], *line[0]);
+
+  static DenseMatrix a(3), ainv(3);
+  static Vector rs(3), lami(3);
+  int i;
+
+  /*
+  (*testout) << "Tri-Line inters: " << endl
+	     << "tri = " << *tri[0] << ", " << *tri[1] << ", " << *tri[2] << endl
+	     << "line = " << *line[0] << ", " << *line[1] << endl;
+  */
+  for (i = 1; i <= 3; i++)
+    {
+      a.Elem(i, 1) = -vl.X(i);
+      a.Elem(i, 2) = vt1.X(i);
+      a.Elem(i, 3) = vt2.X(i);
+      rs.Elem(i) = vrs.X(i);
+    }
+
+  double det = a.Det();
+
+  double arel = vl.Length() * vt1.Length() * vt2.Length();
+  /*
+  double amax = 0;
+  for (i = 1; i <= 9; i++)
+    if (fabs (a.Get(i)) > amax)
+      amax = fabs(a.Get(i));
+  */
+  // new !!!!
+  if (fabs (det) <= 1e-10 * arel)
+    {
+#ifdef DEVELOP      
+      // line parallel to triangle !
+      // cout << "ERROR: IntersectTriangleLine degenerated" << endl;
+      //      (*testout) << "WARNING: IntersectTriangleLine degenerated\n";
+      /*
+      (*testout) << "lin-tri intersection: " << endl
+		 << "line = " << *line[0] << " - " << *line[1] << endl
+		 << "tri = " << *tri[0] << " - " << *tri[1] << " - " << *tri[2] << endl
+		 << "lami = " << lami << endl
+		 << "pc = " << ( *line[0] + lami.Get(1) * vl ) << endl
+		 << "   = " << ( *tri[0] + lami.Get(2) * vt1 + lami.Get(3) * vt2) << endl
+		 << " a = " << a << endl
+		 << " ainv = " << ainv << endl
+		 << " det(a) = " << det << endl
+		 << " rs = " << rs << endl;
+      */
+#endif
+      return 0;
+    }
+
+  CalcInverse (a, ainv);
+  ainv.Mult (rs, lami);
+
+  //  (*testout) << "lami = " << lami << endl;
+
+  double eps = 1e-6;
+  if (
+      (lami.Get(1) >= -eps && lami.Get(1) <= 1+eps && 
+       lami.Get(2) >= -eps && lami.Get(3) >= -eps && 
+       lami.Get(2) + lami.Get(3) <= 1+eps)  && !
+      (lami.Get(1) >= eps && lami.Get(1) <= 1-eps && 
+       lami.Get(2) >= eps && lami.Get(3) >= eps && 
+       lami.Get(2) + lami.Get(3) <= 1-eps) )
+
+
+     {
+#ifdef DEVELOP
+       //      cout << "WARNING: IntersectTriangleLine degenerated" << endl;
+      (*testout) << "WARNING: IntersectTriangleLine numerical inexact" << endl;
+
+      (*testout) << "lin-tri intersection: " << endl
+		 << "line = " << *line[0] << " - " << *line[1] << endl
+		 << "tri = " << *tri[0] << " - " << *tri[1] << " - " << *tri[2] << endl
+		 << "lami = " << lami << endl
+		 << "pc = " << ( *line[0] + lami.Get(1) * vl ) << endl
+		 << "   = " << ( *tri[0] + lami.Get(2) * vt1 + lami.Get(3) * vt2) << endl
+		 << " a = " << a << endl
+		 << " ainv = " << ainv << endl
+		 << " det(a) = " << det << endl
+		 << " rs = " << rs << endl;
+#endif
+    }
+      
+
+  if (lami.Get(1) >= 0 && lami.Get(1) <= 1 && 
+      lami.Get(2) >= 0 && lami.Get(3) >= 0 && lami.Get(2) + lami.Get(3) <= 1)
+    {
+
+      return 1;
+    }
+
+  return 0;
+}
+
+
+
+
+
+int IntersectTetTriangle (const Point<3> ** tet, const Point<3> ** tri,
+			  const int * tetpi, const int * tripi)
+{
+  int i, j;
+  double diam = Dist (*tri[0], *tri[1]);
+  double epsrel = 1e-8;
+  double eps = diam * epsrel;
+
+  double eps2 = eps * eps;
+  int cnt = 0;
+
+  int tetp1 = -1, tetp2 = -1;
+  int trip1 = -1, trip2 = -1;
+  int tetp3, tetp4, trip3;
+
+  /*
+  for (i = 0; i < 4; i++)
+    loctetpi[i] = -1;
+  */
+
+
+  if (!tetpi)
+    {
+      for (i = 0; i <= 2; i++)
+	{
+	  //	  loctripi[i] = -1;
+	  for (j = 0; j <= 3; j++)
+	    {
+	      if (Dist2 (*tet[j], *tri[i]) < eps2)
+		{
+		  //		  loctripi[i] = j;
+		  //		  loctetpi[j] = i;
+		  cnt++;
+		  tetp2 = tetp1;
+		  tetp1 = j;
+		  trip2 = trip1;
+		  trip1 = i;
+		  break;
+		}
+	    }
+	}
+    }
+  else
+    {
+      for (i = 0; i <= 2; i++)
+	{
+	  //	  loctripi[i] = -1;
+	  for (j = 0; j <= 3; j++)
+	    {
+	      if (tetpi[j] == tripi[i])
+		{
+		  //		  loctripi[i] = j;
+		  //		  loctetpi[j] = i;
+		  cnt++;
+		  tetp2 = tetp1;
+		  tetp1 = j;
+		  trip2 = trip1;
+		  trip1 = i;
+		  break;
+		}
+	    }
+	}
+    }  
+  
+  //  (*testout) << "cnt = " << cnt << endl;
+
+
+  //  (*testout) << "tet-trig inters, cnt = " << cnt << endl;
+  
+  // cnt .. number of common points
+  switch (cnt)
+    {
+    case 0:
+      {
+	Vec3d no, n;
+	int inpi[3];
+
+	// check, if some trigpoint is in tet:
+
+	for (j = 0; j < 3; j++)
+	  inpi[j] = 1;
+
+	for (i = 1; i <= 4; i++)
+	  {
+	    int pi1 = i % 4;
+	    int pi2 = (i+1) % 4;
+	    int pi3 = (i+2) % 4;
+	    int pi4 = (i+3) % 4;
+
+	    Vec3d v1 (*tet[pi1], *tet[pi2]);
+	    Vec3d v2 (*tet[pi1], *tet[pi3]);
+	    Vec3d v3 (*tet[pi1], *tet[pi4]);
+	    Cross (v1, v2, n);
+
+	    // n /= n.Length();
+	    double nl = n.Length();
+
+	    if (v3 * n > 0)
+	      n *= -1;
+
+	    int outeri = 1;
+	    for (j = 0; j < 3; j++)
+	      {
+		Vec3d v(*tet[pi1], *tri[j]);
+		if ( v * n < eps * nl)
+		  outeri = 0;
+		else
+		  inpi[j] = 0;
+	      }
+
+	    if (outeri)
+	      return 0;
+	  }
+
+	if (inpi[0] || inpi[1] || inpi[2])
+	  {
+	    return 1;
+	  }
+
+
+	// check, if some tet edge intersects triangle:
+	const Point<3> * line[2], *tetf[3];
+	for (i = 0; i <= 2; i++)
+	  for (j = i+1; j <= 3; j++)
+	    {
+	      line[0] = tet[i];
+	      line[1] = tet[j];
+
+	      if (IntersectTriangleLine (tri, &line[0]))
+		return 1;
+	    }
+
+	// check, if triangle line intersects tet face:
+	for (i = 0; i <= 3; i++)
+	  {
+	    for (j = 0; j <= 2; j++)
+	      tetf[j] = tet[(i+j) % 4];
+	    
+	    for (j = 0; j <= 2; j++)
+	      {
+		line[0] = tri[j];
+		line[1] = tri[(j+1) % 3];
+		
+		if (IntersectTriangleLine (&tetf[0], &line[0]))
+		  return 1;
+	      }
+	  }
+
+
+	return 0;
+//GH	break;
+      }
+    case 1:
+      {
+	trip2 = 0;
+	while (trip2 == trip1)
+	  trip2++;
+	trip3 = 3 - trip1 - trip2;
+
+	tetp2 = 0;
+	while (tetp2 == tetp1)
+	  tetp2++;
+	tetp3 = 0;
+	while (tetp3 == tetp1 || tetp3 == tetp2)
+	  tetp3++;
+	tetp4 = 6 - tetp1 - tetp2 - tetp3;
+
+	Vec3d vtri1 = *tri[trip2] - *tri[trip1];
+	Vec3d vtri2 = *tri[trip3] - *tri[trip1];
+	Vec3d ntri;
+	Cross (vtri1, vtri2, ntri);
+
+	// tri durch tet ?
+	// fehlt noch
+
+
+	// test 3 tet-faces:
+	for (i = 1; i <= 3; i++)
+	  {
+	    Vec3d vtet1, vtet2;
+	    switch (i)
+	      {
+	      case 1:
+		{
+		  vtet1 = *tet[tetp2] - *tet[tetp1];
+		  vtet2 = *tet[tetp3] - *tet[tetp1];
+		  break;
+		}
+	      case 2:
+		{
+		  vtet1 = *tet[tetp3] - *tet[tetp1];
+		  vtet2 = *tet[tetp4] - *tet[tetp1];
+		  break;
+		}
+	      case 3:
+		{
+		  vtet1 = *tet[tetp4] - *tet[tetp1];
+		  vtet2 = *tet[tetp2] - *tet[tetp1];
+		  break;
+		}
+	      }
+	    
+	    Vec3d ntet;
+	    Cross (vtet1, vtet2, ntet);
+	    
+	    Vec3d crline = Cross (ntri, ntet);
+
+	    double lcrline = crline.Length();
+
+	    if (lcrline < eps * eps * eps * eps)  // new change !
+	      continue;
+
+	    if (vtri1 * crline + vtri2 * crline < 0)
+	      crline *= -1;
+
+	    crline /= lcrline;
+
+	    double lam1, lam2, lam3, lam4;
+	    LocalCoordinates (vtri1, vtri2, crline, lam1, lam2);
+	    LocalCoordinates (vtet1, vtet2, crline, lam3, lam4);
+	    
+	    if (lam1 > -epsrel && lam2 > -epsrel &&
+		lam3 > -epsrel && lam4 > -epsrel)
+	      {
+		
+		/*
+		(*testout) << "lcrline = " << lcrline 
+			   << " eps = " << eps << " diam = " << diam << endl;
+		 
+		(*testout) << "hit, cnt == 1 " 
+			   << "lam1,2,3,4 = " << lam1 << ", " 
+			   << lam2 << ", " << lam3 << ", " << lam4
+			   << "\n";
+		*/
+		return 1;
+	      }
+	  }
+	return 0;
+//GH	break;
+      }
+    case 2:
+      {
+	// common edge
+	tetp3 = 0;
+	while (tetp3 == tetp1 || tetp3 == tetp2)
+	  tetp3++;
+	tetp4 = 6 - tetp1 - tetp2 - tetp3;
+	trip3 = 3 - trip1 - trip2;
+
+	//	(*testout) << "trip1,2,3 = " << trip1 << ", " << trip2 << ", " << trip3 << endl;
+	//	(*testout) << "tetp1,2,3,4 = " << tetp1 << ", " << tetp2 
+	//		   << ", " << tetp3 << ", " << tetp4 << endl;
+
+	Vec3d vtri = *tri[trip3] - *tri[trip1];
+	Vec3d vtet1 = *tet[tetp3] - *tri[trip1];
+	Vec3d vtet2 = *tet[tetp4] - *tri[trip1];
+
+	Vec3d n = *tri[trip2] - *tri[trip1];
+	n /= n.Length();
+
+	vtet1 -= (n * vtet1) * n;
+	vtet2 -= (n * vtet2) * n;
+
+
+	double lam1, lam2;
+	LocalCoordinates (vtet1, vtet2, vtri, lam1, lam2);
+	
+	if (lam1 < -epsrel || lam2 < -epsrel)
+	  return 0;
+	else
+	  {
+	    /*
+
+	    (*testout) << "vtet1 = " << vtet1 << endl;
+	    (*testout) << "vtet2 = " << vtet2 << endl;
+	    (*testout) << "vtri = " << vtri << endl;
+	    (*testout) << "lam1 = " << lam1 << " lam2 = " << lam2 << endl;
+	    (*testout) << (lam1 * (vtet1 * vtet1) + lam2 * (vtet1 * vtet2))
+		       << " = " << (vtet1 * vtri) << endl;
+	    (*testout) << (lam1 * (vtet1 * vtet2) + lam2 * (vtet2 * vtet2))
+		       << " = " << (vtet2 * vtri) << endl;
+	    
+	    (*testout) << "tet = ";
+	    for (j = 0; j < 4; j++)
+	      (*testout) << (*tet[j]) << " ";
+	    (*testout) << endl;
+	    (*testout) << "tri = ";
+	    for (j = 0; j < 3; j++)
+	      (*testout) << (*tri[j]) << " ";
+	    (*testout) << endl;
+
+	    (*testout) << "hit, cnt == 2" << endl;
+	    */
+	    
+	    return 1;
+	  }
+	  
+	break;
+      }
+    case 3:
+      {
+	// common face
+	return 0;
+      }
+    }
+
+  (*testout) << "hit, cnt = " << cnt << endl;
+  return 1;
+}
+
+
+
+
+
+int IntersectTetTriangleRef (const Point<3> ** tri, const int * tripi)
+{
+  int i, j;
+  double eps = 1e-8;
+  double eps2 = eps * eps;
+
+  static Point<3> rtetp1(0, 0, 0);
+  static Point<3> rtetp2(1, 0, 0);  
+  static Point<3> rtetp3(0, 1, 0); 
+  static Point<3> rtetp4(0, 0, 1);
+
+  static const Point<3> * tet[] = { &rtetp1, &rtetp2, &rtetp3, &rtetp4 };
+  static int tetpi[] = { 1, 2, 3, 4 };
+
+
+  //  return IntersectTetTriangle (tet, tri, tetpi, tripi);
+
+  
+  int cnt = 0;
+
+  int tetp1 = -1, tetp2 = -1;
+  int trip1 = -1, trip2 = -1;
+  int tetp3, tetp4, trip3;
+
+  /*
+  if (!tetpi)
+    {
+      for (i = 0; i <= 2; i++)
+	{
+	  for (j = 0; j <= 3; j++)
+	    {
+	      if (Dist2 (*tet[j], *tri[i]) < eps2)
+		{
+		  cnt++;
+		  tetp2 = tetp1;
+		  tetp1 = j;
+		  trip2 = trip1;
+		  trip1 = i;
+		  break;
+		}
+	    }
+	}
+    }
+  else
+  */
+    {
+      for (i = 0; i <= 2; i++)
+	{
+	  for (j = 0; j <= 3; j++)
+	    {
+	      if (tetpi[j] == tripi[i])
+		{
+		  cnt++;
+		  tetp2 = tetp1;
+		  tetp1 = j;
+		  trip2 = trip1;
+		  trip1 = i;
+		  break;
+		}
+	    }
+	}
+    }  
+  
+  //  (*testout) << "cnt = " << cnt << endl;
+
+
+  switch (cnt)
+    {
+    case 0:
+      {
+	Vec3d no, n;
+	//	int inpi[3];
+	int pside[3][4];
+
+	for (j = 0; j < 3; j++)
+	  {
+	    pside[j][0] = (*tri[j])(0) > -eps;
+	    pside[j][1] = (*tri[j])(1) > -eps;
+	    pside[j][2] = (*tri[j])(2) > -eps;
+	    pside[j][3] = (*tri[j])(0) + (*tri[j])(1) + (*tri[j])(2) < 1+eps;
+	  }
+
+	
+	for (j = 0; j < 4; j++)
+	  {
+	    if (!pside[0][j] && !pside[1][j] && !pside[2][j])
+	      return 0;
+	  }
+
+	for (j = 0; j < 3; j++)
+	  {
+	    if (pside[j][0] && pside[j][1] && pside[j][2] && pside[j][3])
+	      return 1;
+	  }
+
+
+	const Point<3> * line[2], *tetf[3];
+	for (i = 0; i <= 2; i++)
+	  for (j = i+1; j <= 3; j++)
+	    {
+	      line[0] = tet[i];
+	      line[1] = tet[j];
+
+	      if (IntersectTriangleLine (tri, &line[0]))
+		return 1;
+	    }
+
+	for (i = 0; i <= 3; i++)
+	  {
+	    for (j = 0; j <= 2; j++)
+	      tetf[j] = tet[(i+j) % 4];
+	    
+	    for (j = 0; j <= 2; j++)
+	      {
+		line[0] = tri[j];
+		line[1] = tri[(j+1) % 3];
+
+	      if (IntersectTriangleLine (&tetf[0], &line[0]))
+		return 1;
+	      }
+	  }
+
+
+	return 0;
+	break;
+      }
+    case 1:
+      {
+	trip2 = 0;
+	if (trip2 == trip1)
+	  trip2++;
+	trip3 = 3 - trip1 - trip2;
+
+	tetp2 = 0;
+	while (tetp2 == tetp1)
+	  tetp2++;
+	tetp3 = 0;
+	while (tetp3 == tetp1 || tetp3 == tetp2)
+	  tetp3++;
+	tetp4 = 6 - tetp1 - tetp2 - tetp3;
+
+	Vec3d vtri1 = *tri[trip2] - *tri[trip1];
+	Vec3d vtri2 = *tri[trip3] - *tri[trip1];
+	Vec3d ntri;
+	Cross (vtri1, vtri2, ntri);
+
+	// tri durch tet ?
+
+	/*
+	Vec3d vtet1(*tet[tetp1], *tet[tetp2]);
+	Vec3d vtet2(*tet[tetp1], *tet[tetp3]);
+	Vec3d vtet3(*tet[tetp1], *tet[tetp4]);
+	Vec3d sol;
+	
+	SolveLinearSystem (vtet1, vtet2, vtet3, vtri1, sol);
+	if (sol.X() > 0 && sol.Y() > 0 && sol.Z() > 0)
+	  return 1;
+
+	SolveLinearSystem (vtet1, vtet2, vtet3, vtri2, sol);
+	if (sol.X() > 0 && sol.Y() > 0 && sol.Z() > 0)
+	  return 1;
+	*/
+
+	// test 3 tet-faces:
+	for (i = 1; i <= 3; i++)
+	  {
+	    Vec3d vtet1, vtet2;
+	    switch (i)
+	      {
+	      case 1:
+		{
+		  vtet1 = *tet[tetp2] - *tet[tetp1];
+		  vtet2 = *tet[tetp3] - *tet[tetp1];
+		  break;
+		}
+	      case 2:
+		{
+		  vtet1 = *tet[tetp3] - *tet[tetp1];
+		  vtet2 = *tet[tetp4] - *tet[tetp1];
+		  break;
+		}
+	      case 3:
+		{
+		  vtet1 = *tet[tetp4] - *tet[tetp1];
+		  vtet2 = *tet[tetp2] - *tet[tetp1];
+		  break;
+		}
+	      }
+	    
+	    Vec3d ntet;
+	    Cross (vtet1, vtet2, ntet);
+	    
+	    Vec3d crline = Cross (ntri, ntet);
+
+	    double lcrline = crline.Length();
+	    if (lcrline < eps * eps)
+	      continue;
+
+
+	    if (vtri1 * crline + vtri2 * crline < 0)
+	      crline *= -1;
+
+	    double lam1, lam2, lam3, lam4;
+	    LocalCoordinates (vtri1, vtri2, crline, lam1, lam2);
+	    LocalCoordinates (vtet1, vtet2, crline, lam3, lam4);
+	    
+	    if (lam1 > -eps && lam2 > -eps &&
+		lam3 > -eps && lam4 > -eps)
+	      {
+		//		(*testout) << "hit, cnt == 1" << "\n";
+		return 1;
+	      }
+	  }
+
+	return 0;
+	break;
+      }
+    case 2:
+      {
+	// common edge
+	tetp3 = 0;
+	while (tetp3 == tetp1 || tetp3 == tetp2)
+	  tetp3++;
+	tetp4 = 6 - tetp1 - tetp2 - tetp3;
+	trip3 = 3 - trip1 - trip2;
+
+	//	(*testout) << "trip1,2,3 = " << trip1 << ", " << trip2 << ", " << trip3 << endl;
+	//	(*testout) << "tetp1,2,3,4 = " << tetp1 << ", " << tetp2 
+	//		   << ", " << tetp3 << ", " << tetp4 << endl;
+
+	Vec3d vtri = *tri[trip3] - *tri[trip1];
+	Vec3d vtet1 = *tet[tetp3] - *tri[trip1];
+	Vec3d vtet2 = *tet[tetp4] - *tri[trip1];
+
+	Vec3d n = *tri[trip2] - *tri[trip1];
+	n /= n.Length();
+
+	vtet1 -= (n * vtet1) * n;
+	vtet2 -= (n * vtet2) * n;
+
+
+	double lam1, lam2;
+	LocalCoordinates (vtet1, vtet2, vtri, lam1, lam2);
+	
+	if (lam1 < -eps || lam2 < -eps)
+	  return 0;
+	else
+	  {
+
+// 	    (*testout) << "vtet1 = " << vtet1 << endl;
+// 	    (*testout) << "vtet2 = " << vtet2 << endl;
+// 	    (*testout) << "vtri = " << vtri << endl;
+// 	    (*testout) << "lam1 = " << lam1 << " lam2 = " << lam2 << endl;
+
+// 	    (*testout) << (lam1 * (vtet1 * vtet1) + lam2 * (vtet1 * vtet2))
+// 		       << " = " << (vtet1 * vtri) << endl;
+// 	    (*testout) << (lam1 * (vtet1 * vtet2) + lam2 * (vtet2 * vtet2))
+// 		       << " = " << (vtet2 * vtri) << endl;
+	    
+// 	    (*testout) << "tet = ";
+// 	    for (j = 0; j < 4; j++)
+// 	      (*testout) << (*tet[j]) << " ";
+// 	    (*testout) << endl;
+// 	    (*testout) << "tri = ";
+// 	    for (j = 0; j < 3; j++)
+// 	      (*testout) << (*tri[j]) << " ";
+// 	    (*testout) << endl;
+
+// 	    (*testout) << "hit, cnt == 2" << endl;
+
+	    return 1;
+	  }
+	  
+	break;
+      }
+    case 3:
+      {
+	// common face
+	return 0;
+      }
+    }
+
+  (*testout) << "hit, cnt = " << cnt << endl;
+  return 1;
+}
+
+
+
+
+
+
+
+
+
+
+
+int IntersectTriangleTriangle (const Point<3> ** tri1, const Point<3> ** tri2)
+{
+  int i, j;
+  double diam = Dist (*tri1[0], *tri1[1]);
+  double epsrel = 1e-8;
+  double eps = diam * epsrel;
+  double eps2 = eps * eps;
+
+
+
+  int cnt = 0;
+  /*
+  int tri1pi[3];
+  int tri2pi[3];
+  */
+
+  //  int tri1p1 = -1; 
+  /// int tri1p2 = -1;
+  //  int tri2p1 = -1;
+  //   int tri2p2 = -1;
+  //  int tri1p3, tri2p3;
+
+  /*
+  for (i = 0; i < 3; i++)
+    tri1pi[i] = -1;
+  */
+  for (i = 0; i <= 2; i++)
+    {
+      //      tri2pi[i] = -1;
+      for (j = 0; j <= 2; j++)
+	{
+	  if (Dist2 (*tri1[j], *tri2[i]) < eps2)
+	    {
+	      //	      tri2pi[i] = j;
+	      //	      tri1pi[j] = i;
+	      cnt++;
+	      //	      tri1p2 = tri1p1;
+	      //	      tri1p1 = j;
+	      //	      tri2p2 = tri2p1;
+	      //	      tri2p1 = i;
+	      break;
+	    }
+	}
+    }
+  
+  switch (cnt)
+    {
+    case 0:
+      {
+	const Point<3> * line[2];
+	
+	for (i = 0; i <= 2; i++)
+	  {
+	    line[0] = tri2[i];
+	    line[1] = tri2[(i+1)%3];
+
+	    if (IntersectTriangleLine (tri1, &line[0]))
+	      {
+		(*testout) << "int1, line = " << *line[0] << " - " << *line[1] << endl;
+		return 1;
+	      }
+	  }	
+
+	for (i = 0; i <= 2; i++)
+	  {
+	    line[0] = tri1[i];
+	    line[1] = tri1[(i+1)%3];
+
+	    if (IntersectTriangleLine (tri2, &line[0]))
+	      {
+		(*testout) << "int2, line = " << *line[0] << " - " << *line[1] << endl;
+		return 1;
+	      }
+	  }	
+	break;
+      }
+    default:
+      return 0;
+    }
+
+  return 0;
+}
+
+
+
+void
+LocalCoordinates (const Vec3d & e1, const Vec3d & e2,
+		  const Vec3d & v, double & lam1, double & lam2)
+{
+  double m11 = e1 * e1;
+  double m12 = e1 * e2;
+  double m22 = e2 * e2;
+  double rs1 = v * e1;
+  double rs2 = v * e2;
+  
+  double det = m11 * m22 - m12 * m12;
+  lam1 = (rs1 * m22 - rs2 * m12)/det;
+  lam2 = (m11 * rs2 - m12 * rs1)/det;
+}
+
+
+
+
+
+int CalcSphereCenter (const Point<3> ** pts, Point<3> & c)
+{
+  Vec3d row1 (*pts[0], *pts[1]);
+  Vec3d row2 (*pts[0], *pts[2]);
+  Vec3d row3 (*pts[0], *pts[3]);
+
+  Vec3d rhs(0.5 * (row1*row1),
+	    0.5 * (row2*row2),
+	    0.5 * (row3*row3));
+  Transpose (row1, row2, row3);
+  
+  Vec3d sol;
+  if (SolveLinearSystem (row1, row2, row3, rhs, sol))
+    {
+      (*testout) << "CalcSphereCenter: degenerated" << endl;
+      return 1;
+    }
+
+  c = *pts[0] + sol;
+  return 0;
+}
+
+
+
+
+
+int CalcTriangleCenter (const Point3d ** pts, Point3d & c)
+{
+  static DenseMatrix a(2), inva(2);
+  static Vector rs(2), sol(2);
+  double h = Dist(*pts[0], *pts[1]);
+
+  Vec3d v1(*pts[0], *pts[1]);
+  Vec3d v2(*pts[0], *pts[2]);
+
+  rs.Elem(1) = v1 * v1;
+  rs.Elem(2) = v2 * v2;
+
+  a.Elem(1,1) = 2 * rs.Get(1);
+  a.Elem(1,2) = a.Elem(2,1) = 2 * (v1 * v2);
+  a.Elem(2,2) = 2 * rs.Get(2);
+
+  if (fabs (a.Det()) <= 1e-12 * h * h)
+    {
+      (*testout) << "CalcTriangleCenter: degenerated" << endl;
+      return 1;
+    }
+
+  CalcInverse (a, inva);
+  inva.Mult (rs, sol);
+
+  c = *pts[0];
+  v1 *= sol.Get(1);
+  v2 *= sol.Get(2);
+
+  c += v1;
+  c += v2;
+
+  return 0;
+}
+
+
+
+double ComputeCylinderRadius (const Point3d & p1, 
+			      const Point3d & p2,
+			      const Point3d & p3, 
+			      const Point3d & p4)
+{
+  Vec3d v12(p1, p2);
+  Vec3d v13(p1, p3);
+  Vec3d v14(p1, p4);
+
+  Vec3d n1 = Cross (v12, v13);
+  Vec3d n2 = Cross (v14, v12);
+		
+  double n1l = n1.Length();
+  double n2l = n2.Length();
+  n1 /= n1l;
+  n2 /= n2l;
+
+  double v12len = v12.Length();
+  double h1 = n1l / v12len;
+  double h2 = n2l / v12len;
+  
+  /*
+  (*testout) << "n1 = " << n1 << " n2 = " << n2 
+	     << "h1 = " << h1 << " h2 = " << h2 << endl;
+  */
+  return ComputeCylinderRadius (n1, n2, h1, h2);
+}
+
+
+
+
+/*
+  Two triangles T1 and T2 have normals n1 and n2.
+  The height over the common edge is h1, and h2.
+ */
+double ComputeCylinderRadius (const Vec3d & n1, const Vec3d & n2,
+				     double h1, double h2)
+{
+  Vec3d t1, t2;
+  double n11 = n1 * n1;
+  double n12 = n1 * n2;
+  double n22 = n2 * n2;
+  double det = n11 * n22 - n12 * n12;
+  
+  if (fabs (det) < 1e-14 * n11 * n22)
+    return 1e20;
+
+  // a biorthogonal bases   (ti * nj) = delta_ij:
+  t1 = (n22/det) * n1 + (-n12/det) * n2;
+  t2 = (-n12/det) * n1 + (n11/det) * n2;
+
+  // normalize:
+  t1 /= t1.Length();
+  t2 /= t2.Length();
+
+  /*
+    vector to center point has form
+    v = lam1 n1 + lam2 n2
+    and fulfills
+    t2 v = h1/2
+    t1 v = h2/2
+  */
+
+  double lam1 = 0.5 * h2 / (n1 * t1);
+  double lam2 = 0.5 * h1 / (n2 * t2);
+  
+  double rad = (lam1 * n1 + lam2 * n2).Length();
+  /*
+  (*testout) << "n1 = " << n1
+	     << " n2 = " << n2
+	     << " t1 = " << t1
+	     << " t2 = " << t2
+	     << " rad = " << rad << endl;
+  */
+  return rad;
+}
+    
+
+
+
+
+
+double MinDistLP2 (const Point2d & lp1, const Point2d & lp2, const Point2d & p)
+{
+  Vec2d v(lp1, lp2);
+  Vec2d vlp(lp1, p);
+
+  // dist(lam) = \| vlp \|^2 - 2 lam (v1p, v) + lam^2 \| v \|^2
+
+  // lam = (v * vlp) / (v * v);
+  // if (lam < 0) lam = 0;
+  // if (lam > 1) lam = 1;
+
+  double num = v*vlp;
+  double den = v*v;
+
+  if (num <= 0) 
+    return Dist2 (lp1, p);
+
+  if (num >= den) 
+    return Dist2 (lp2, p);
+  
+  if (den > 0)
+    {
+      return vlp.Length2() - num * num /den;
+    }
+  else
+    return vlp.Length2();
+}
+
+
+
+
+double MinDistLP2 (const Point3d & lp1, const Point3d & lp2, const Point3d & p)
+{
+  Vec3d v(lp1, lp2);
+  Vec3d vlp(lp1, p);
+
+  // dist(lam) = \| vlp \|^2 - 2 lam (v1p, v) + lam^2 \| v \|^2
+
+  // lam = (v * vlp) / (v * v);
+  // if (lam < 0) lam = 0;
+  // if (lam > 1) lam = 1;
+
+  double num = v*vlp;
+  double den = v*v;
+
+  if (num <= 0) 
+    return Dist2 (lp1, p);
+
+  if (num >= den) 
+    return Dist2 (lp2, p);
+  
+  if (den > 0)
+    {
+      return vlp.Length2() - num * num /den;
+    }
+  else
+    return vlp.Length2();
+}
+
+
+
+double MinDistTP2 (const Point3d & tp1, const Point3d & tp2, 
+		   const Point3d & tp3, const Point3d & p)
+{
+  double lam1, lam2;
+  double res;
+
+  LocalCoordinates (Vec3d (tp1, tp2), Vec3d (tp1, tp3),
+		    Vec3d (tp1, p), lam1, lam2);
+  int in1 = lam1 >= 0;
+  int in2 = lam2 >= 0;
+  int in3 = lam1+lam2 <= 1;
+  
+  if (in1 && in2 && in3)
+    {
+      Point3d pp = tp1 + lam1 * Vec3d(tp1, tp2) + lam2 *  Vec3d (tp1, tp3);
+      res = Dist2 (p, pp);
+    }
+  else
+    {
+      res = Dist2 (tp1, p);
+      if (!in1)
+	{
+	  double hv = MinDistLP2 (tp1, tp3, p);
+	  if (hv < res) res = hv; 
+	}
+      if (!in2)
+	{
+	  double hv = MinDistLP2 (tp1, tp2, p);
+	  if (hv < res) res = hv; 
+	}
+      if (!in3)
+	{
+	  double hv = MinDistLP2 (tp2, tp3, p);
+	  if (hv < res) res = hv; 
+	}
+      /*
+      double d1 = MinDistLP2 (tp1, tp2, p);
+      double d2 = MinDistLP2 (tp1, tp3, p);
+      double d3 = MinDistLP2 (tp2, tp3, p);
+      res = min3 (d1, d2, d3);
+      */
+    }
+
+  return res;
+
+  Vec3d pp1(tp1, p);
+  Vec3d v1(tp1, tp2), v2(tp1, tp3);
+
+  double c = pp1.Length2();
+  double cx = -2 * (pp1 * v1);
+  double cy = -2 * (pp1 * v2);
+  double cxx = v1.Length2();
+  double cxy = 2 * (v1 * v2);
+  double cyy = v2.Length2();
+
+  QuadraticPolynomial2V pol (-c, -cx, -cy, -cxx, -cxy, -cyy);
+  double res2 =  - pol.MaxUnitTriangle ();
+
+  if (fabs (res - res2) > 1e-8)
+    cout << "res and res2 differ: " << res << " != " << res2 << endl;
+  return res2;
+}
+
+
+// 0 checks !!!
+double MinDistLL2 (const Point3d & l1p1, const Point3d & l1p2,
+		  const Point3d & l2p1, const Point3d & l2p2)
+{
+  // dist(lam1,lam2) = \| l2p1+lam2v2 - (l1p1+lam1 v1) \|
+  // min !
+
+  Vec3d l1l2 (l1p1, l2p1);
+  Vec3d v1 (l1p1, l1p2);
+  Vec3d v2 (l2p1, l2p2);
+
+  double a11, a12, a22, rs1, rs2;
+  double lam1, lam2, det;
+
+  a11 = v1*v1;
+  a12 = -(v1*v2);
+  a22 = v2*v2;
+  rs1 = l1l2 * v1;
+  rs2 = - (l1l2 * v2);
+  
+  det = a11 * a22 - a12 * a12;
+  if (det < 1e-14 * a11 * a22) 
+    det = 1e-14 * a11 * a22;  // regularization should be stable
+
+  if (det < 1e-20)
+    det = 1e-20;
+
+
+  lam1 = (a22 * rs1 - a12 * rs2) / det;
+  lam2 = (-a12 * rs1 + a11 * rs2) / det;
+
+  if (lam1 >= 0 && lam2 >= 0 && lam1 <= 1 && lam2 <= 1)
+    {
+      Vec3d v = l1l2 + (-lam1) * v1 + lam2 * v2;
+      return v.Length2();
+    }
+
+  double minv, hv;
+  minv = MinDistLP2 (l1p1, l1p2, l2p1);
+  hv =  MinDistLP2 (l1p1, l1p2, l2p2);
+  if (hv < minv) minv = hv;
+
+  hv =  MinDistLP2 (l2p1, l2p2, l1p1);
+  if (hv < minv) minv = hv;
+  hv =  MinDistLP2 (l2p1, l2p2, l1p2);
+  if (hv < minv) minv = hv;
+
+  return minv;
+}
+			 
+}
+
+
diff --git a/contrib/Netgen/libsrc/gprim/geomtest3d.hpp b/contrib/Netgen/libsrc/gprim/geomtest3d.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..7ce362d05222c857288ea0e8d9c8fc1f25fc90e6
--- /dev/null
+++ b/contrib/Netgen/libsrc/gprim/geomtest3d.hpp
@@ -0,0 +1,80 @@
+#ifndef FILE_GEOMTEST3D
+#define FILE_GEOMTEST3D
+
+/* *************************************************************************/
+/* File:   geomtest3d.hh                                                   */
+/* Author: Joachim Schoeberl                                               */
+/* Date:   13. Feb. 98                                                     */
+/* *************************************************************************/
+
+
+
+extern int
+IntersectTriangleLine (const Point<3> ** tri, const Point<3> ** line);
+
+
+
+/**
+  Returns 0, iff
+  closure (tet)  cup  closure (tri)  is empty, one corner point of tet,
+  one edge of tet or one face of tet
+ */
+extern int 
+IntersectTetTriangle (const Point<3> ** tet, const Point<3> ** tri,
+		      const int * tetpi = NULL, const int * tripi = NULL);
+
+/**
+  Same test as above, but tet int reference position (0, ex, ey, ez),
+  tetpi = 1, 2, 4, 5
+ */
+extern int 
+IntersectTetTriangleRef (const Point3d ** tri, const int * tripi = NULL);
+
+
+// 1, iff not regular triangulation
+extern int 
+IntersectTriangleTriangle (const Point<3> ** tri1, const Point<3> ** tri2);
+
+
+extern void
+LocalCoordinates (const Vec3d & e1, const Vec3d & e2,
+		  const Vec3d & v, double & lam1, double & lam2);
+
+/// return 1 = degenerated sphere
+extern int
+CalcSphereCenter (const Point<3> ** pts, Point<3> & c);
+
+/// return 1 = degenerated triangle
+extern int
+CalcTriangleCenter (const Point3d ** pts, Point3d & c);
+
+
+
+/*
+  Compute radius of cylinder fitting 4 points.
+  cylinder axis is in the direction of p1-p2
+*/
+extern double ComputeCylinderRadius (const Point3d & p1, const Point3d & p2,
+				     const Point3d & p3, const Point3d & p4);
+
+/*
+  Two triangles T1 and T2 have normals n1 and n2.
+  The height over the common edge is h1, and h2.
+  Radius of cylinder fitting both triangles
+*/
+extern double ComputeCylinderRadius (const Vec3d & n1, const Vec3d & n2,
+				     double h1, double h2);
+
+
+extern double MinDistLP2 (const Point2d & lp1, const Point2d & lp2, const Point2d & p);
+
+extern double MinDistLP2 (const Point3d & lp1, const Point3d & lp2, const Point3d & p);
+
+extern double MinDistTP2 (const Point3d & tp1, const Point3d & tp2, 
+			  const Point3d & tp3, const Point3d & p);
+
+extern double MinDistLL2 (const Point3d & l1p1, const Point3d & l1p2,
+			  const Point3d & l2p1, const Point3d & l2p2);
+
+
+#endif
diff --git a/contrib/Netgen/libsrc/gprim/gprim.hpp b/contrib/Netgen/libsrc/gprim/gprim.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..0f57ebac869366f0bb1eeefe4c65ca93c1ab4526
--- /dev/null
+++ b/contrib/Netgen/libsrc/gprim/gprim.hpp
@@ -0,0 +1,26 @@
+#ifndef FILE_GPRIM
+#define FILE_GPRIM
+
+/* *************************************************************************/
+/* File:   gprim.hpp                                                        */
+/* Author: Joachim Schoeberl                                               */
+/* Date:   14. Aug. 97                                                     */
+/* *************************************************************************/
+
+
+namespace netgen
+{
+#include "geomobjects.hpp"
+#include "geomops.hpp"
+#include "geomfuncs.hpp"
+
+#include "geom2d.hpp"
+#include "geom3d.hpp"
+#include "geomtest3d.hpp"
+// #include "rot3d.hpp"
+#include "transform3d.hpp"
+// #include "reftrans.hpp"
+#include "adtree.hpp"
+}
+
+#endif
diff --git a/contrib/Netgen/libsrc/gprim/transform3d.cpp b/contrib/Netgen/libsrc/gprim/transform3d.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..ea62fffe5a0e9563644b0428f822ca1bbf2cac77
--- /dev/null
+++ b/contrib/Netgen/libsrc/gprim/transform3d.cpp
@@ -0,0 +1,173 @@
+#include <mystdlib.h>
+
+#include <myadt.hpp>
+#include <gprim.hpp>
+#include <linalg.hpp>
+
+namespace netgen
+{
+
+Transformation3d :: Transformation3d ()
+{
+  int i, j;
+  for (i = 0; i < 3; i++)
+    {
+      offset[i] = 0;
+      for (j = 0; j < 3; j++)
+	lin[i][j] = 0;
+    }
+}
+
+Transformation3d :: Transformation3d (const Vec3d & translate)
+{
+  int i, j;
+  for (i = 0; i < 3; i++)
+    for (j = 0; j < 3; j++)
+      lin[i][j] = 0;
+  for (i = 0; i < 3; i++)
+    {
+      offset[i] = translate.X(i+1);
+      lin[i][i] = 1;
+    }
+}
+
+
+Transformation3d :: 
+Transformation3d (const Point3d & c, double alpha, 
+		  double beta, double gamma)
+{
+  // total = T_c x Rot_0 x T_c^{-1}
+  // Use Euler angles, see many books from tech mech, e.g. 
+  // Shabana "multibody systems"
+
+  Transformation3d tc(c);
+  Transformation3d tcinv;
+  tc.CalcInverse (tcinv);
+
+  Transformation3d r1, r2, r3, ht, ht2;
+  r1.SetAxisRotation (3, alpha);
+  r2.SetAxisRotation (1, beta);
+  r3.SetAxisRotation (3, gamma);
+
+  ht.Combine (tc, r3);
+  ht2.Combine (ht, r2);
+  ht.Combine (ht2, r1);
+  Combine (ht, tcinv);
+
+ cout << "Rotation - Transformation:" << (*this) << endl;
+  //  (*testout) << "Rotation - Transformation:" << (*this) << endl;
+}
+
+
+
+
+Transformation3d :: Transformation3d (const Point3d ** pp)
+{
+  int i, j;
+  for (i = 1; i <= 3; i++)
+    {
+      offset[i-1] = (*pp[0]).X(i);
+      for (j = 1; j <= 3; j++)
+	lin[i-1][j-1] = (*pp[j]).X(i) - (*pp[0]).X(i);
+    }
+}
+
+Transformation3d :: Transformation3d (const Point3d pp[])
+{
+  int i, j;
+  for (i = 1; i <= 3; i++)
+    {
+      offset[i-1] = pp[0].X(i);
+      for (j = 1; j <= 3; j++)
+	lin[i-1][j-1] = pp[j].X(i) - pp[0].X(i);
+    }
+}
+
+
+void Transformation3d :: CalcInverse (Transformation3d & inv) const
+{
+  static DenseMatrix a(3), inva(3);
+  static Vector b(3), sol(3);
+  int i, j;
+  
+  for (i = 1; i <= 3; i++)
+    {
+      b.Elem(i) = offset[i-1];
+      for (j = 1; j <= 3; j++)
+	a.Elem(i, j) = lin[i-1][j-1];
+    }
+
+  ::netgen::CalcInverse (a, inva);
+  inva.Mult (b, sol);
+
+  for (i = 1; i <= 3; i++)
+    {
+      inv.offset[i-1] = -sol.Get(i);
+      for (j = 1; j <= 3; j++)
+	inv.lin[i-1][j-1] = inva.Elem(i, j);
+    }
+}
+
+
+void  Transformation3d:: 
+Combine (const Transformation3d & ta, const Transformation3d & tb)
+{
+  int i, j, k;
+
+  // o = o_a+ m_a o_b
+  // m = m_a m_b
+
+  for (i = 0; i <= 2; i++)
+    {
+      offset[i] = ta.offset[i];
+      for (j = 0; j <= 2; j++)
+	offset[i] += ta.lin[i][j] * tb.offset[j];
+    }
+  
+  for (i = 0; i <= 2; i++)
+    for (j = 0; j <= 2; j++)
+      {
+	lin[i][j] = 0;
+	for (k = 0; k <= 2; k++)
+	  lin[i][j] += ta.lin[i][k] * tb.lin[k][j];
+      }
+}
+void Transformation3d :: SetAxisRotation (int dir, double alpha)
+{
+  double co = cos(alpha);
+  double si = sin(alpha);
+  dir--;
+  int pos1 = (dir+1) % 3;
+  int pos2 = (dir+2) % 3;
+
+  int i, j;
+  for (i = 0; i <= 2; i++)
+    {
+      offset[i] = 0;
+      for (j = 0; j <= 2; j++)
+	lin[i][j] = 0;
+    }
+
+  lin[dir][dir] = 1;
+  lin[pos1][pos1] = co;
+  lin[pos2][pos2] = co;
+  lin[pos1][pos2] = si;
+  lin[pos2][pos1] = -si;
+}
+
+ostream & operator<< (ostream & ost, Transformation3d & trans)
+{
+  int i, j;
+  ost << "offset = ";
+  for (i = 0; i <= 2; i++)
+    ost << trans.offset[i] << " ";
+  ost << endl << "linear = " << endl;
+  for (i = 0; i <= 2; i++)
+    {
+      for (j = 0; j <= 2; j++)
+	ost << trans.lin[i][j] << " ";
+      ost << endl;
+    }
+  return ost;
+}
+}
diff --git a/contrib/Netgen/libsrc/gprim/transform3d.hpp b/contrib/Netgen/libsrc/gprim/transform3d.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..2754173e2469ebf5e2df1823abb6a03ddf17e26f
--- /dev/null
+++ b/contrib/Netgen/libsrc/gprim/transform3d.hpp
@@ -0,0 +1,190 @@
+#ifndef FILE_TRANSFORM3D
+#define FILE_TRANSFORM3D
+
+/* *************************************************************************/
+/* File:   transform3d.hh                                                  */
+/* Author: Joachim Schoeberl                                               */
+/* Date:   22. Mar. 98                                                     */
+/* *************************************************************************/
+
+/*
+  Affine - Linear mapping in 3D space
+ */
+
+class Transformation3d;
+ostream & operator<< (ostream & ost, Transformation3d & trans);
+
+class Transformation3d
+{
+  double lin[3][3];
+  double offset[3];
+public:
+  ///
+  Transformation3d ();
+  /// Unit tet is mapped to tet descibed by pp
+  Transformation3d (const Point3d ** pp);
+  /// Unit tet is mapped to tet descibed by pp
+  Transformation3d (const Point3d pp[]);
+  /// translation
+  Transformation3d (const Vec3d & translate);
+  /// rotation with ...
+  Transformation3d (const Point3d & c, double alpha, double beta, double gamma);
+  /// 
+  void CalcInverse (Transformation3d & inv) const;
+  /// this = ta x tb
+  void Combine (const Transformation3d & ta, const Transformation3d & tb);
+  /// dir = 1..3 (== x..z)
+  void SetAxisRotation (int dir, double alpha);
+  ///
+  void Transform (const Point3d & from, Point3d & to) const
+    {
+      for (int i = 1; i <= 3; i++)
+	{
+	  to.X(i) = offset[i-1] + lin[i-1][0] * from.X(1) + 
+	    lin[i-1][1] * from.X(2) + lin[i-1][2] * from.X(3);
+	}
+    }
+
+  ///
+  void Transform (Point3d & p) const
+  {
+    Point3d hp;
+    Transform (p, hp);
+    p = hp;
+  }
+
+  /// transform vector, apply only linear part, not offset
+  void Transform (const Vec3d & from, Vec3d & to) const
+    {
+      for (int i = 1; i <= 3; i++)
+	{
+	  to.X(i) = lin[i-1][0] * from.X(1) + 
+	    lin[i-1][1] * from.X(2) + lin[i-1][2] * from.X(3);
+	}
+    }
+  friend ostream & operator<< (ostream & ost, Transformation3d & trans);
+};
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+template <int D>
+class Transformation
+{
+  Mat<D> m;
+  Vec<D> v;
+public:
+  ///
+  Transformation () { m = 0; v = 0; }
+
+  /// Unit tet is mapped to tet descibed by pp
+  Transformation (const Point<D> * pp);
+
+  /// translation
+  Transformation (const Vec<D> & translate)
+  {
+    v = translate;
+    m = 0;
+    for (int i = 0; i < D; i++)
+      m(i,i) = 1;
+  }
+
+  // rotation with ...
+  Transformation (const Point<D> & c, double alpha, double beta, double gamma)
+  {
+    // total = T_c x Rot_0 x T_c^{-1}
+    // Use Euler angles, see many books from tech mech, e.g. 
+    // Shabana "multibody systems"
+    
+    Vec<D> vc(c);
+    Transformation<D> tc(vc);
+    Transformation<D> tcinv(-vc);
+    // tc.CalcInverse (tcinv);
+    
+    Transformation<D> r1, r2, r3, ht, ht2;
+    r1.SetAxisRotation (3, alpha);
+    r2.SetAxisRotation (1, beta);
+    r3.SetAxisRotation (3, gamma);
+    
+    ht.Combine (tc, r3);
+    ht2.Combine (ht, r2);
+    ht.Combine (ht2, r1);
+    Combine (ht, tcinv);
+    
+    // cout << "Rotation - Transformation:" << (*this) << endl;
+    //  (*testout) << "Rotation - Transformation:" << (*this) << endl;
+  }
+
+  /// 
+  void CalcInverse (Transformation & inv) const;
+
+  /// this = ta x tb
+  void Combine (const Transformation & ta, const Transformation & tb)
+  {
+    v = ta.v + ta.m * tb.v;
+    m = ta.m * tb.m;
+  }
+
+
+
+  /// dir = 1..3 (== x..z)
+  void SetAxisRotation (int dir, double alpha)
+  {
+    double co = cos(alpha);
+    double si = sin(alpha);
+    dir--;
+    int pos1 = (dir+1) % 3;
+    int pos2 = (dir+2) % 3;
+    
+    int i, j;
+    for (i = 0; i <= 2; i++)
+    {
+      v(i) = 0;
+      for (j = 0; j <= 2; j++)
+	m(i,j) = 0;
+    }
+    
+    m(dir,dir) = 1;
+    m(pos1, pos1) = co;
+    m(pos2, pos2) = co;
+    m(pos1, pos2) = si;
+    m(pos2, pos1) = -si;
+  }
+
+  ///
+  void Transform (const Point<D> & from, Point<D> & to) const
+  {
+    to = Point<D> (v + m * Vec<D>(from));
+  }
+
+  void Transform (Point<D> & p) const
+  {
+    p = Point<D> (v + m * Vec<D>(p));
+  }
+
+
+
+  /// transform vector, apply only linear part, not offset
+  void Transform (const Vec<D> & from, Vec<D> & to) const
+  {
+    to = m * from;
+  }
+};
+
+template <int D>
+ostream & operator<< (ostream & ost, Transformation<D> & trans);
+
+
+
+
+#endif
diff --git a/contrib/Netgen/libsrc/include/FlexLexer.h b/contrib/Netgen/libsrc/include/FlexLexer.h
new file mode 100644
index 0000000000000000000000000000000000000000..f6120759597d8b5aae428f7f8940481a6fa40fd5
--- /dev/null
+++ b/contrib/Netgen/libsrc/include/FlexLexer.h
@@ -0,0 +1,184 @@
+// $Header: /cvsroot/gmsh/contrib/Netgen/libsrc/include/FlexLexer.h,v 1.3 2008-09-24 18:04:44 geuzaine Exp $
+
+// FlexLexer.h -- define interfaces for lexical analyzer classes generated
+//		  by flex
+
+// Copyright (c) 1993 The Regents of the University of California.
+// All rights reserved.
+//
+// This code is derived from software contributed to Berkeley by
+// Kent Williams and Tom Epperly.
+//
+// Redistribution and use in source and binary forms are permitted provided
+// that: (1) source distributions retain this entire copyright notice and
+// comment, and (2) distributions including binaries display the following
+// acknowledgement:  ``This product includes software developed by the
+// University of California, Berkeley and its contributors'' in the
+// documentation or other materials provided with the distribution and in
+// all advertising materials mentioning features or use of this software.
+// Neither the name of the University nor the names of its contributors may
+// be used to endorse or promote products derived from this software without
+// specific prior written permission.
+// THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+// WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+
+// This file defines FlexLexer, an abstract class which specifies the
+// external interface provided to flex C++ lexer objects, and yyFlexLexer,
+// which defines a particular lexer class.
+//
+// If you want to create multiple lexer classes, you use the -P flag
+// to rename each yyFlexLexer to some other xxFlexLexer.  You then
+// include <FlexLexer.h> in your other sources once per lexer class:
+//
+//	#undef yyFlexLexer
+//	#define yyFlexLexer xxFlexLexer
+//	#include <FlexLexer.h>
+//
+//	#undef yyFlexLexer
+//	#define yyFlexLexer zzFlexLexer
+//	#include <FlexLexer.h>
+//	...
+
+#ifndef __FLEX_LEXER_H
+// Never included before - need to define base class.
+#define __FLEX_LEXER_H
+
+
+extern "C++" {
+struct yy_buffer_state;
+typedef int yy_state_type;
+
+class FlexLexer {
+public:
+	virtual ~FlexLexer()	{ }
+
+	const char* YYText()	{ return yytext; }
+	int YYLeng()		{ return yyleng; }
+
+	virtual void
+		yy_switch_to_buffer( struct yy_buffer_state* new_buffer ) = 0;
+	virtual struct yy_buffer_state*
+		yy_create_buffer( istream* s, int size ) = 0;
+	virtual void yy_delete_buffer( struct yy_buffer_state* b ) = 0;
+	virtual void yyrestart( istream* s ) = 0;
+
+	virtual int yylex() = 0;
+
+	// Call yylex with new input/output sources.
+	int yylex( istream* new_in, ostream* new_out = 0 )
+		{
+		switch_streams( new_in, new_out );
+		return yylex();
+		}
+
+	// Switch to new input/output streams.  A nil stream pointer
+	// indicates "keep the current one".
+	virtual void switch_streams( istream* new_in = 0,
+					ostream* new_out = 0 ) = 0;
+
+	int lineno() const		{ return yylineno; }
+
+	int debug() const		{ return yy_flex_debug; }
+	void set_debug( int flag )	{ yy_flex_debug = flag; }
+
+protected:
+	char* yytext;
+	int yyleng;
+	int yylineno;		// only maintained if you use %option yylineno
+	int yy_flex_debug;	// only has effect with -d or "%option debug"
+};
+
+}
+#endif
+
+#if defined(yyFlexLexer) || ! defined(yyFlexLexerOnce)
+// Either this is the first time through (yyFlexLexerOnce not defined),
+// or this is a repeated include to define a different flavor of
+// yyFlexLexer, as discussed in the flex man page.
+#define yyFlexLexerOnce
+
+class yyFlexLexer : public FlexLexer {
+public:
+	// arg_yyin and arg_yyout default to the cin and cout, but we
+	// only make that assignment when initializing in yylex().
+	yyFlexLexer( istream* arg_yyin = 0, ostream* arg_yyout = 0 );
+
+	virtual ~yyFlexLexer();
+
+	void yy_switch_to_buffer( struct yy_buffer_state* new_buffer );
+	struct yy_buffer_state* yy_create_buffer( istream* s, int size );
+	void yy_delete_buffer( struct yy_buffer_state* b );
+	void yyrestart( istream* s );
+
+	virtual int yylex();
+	virtual void switch_streams( istream* new_in, ostream* new_out );
+
+protected:
+	virtual int LexerInput( char* buf, int max_size );
+	virtual void LexerOutput( const char* buf, int size );
+	virtual void LexerError( const char* msg );
+
+	void yyunput( int c, char* buf_ptr );
+	int yyinput();
+
+	void yy_load_buffer_state();
+	void yy_init_buffer( struct yy_buffer_state* b, istream* s );
+	void yy_flush_buffer( struct yy_buffer_state* b );
+
+	int yy_start_stack_ptr;
+	int yy_start_stack_depth;
+	int* yy_start_stack;
+
+	void yy_push_state( int new_state );
+	void yy_pop_state();
+	int yy_top_state();
+
+	yy_state_type yy_get_previous_state();
+	yy_state_type yy_try_NUL_trans( yy_state_type current_state );
+	int yy_get_next_buffer();
+
+	istream* yyin;	// input source for default LexerInput
+	ostream* yyout;	// output sink for default LexerOutput
+
+	struct yy_buffer_state* yy_current_buffer;
+
+	// yy_hold_char holds the character lost when yytext is formed.
+	char yy_hold_char;
+
+	// Number of characters read into yy_ch_buf.
+	int yy_n_chars;
+
+	// Points to current character in buffer.
+	char* yy_c_buf_p;
+
+	int yy_init;		// whether we need to initialize
+	int yy_start;		// start state number
+
+	// Flag which is used to allow yywrap()'s to do buffer switches
+	// instead of setting up a fresh yyin.  A bit of a hack ...
+	int yy_did_buffer_switch_on_eof;
+
+	// The following are not always needed, but may be depending
+	// on use of certain flex features (like REJECT or yymore()).
+
+	yy_state_type yy_last_accepting_state;
+	char* yy_last_accepting_cpos;
+
+	yy_state_type* yy_state_buf;
+	yy_state_type* yy_state_ptr;
+
+	char* yy_full_match;
+	int* yy_full_state;
+	int yy_full_lp;
+
+	int yy_lp;
+	int yy_looking_for_trail_begin;
+
+	int yy_more_flag;
+	int yy_more_len;
+	int yy_more_offset;
+	int yy_prev_more_offset;
+};
+
+#endif
diff --git a/contrib/Netgen/libsrc/include/acisgeom.hpp b/contrib/Netgen/libsrc/include/acisgeom.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..491b7720dbdb18f49b2fce4530708f0c890170f0
--- /dev/null
+++ b/contrib/Netgen/libsrc/include/acisgeom.hpp
@@ -0,0 +1,3 @@
+#ifdef ACIS
+#include "../acisgeom/acisgeom.hpp"
+#endif
diff --git a/contrib/Netgen/libsrc/include/csg.hpp b/contrib/Netgen/libsrc/include/csg.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..ffd45ef0bf4fb948a3efd2432eb8e7b6c111900c
--- /dev/null
+++ b/contrib/Netgen/libsrc/include/csg.hpp
@@ -0,0 +1 @@
+#include "../csg/csg.hpp"
diff --git a/contrib/Netgen/libsrc/include/geometry2d.hpp b/contrib/Netgen/libsrc/include/geometry2d.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..bf0965c228fc36935a9c2a539aa8d1ea133ad158
--- /dev/null
+++ b/contrib/Netgen/libsrc/include/geometry2d.hpp
@@ -0,0 +1 @@
+#include "../geom2d/geometry2d.hpp"
diff --git a/contrib/Netgen/libsrc/include/gprim.hpp b/contrib/Netgen/libsrc/include/gprim.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..1e827aaf8c01c9b7296876c16309c3462e772ac8
--- /dev/null
+++ b/contrib/Netgen/libsrc/include/gprim.hpp
@@ -0,0 +1 @@
+#include "../gprim/gprim.hpp"
diff --git a/contrib/Netgen/libsrc/include/incvis.hpp b/contrib/Netgen/libsrc/include/incvis.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..0f2b1026a0670f49b5976cd82249dea3e1815f6c
--- /dev/null
+++ b/contrib/Netgen/libsrc/include/incvis.hpp
@@ -0,0 +1,31 @@
+// libraries for User interface:
+
+
+#ifndef NOTCL
+
+#include <tcl.h>
+#include <tk.h>
+
+#if TK_MAJOR_VERSION==8 && TK_MINOR_VERSION>=4
+#define tcl_const const
+#else
+#define tcl_const
+#endif
+
+#endif
+
+#include <GL/gl.h>
+#include <GL/glu.h>
+#ifndef NOTCL
+#include "../../togl/togl.h"
+#endif
+
+
+
+
+// part of OpenGL 1.2, but not in Microsoft's OpenGL 1.1 header:
+// GL version sould be checked at runtime
+#ifndef GL_CLAMP_TO_EDGE
+#define GL_CLAMP_TO_EDGE 0x812F
+#endif
+
diff --git a/contrib/Netgen/libsrc/include/linalg.hpp b/contrib/Netgen/libsrc/include/linalg.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..e96bd036c3ed3606d458b2db3275fb273d27d138
--- /dev/null
+++ b/contrib/Netgen/libsrc/include/linalg.hpp
@@ -0,0 +1 @@
+#include "../linalg/linalg.hpp"
diff --git a/contrib/Netgen/libsrc/include/meshing.hpp b/contrib/Netgen/libsrc/include/meshing.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..e41a88f9f221c969e56923d95d5dc9c5214b98f3
--- /dev/null
+++ b/contrib/Netgen/libsrc/include/meshing.hpp
@@ -0,0 +1 @@
+#include <../meshing/meshing.hpp>
diff --git a/contrib/Netgen/libsrc/include/myadt.hpp b/contrib/Netgen/libsrc/include/myadt.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..d36bef05c12d28b9aa35e9c1de6fcd8df749dcc9
--- /dev/null
+++ b/contrib/Netgen/libsrc/include/myadt.hpp
@@ -0,0 +1 @@
+#include <../general/myadt.hpp>
diff --git a/contrib/Netgen/libsrc/include/mydefs.hpp b/contrib/Netgen/libsrc/include/mydefs.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..c34ce56a8e03cd621577d526e57b65ce358346a6
--- /dev/null
+++ b/contrib/Netgen/libsrc/include/mydefs.hpp
@@ -0,0 +1,29 @@
+#ifndef FILE_MYDEFS
+#define FILE_MYDEFS
+
+/**************************************************************************/
+/* File:   mydefs.hh                                                      */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   10. Mar. 98                                                    */
+/**************************************************************************/
+
+/*
+  defines for graphics, testmodes, ...
+*/
+
+
+// #define DEBUG
+
+
+#define noDEMOVERSION
+#define noDEVELOP
+#define noSTEP
+#define noSOLIDGEOM
+
+#define noDEMOAPP
+#define noMODELLER
+
+#define noSTAT_STREAM
+#define noLOG_STREAM
+
+#endif
diff --git a/contrib/Netgen/libsrc/include/mystdlib.h b/contrib/Netgen/libsrc/include/mystdlib.h
new file mode 100644
index 0000000000000000000000000000000000000000..939a268e6ea1eebe0d3c8d7235a75c256f0b5abb
--- /dev/null
+++ b/contrib/Netgen/libsrc/include/mystdlib.h
@@ -0,0 +1,104 @@
+#ifndef FILE_MYSTDLIB
+#define FILE_MYSTDLIB
+
+
+#include <iostream>
+#include <iomanip>
+#include <fstream>
+#include <sstream>
+
+#ifdef OLDCINCLUDE
+
+// e.g., CC compiler on SGI
+#include <stdlib.h>
+#include <stdio.h>
+#include <math.h>
+#include <malloc.h>
+#include <ctype.h>
+#include <time.h>
+
+#else
+
+// new standard
+#include <cstdlib>
+#include <cstdio>
+#include <cmath>
+#include <cctype>
+#include <ctime>
+#include <cstring>
+#include <climits>
+#endif
+
+
+
+#include <new>
+#include <string>
+#include <typeinfo>
+
+#ifdef PARALLEL
+#undef SEEK_SET
+#undef SEEK_CUR
+#undef SEEK_END
+#include <mpi.h>
+#endif
+
+#ifdef _OPENMP
+#include <omp.h>
+#endif
+
+
+#ifdef METIS
+namespace metis { extern "C" {
+#include <metis.h>
+} }
+#endif
+
+
+
+#ifndef NO_PARALLEL_THREADS
+#ifndef WIN32
+#include <pthread.h>
+#endif
+#endif
+
+#ifndef M_PI
+#define M_PI 3.14159265358979323846
+#endif
+
+
+/*** Windows headers ***/
+#ifdef _MSC_VER
+# define WIN32_LEAN_AND_MEAN
+# ifndef NO_PARALLEL_THREADS
+#  include <afxwin.h>
+#  include <afxmt.h>
+# endif
+# include <windows.h>
+# undef WIN32_LEAN_AND_MEAN
+# include <winnt.h>
+
+#else
+# ifndef NO_PARALLEL_THREADS
+#  include <pthread.h>
+# endif
+#endif
+
+/*
+extern void* operator new(std::size_t) throw (std::bad_alloc);
+extern void* operator new[](std::size_t) throw (std::bad_alloc);
+extern void operator delete(void*) throw();
+extern void operator delete[](void*) throw();
+*/
+
+/*
+extern int mem_alloc;
+extern int mem_total_alloc;
+extern int mem_max_alloc;
+extern int mem_total_alloc_array;
+extern int mem_total_alloc_table;
+*/
+
+using namespace std;
+
+#endif
+
diff --git a/contrib/Netgen/libsrc/include/occgeom.hpp b/contrib/Netgen/libsrc/include/occgeom.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..af258e0df032193ef448a72102d8c7215ec9d9b0
--- /dev/null
+++ b/contrib/Netgen/libsrc/include/occgeom.hpp
@@ -0,0 +1 @@
+#include "../occ/occgeom.hpp"
diff --git a/contrib/Netgen/libsrc/include/opti.hpp b/contrib/Netgen/libsrc/include/opti.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..6b8a0b61c8d1eb081531c9351ab2a7b3ba85fbe8
--- /dev/null
+++ b/contrib/Netgen/libsrc/include/opti.hpp
@@ -0,0 +1 @@
+#include "../opti/opti.hpp"
diff --git a/contrib/Netgen/libsrc/include/parallel.hpp b/contrib/Netgen/libsrc/include/parallel.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..4ba662f810ea4c6240c57cf64608803abc18f602
--- /dev/null
+++ b/contrib/Netgen/libsrc/include/parallel.hpp
@@ -0,0 +1 @@
+#include "../parallel/parallel.hpp"
diff --git a/contrib/Netgen/libsrc/include/stepgeom.hpp b/contrib/Netgen/libsrc/include/stepgeom.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..d2c5c5e41e9683fe5f8537c4fae9337306c1d02a
--- /dev/null
+++ b/contrib/Netgen/libsrc/include/stepgeom.hpp
@@ -0,0 +1,10 @@
+#include "../stepgeom/geomanif.hh"
+#include "../stepgeom/geopac2d.hh"
+#include "../stepgeom/geopac3d.hh"
+#include "../stepgeom/geosplinesurf.hh"
+#include "../stepgeom/algprim.hh"
+#include "../stepgeom/scenery.hh"
+#include "../stepgeom/brep.hh"
+#include "../stepgeom/adtcrit.hh"
+#include "../stepgeom/STEPgeom.hh"
+#include "../stepgeom/visapprox.hh"
diff --git a/contrib/Netgen/libsrc/include/stepreader.hpp b/contrib/Netgen/libsrc/include/stepreader.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..0214d58d9dcf3297ee09ef74abd6a03af3e72390
--- /dev/null
+++ b/contrib/Netgen/libsrc/include/stepreader.hpp
@@ -0,0 +1 @@
+#include "../stepgeom/STEPread.hh"
diff --git a/contrib/Netgen/libsrc/include/stlgeom.hpp b/contrib/Netgen/libsrc/include/stlgeom.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..f1eea264e11281071ae2ae1235bc098ff3352ce6
--- /dev/null
+++ b/contrib/Netgen/libsrc/include/stlgeom.hpp
@@ -0,0 +1 @@
+#include <../stlgeom/stlgeom.hpp>
diff --git a/contrib/Netgen/libsrc/include/visual.hpp b/contrib/Netgen/libsrc/include/visual.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..f026f5a458c6c131b65b0b1d616d42eefae015a5
--- /dev/null
+++ b/contrib/Netgen/libsrc/include/visual.hpp
@@ -0,0 +1 @@
+#include "../visualization/visual.hpp"
diff --git a/contrib/Netgen/libsrc/interface/Makefile b/contrib/Netgen/libsrc/interface/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..8c8cfcc69ac4168b896925f83e74ee06ec9a638f
--- /dev/null
+++ b/contrib/Netgen/libsrc/interface/Makefile
@@ -0,0 +1,9 @@
+# MODIFIED FOR GMSH
+#src = nginterface.cpp writeuser.cpp writediffpack.cpp writeabaqus.cpp writefluent.cpp writepermas.cpp writetochnog.cpp writetecplot.cpp wuchemnitz.cpp writetochnog.cpp writefeap.cpp writeelmer.cpp  writegmsh.cpp writejcm.cpp writetet.cpp writedolfin.cpp readuser.cpp importsolution.cpp readtetmesh.cpp
+src = nglib.cpp
+#
+lib = nginterface
+libpath = libsrc/interface
+#
+include ../makefile.inc
+#
diff --git a/contrib/Netgen/libsrc/interface/importsolution.cpp b/contrib/Netgen/libsrc/interface/importsolution.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..4f9d3e6727658f295aacf6fee57333d4a414a834
--- /dev/null
+++ b/contrib/Netgen/libsrc/interface/importsolution.cpp
@@ -0,0 +1,129 @@
+//
+//  Read solution file
+//
+
+
+#include <mystdlib.h>
+
+
+#include <myadt.hpp>
+#include <linalg.hpp>
+#include <csg.hpp>
+#include <meshing.hpp>
+
+#include "nginterface.h"
+
+namespace netgen
+{
+#include "writeuser.hpp"
+
+
+void ImportSolution (const char * filename)
+{
+  ifstream inf (filename);
+  char buf[100], name[1000];
+  int i, size, comps, order;
+  bool iscomplex;
+  const char * type;
+  Flags flags;
+
+  while (1)
+    {
+      buf[0] = 0;
+      inf >> buf;
+      if (strcmp (buf, "solution") == 0)
+	{
+	  inf >> name;
+	  
+	  inf >> buf[0];
+	  flags.DeleteFlags ();
+	  while (buf[0] == '-')
+	    {
+	      inf >> buf[1];
+	      inf.putback (buf[1]);
+	      if (!isalpha (buf[1]))
+		{
+		  break;
+		}
+	      inf >> (buf+1);
+	      flags.SetCommandLineFlag (buf);
+	      buf[0] = 0;
+	      inf >> buf[0];
+	    }
+	  inf.putback (buf[0]);
+
+	  (*testout) << "Flags: " << endl;
+	  flags.PrintFlags (*testout);
+	  (*testout) << "done" << endl;
+
+	  size = int(flags.GetNumFlag ("size", Ng_GetNP()));
+	  comps = int(flags.GetNumFlag ("components", 1));
+	  type = flags.GetStringFlag ("type", "nodal");
+	  order = int(flags.GetNumFlag ("order", 1));
+	  iscomplex = flags.GetDefineFlag ("complex");
+
+	  double * sol = new double[size*comps];
+	  
+	  (*testout) << "import solution " << name << " size = " << size << " comps = " << comps << " order = " << order << endl;
+
+	  for (i = 0; i < size*comps; i++)
+	    {
+	      inf >> sol[i];
+	      //	      (*testout) << "sol: " << sol[i] << endl;
+	    }
+	  
+	  Ng_SolutionData soldata;
+	  Ng_InitSolutionData (&soldata);
+	  soldata.name = name;
+	  soldata.data = sol;
+	  soldata.dist = comps;
+	  soldata.components = comps;
+	  soldata.order = order;
+	  soldata.iscomplex = iscomplex;
+	  soldata.soltype = NG_SOLUTION_NODAL;
+          soldata.draw_surface = 1;
+          soldata.draw_volume = 1;
+	  if (strcmp (type, "element") == 0)
+            {
+              soldata.soltype = NG_SOLUTION_ELEMENT;
+              soldata.draw_surface = 0;
+            }
+	  if (strcmp (type, "surfaceelement") == 0)
+            {
+              soldata.soltype = NG_SOLUTION_SURFACE_ELEMENT;
+              soldata.draw_volume = 0;
+            }
+	  if (strcmp (type, "noncontinuous") == 0)
+	    soldata.soltype = NG_SOLUTION_NONCONTINUOUS;
+	  if (strcmp (type, "surfacenoncontinuous") == 0)
+	    soldata.soltype = NG_SOLUTION_SURFACE_NONCONTINUOUS;
+
+	  Ng_SetSolutionData (&soldata);
+	  }
+      else
+	{
+	  //	  cout << "kw = (" << buf << ")" << endl;
+	  (*testout) << "kw = (" << buf << ")" << endl;
+	  break;
+	}
+    }
+  /*
+  struct Ng_SolutionData
+    {
+      char * name;      // name of gridfunction
+      double * data;    // solution values
+      int components;   // used components in solution vector
+      int dist;         // num of doubles per entry (alignment!)
+      Ng_SolutionType soltype;  // type of solution function
+  };
+
+  // initialize solution data with default arguments
+  void Ng_InitSolutionData (Ng_SolutionData * soldata);
+  // set solution data
+  void Ng_SetSolutionData (Ng_SolutionData * soldata);
+  */
+}
+
+
+
+}
diff --git a/contrib/Netgen/libsrc/interface/nginterface.cpp b/contrib/Netgen/libsrc/interface/nginterface.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..400a7a19eb9c5ad4b610659db2d7b749d91b9496
--- /dev/null
+++ b/contrib/Netgen/libsrc/interface/nginterface.cpp
@@ -0,0 +1,2412 @@
+#include <mystdlib.h>
+
+
+#include <meshing.hpp>
+#include <csg.hpp>
+#include <geometry2d.hpp>
+#include <stlgeom.hpp>
+
+
+#ifdef OCCGEOMETRY
+#include <occgeom.hpp>
+#endif
+
+#ifdef ACIS
+#include <acisgeom.hpp>
+#endif
+
+#ifdef SOCKETS
+#include "../sockets/sockets.hpp"
+#endif
+
+#ifndef NOTCL
+#include <visual.hpp>
+#endif
+
+
+#include "nginterface.h"
+
+// #include <FlexLexer.h>
+
+
+// #include <mystdlib.h>
+
+
+namespace netgen
+{
+#include "writeuser.hpp"
+
+	extern AutoPtr<Mesh> mesh;
+#ifndef NOTCL
+  extern VisualSceneMesh vsmesh;
+  extern Tcl_Interp * tcl_interp;
+#endif
+
+  extern AutoPtr<SplineGeometry2d> geometry2d;
+  extern AutoPtr<CSGeometry> geometry;
+  extern STLGeometry * stlgeometry;
+
+#ifdef OCCGEOMETRY
+  extern OCCGeometry * occgeometry;
+#endif
+#ifdef ACIS
+  extern ACISGeometry * acisgeometry;
+#endif
+
+#ifdef OPENGL
+  extern VisualSceneSolution vssolution;
+#endif
+  extern CSGeometry * ParseCSG (istream & istr);
+
+#ifdef SOCKETS
+  extern AutoPtr<ClientSocket> clientsocket;
+  //extern ARRAY< AutoPtr < ServerInfo > > servers;
+  extern ARRAY< ServerInfo* > servers;
+#endif
+}
+
+
+using namespace netgen;
+
+/*
+  extern void * operator new (size_t s);
+  extern void * operator new [] (size_t s);
+  extern void operator delete (void * p);
+  extern void operator delete [] (void * p);
+*/
+
+// extern FlexLexer * lexer;
+
+
+
+void Ng_LoadGeometry (const char * filename)
+{
+
+  
+  if (printmessage_importance>0)
+    cout << "CALLED NG LOAD GEOMETRY" << endl; 
+  
+  geometry.Reset (new CSGeometry ());
+  geometry2d.Reset ();
+
+#ifdef OCCGEOMETRY
+  delete occgeometry;
+  occgeometry = 0;
+#endif
+#ifdef ACIS
+  delete acisgeometry;
+  acisgeometry = 0;
+#endif
+  
+  // he: if filename is empty, return
+  // can be used to reset geometry
+  if (strcmp(filename,"")==0) 
+    return;
+     
+  ifstream infile (filename);
+  
+  if ((strcmp (&filename[strlen(filename)-3], "geo") == 0) ||
+      (strcmp (&filename[strlen(filename)-3], "GEO") == 0) ||
+      (strcmp (&filename[strlen(filename)-3], "Geo") == 0))
+    {
+ 
+
+      geometry.Reset( netgen::ParseCSG(infile) );   
+
+      if (!geometry)
+	{
+	  geometry.Reset (new CSGeometry ());
+	  //throw NgException ("input file not found");
+	  cerr << "Error: input file \"" << filename << "\" not found" << endl;
+	}
+
+      geometry -> FindIdenticSurfaces(1e-6);
+
+#ifdef PARALLEL
+      int id, rc, ntasks;
+      MPI_Comm_size(MPI_COMM_WORLD, &ntasks);
+      MPI_Comm_rank(MPI_COMM_WORLD, &id);
+      if ( id > 0 )
+	{
+	  geometry->CalcTriangleApproximation ( geometry->BoundingBox(), 0.001, 20 );
+	  return;
+	}
+#endif
+
+      Box<3> box (geometry->BoundingBox());
+#ifdef NOTCL
+      double detail = 0.001;
+      double facets = 20;
+      geometry->CalcTriangleApproximation(box, detail, facets);
+      
+#else
+      double detail = atof (Tcl_GetVar (tcl_interp, "::geooptions.detail", 0));
+      double facets = atof (Tcl_GetVar (tcl_interp, "::geooptions.facets", 0));
+      
+      if (atoi (Tcl_GetVar (tcl_interp, "::geooptions.drawcsg", 0)))
+	geometry->CalcTriangleApproximation(box, detail, facets);
+#endif
+    }
+
+  else if (strcmp (&filename[strlen(filename)-4], "in2d") == 0)
+    {
+      geometry2d.Reset (new SplineGeometry2d());
+      geometry2d -> Load (filename);
+    }
+
+  else if ((strcmp (&filename[strlen(filename)-3], "stl") == 0) ||
+	   (strcmp (&filename[strlen(filename)-3], "STL") == 0) ||
+	   (strcmp (&filename[strlen(filename)-3], "Stl") == 0))
+    {
+      stlgeometry = STLGeometry :: Load (infile);
+      stlgeometry->edgesfound = 0;
+      Mesh meshdummy;
+      stlgeometry->Clear();
+      stlgeometry->BuildEdges();
+      stlgeometry->MakeAtlas(meshdummy);
+      stlgeometry->CalcFaceNums();
+      stlgeometry->AddFaceEdges();
+      stlgeometry->LinkEdges();
+    }
+
+#ifdef OCCGEOMETRY
+  else if ((strcmp (&filename[strlen(filename)-4], "iges") == 0) ||
+	   (strcmp (&filename[strlen(filename)-3], "igs") == 0) ||
+	   (strcmp (&filename[strlen(filename)-3], "IGS") == 0) ||
+	   (strcmp (&filename[strlen(filename)-4], "IGES") == 0))
+    {
+      PrintMessage (1, "Load IGES geometry file ", filename);
+      occgeometry = LoadOCC_IGES (filename);
+    }
+  else if ((strcmp (&filename[strlen(filename)-4], "step") == 0) ||
+	   (strcmp (&filename[strlen(filename)-3], "stp") == 0) ||
+	   (strcmp (&filename[strlen(filename)-3], "STP") == 0) ||
+	   (strcmp (&filename[strlen(filename)-4], "STEP") == 0))
+    {
+      PrintMessage (1, "Load STEP geometry file ", filename);
+      occgeometry = LoadOCC_STEP (filename);
+    }
+#endif
+
+#ifdef ACIS
+  else if (
+		  strcmp (&filename[strlen(filename)-3], "sat") == 0 ||
+		  ( strlen(filename) >= 7 && strcmp ( &filename[ strlen( filename)-7 ], "sat.tet" ) == 0 )
+		)
+    {
+      PrintMessage (1, "Load ACIS geometry file ", filename);
+      acisgeometry = LoadACIS_SAT (filename);
+    }
+#endif
+  else
+    {
+      //throw NgException("Unknown geometry extension");
+		cerr << "Error: Unknown geometry extension \"" << filename[strlen(filename)-3] << "\"" << endl;
+    }
+
+
+}                          
+
+
+void Ng_LoadMeshFromStream ( istream & input )
+{
+  mesh.Reset (new Mesh());
+  mesh -> Load(input);
+  if(input.good())
+    {
+      string auxstring;
+      input >> auxstring;
+      if(auxstring == "csgsurfaces")
+	{
+	  if (geometry)
+            {
+              geometry.Reset (new CSGeometry (""));
+            }
+	  if (stlgeometry)
+	    {
+	      delete stlgeometry;
+	      stlgeometry = NULL;
+	    }
+#ifdef OCCGEOMETRY
+	  if (occgeometry)
+	    {
+ 	      delete occgeometry;
+ 	      occgeometry = NULL;
+	    }
+#endif
+#ifdef ACIS
+	  if (acisgeometry)
+	    {
+ 	      delete acisgeometry;
+ 	      acisgeometry = NULL;
+	    }
+#endif
+ 	  geometry2d.Reset (0);
+	  
+ 	  geometry -> LoadSurfaces(input);
+	}
+    }
+ 
+}
+
+
+void Ng_LoadMesh (const char * filename)
+{
+  if ( (strlen (filename) > 4) &&
+       strcmp (filename + (strlen (filename)-4), ".vol") != 0 )
+    {
+      mesh.Reset (new Mesh());
+      ReadFile(*mesh,filename);
+
+      //mesh->SetGlobalH (mparam.maxh);
+      //mesh->CalcLocalH();
+      return;
+    }
+
+  ifstream infile(filename);
+  Ng_LoadMeshFromStream(infile);
+}
+
+void Ng_LoadMeshFromString (char * mesh_as_string)
+{
+  istringstream instream(mesh_as_string);
+  Ng_LoadMeshFromStream(instream);
+}
+  
+
+
+
+int Ng_GetDimension ()
+{
+  return (mesh) ? mesh->GetDimension() : -1;
+}
+
+int Ng_GetNP ()
+{
+  return (mesh) ? mesh->GetNP() : 0;
+}
+
+int Ng_GetNV ()
+{
+  return (mesh) ? mesh->GetNV() : 0;
+}
+
+int Ng_GetNE ()
+{
+  if(!mesh) return 0;
+  if (mesh->GetDimension() == 3)
+    return mesh->GetNE();
+  else
+    return mesh->GetNSE();
+}
+
+int Ng_GetNSE ()
+{
+  if(!mesh) return 0;
+  if (mesh->GetDimension() == 3)
+    return mesh->GetNSE();
+  else
+    return mesh->GetNSeg();
+}
+
+void Ng_GetPoint (int pi, double * p)
+{
+  if (pi < 1 || pi > mesh->GetNP())
+    {
+      if (printmessage_importance>0)
+        cout << "Ng_GetPoint: illegal point " << pi << endl;
+      return;
+    }
+
+  const Point3d & hp = mesh->Point (pi);
+  p[0] = hp.X();
+  p[1] = hp.Y();
+  if (mesh->GetDimension() == 3)
+    p[2] = hp.Z();
+}
+
+
+NG_ELEMENT_TYPE Ng_GetElement (int ei, int * epi, int * np)
+{
+  if (mesh->GetDimension() == 3)
+    {
+      int i;
+      const Element & el = mesh->VolumeElement (ei);
+      for (i = 0; i < el.GetNP(); i++)
+	epi[i] = el.PNum(i+1);
+      
+      if (np)
+	*np = el.GetNP();
+
+      if (el.GetType() == PRISM)
+	{
+	  // degenerated prism, (should be obsolete)
+	  const int map1[] = { 3, 2, 5, 6, 1 };
+	  const int map2[] = { 1, 3, 6, 4, 2 };
+	  const int map3[] = { 2, 1, 4, 5, 3 };
+	  
+	  const int * map = NULL;
+	  int deg1 = 0, deg2 = 0, deg3 = 0;
+	  //int deg = 0;
+	  if (el.PNum(1) == el.PNum(4)) { map = map1; deg1 = 1; }
+	  if (el.PNum(2) == el.PNum(5)) { map = map2; deg2 = 1; }
+	  if (el.PNum(3) == el.PNum(6)) { map = map3; deg3 = 1; }
+	  
+	  switch (deg1+deg2+deg3)
+	    {
+	      {
+	      case 1:
+                if (printmessage_importance>0)
+                  cout << "degenerated prism found, deg = 1" << endl;
+		for (i = 0; i < 5; i++)
+		  epi[i] = el.PNum (map[i]);
+		
+		if (np) *np = 5;
+		return NG_PYRAMID;
+		break;
+	      }
+	    case 2:
+	      {
+                if (printmessage_importance>0)
+                  cout << "degenerated prism found, deg = 2" << endl;
+		if (!deg1) epi[3] = el.PNum(4);
+		if (!deg2) epi[3] = el.PNum(5);
+		if (!deg3) epi[3] = el.PNum(6);
+		
+		if (np) *np = 4;
+		return NG_TET;
+		break;
+	      }
+	    default:
+	      ;
+	    }
+	  
+	}
+
+      return NG_ELEMENT_TYPE (el.GetType());
+    }
+  else
+    {
+      int i;
+      const Element2d & el = mesh->SurfaceElement (ei);
+      for (i = 0; i < el.GetNP(); i++)
+	epi[i] = el.PNum(i+1);      
+
+      if (np) *np = el.GetNP();
+      return NG_ELEMENT_TYPE (el.GetType());
+      /*
+      switch (el.GetNP())
+	{
+	case 3: return NG_TRIG; 
+	case 4: return NG_QUAD; 
+	case 6: return NG_TRIG6; 
+	}
+      */
+    }
+
+  // should not occur
+  return NG_TET;
+}
+
+
+NG_ELEMENT_TYPE Ng_GetElementType (int ei)
+{
+  if (mesh->GetDimension() == 3)
+    {
+      return NG_ELEMENT_TYPE (mesh->VolumeElement (ei).GetType());
+    }
+  else
+    {
+      const Element2d & el = mesh->SurfaceElement (ei);
+      switch (el.GetNP())
+	{
+	case 3: return NG_TRIG; 
+	case 4: return NG_QUAD; 
+	case 6: return NG_TRIG6; 
+	}
+    }
+
+  // should not occur
+  return NG_TET;
+}
+
+
+
+int Ng_GetElementIndex (int ei)
+{
+  if (mesh->GetDimension() == 3)
+    return mesh->VolumeElement(ei).GetIndex();
+  else
+    {
+      int ind = mesh->SurfaceElement(ei).GetIndex(); 
+      ind = mesh->GetFaceDescriptor(ind).BCProperty();
+      return ind;
+    }
+}
+
+void Ng_SetElementIndex(const int ei, const int index)
+{
+  mesh->VolumeElement(ei).SetIndex(index);
+}
+
+char * Ng_GetElementMaterial (int ei)
+{
+  static char empty[] = "";
+  if (mesh->GetDimension() == 3)
+    {
+      int ind = mesh->VolumeElement(ei).GetIndex();
+      // cout << "ind = " << ind << endl;
+      const char * mat = mesh->GetMaterial (ind);
+      if (mat)
+	return const_cast<char*> (mat);
+      else 
+	return empty;
+    }
+  // add astrid
+  else
+    {
+      int ind = mesh->SurfaceElement(ei).GetIndex();
+      ind = mesh->GetFaceDescriptor(ind).BCProperty();
+      const char * mat = mesh->GetMaterial ( ind );
+      if (mat)
+	return const_cast<char*> (mat);
+      else
+	return empty;
+    }
+  return 0;
+}
+
+char * Ng_GetDomainMaterial (int dom)
+{
+  static char empty[] = "";
+  // astrid
+  if ( 1 ) // mesh->GetDimension() == 3)
+    {
+      const char * mat = mesh->GetMaterial(dom);
+      if (mat)
+	return const_cast<char*> (mat);
+      else 
+	return empty;      
+    }
+
+  return 0;
+}
+
+
+NG_ELEMENT_TYPE Ng_GetSurfaceElement (int ei, int * epi, int * np)
+{
+  if (mesh->GetDimension() == 3)
+    {
+      const Element2d & el = mesh->SurfaceElement (ei);
+      for (int i = 0; i < el.GetNP(); i++)
+	epi[i] = el[i];
+      
+      if (np) *np = el.GetNP();
+      
+      return NG_ELEMENT_TYPE (el.GetType());
+    }
+  else
+    {
+      const Segment & seg = mesh->LineSegment (ei);
+
+      if (seg.pmid < 0)
+	{
+	  epi[0] = seg.p1;
+	  epi[1] = seg.p2;
+	  
+	  if (np) *np = 2;
+	  return NG_SEGM;
+	}
+      else
+	{
+	  epi[0] = seg.p1;
+	  epi[1] = seg.p2;
+	  epi[2] = seg.pmid;
+
+	  if (np) *np = 3;
+	  return NG_SEGM3;
+	}
+    }
+
+  return NG_TRIG;
+}
+
+int Ng_GetSurfaceElementIndex (int ei)
+{
+  if (mesh->GetDimension() == 3)
+    return mesh->GetFaceDescriptor(mesh->SurfaceElement(ei).GetIndex()).BCProperty();
+  else
+    return mesh->LineSegment(ei).si;
+}
+
+int Ng_GetSurfaceElementSurfaceNumber (int ei)
+{
+  if (mesh->GetDimension() == 3)
+    return mesh->GetFaceDescriptor(mesh->SurfaceElement(ei).GetIndex()).SurfNr();
+  else
+    return mesh->LineSegment(ei).si;
+}
+int Ng_GetSurfaceElementFDNumber (int ei)
+{
+  if (mesh->GetDimension() == 3)
+    return mesh->SurfaceElement(ei).GetIndex();
+  else
+    return -1;
+}
+
+
+char * Ng_GetSurfaceElementBCName (int ei)
+{
+  if ( mesh->GetDimension() == 3 )
+    return const_cast<char *>(mesh->GetFaceDescriptor(mesh->SurfaceElement(ei).GetIndex()).GetBCName().c_str());
+  else
+    return const_cast<char *>(mesh->LineSegment(ei).GetBCName().c_str());
+}
+
+
+// Inefficient (but maybe safer) version:
+//void Ng_GetSurfaceElementBCName (int ei, char * name)
+//{
+//  if ( mesh->GetDimension() == 3 )
+//      strcpy(name,mesh->GetFaceDescriptor(mesh->SurfaceElement(ei).GetIndex()).GetBCName().c_str());
+//  else
+//      strcpy(name,mesh->LineSegment(ei).GetBCName().c_str());
+//}
+
+char * Ng_GetBCNumBCName (int bcnr)
+{
+  return const_cast<char *>(mesh->GetBCName(bcnr).c_str());
+}
+
+
+// Inefficient (but maybe safer) version:
+//void Ng_GetBCNumBCName (int bcnr, char * name)
+//{
+//    strcpy(name,mesh->GetBCName(bcnr).c_str());
+//}
+
+void Ng_GetNormalVector (int sei, int locpi, double * nv)
+{
+  nv[0] = 0; 
+  nv[1] = 0;
+  nv[2] = 1;
+
+  (*testout) << "Ng_GetNormalVector (sei = " << sei << ", locpi = " << locpi << ")" << endl;
+  
+  if (mesh->GetDimension() == 3)
+    {
+      Vec<3> n;
+      Point<3> p;
+      p = mesh->Point (mesh->SurfaceElement(sei).PNum(locpi));
+
+      int surfi = mesh->GetFaceDescriptor(mesh->SurfaceElement(sei).GetIndex()).SurfNr();
+
+      (*testout) << "surfi = " << surfi << endl;
+#ifdef OCCGEOMETRY
+      if (occgeometry)
+	{
+	  PointGeomInfo gi = mesh->SurfaceElement(sei).GeomInfoPi(locpi);
+	  occgeometry->GetSurface (surfi).GetNormalVector(p, gi, n);
+	  nv[0] = n(0);
+	  nv[1] = n(1);
+	  nv[2] = n(2);
+	}
+      else
+#endif
+      if (geometry)
+	{
+	  (*testout) << "geometry defined" << endl;
+	  n = geometry->GetSurface (surfi) -> GetNormalVector(p);
+	  (*testout) << "aus is" << endl;
+	  nv[0] = n(0);
+	  nv[1] = n(1);
+	  nv[2] = n(2);
+	}
+    }
+}
+
+
+
+void Ng_SetPointSearchStartElement(const int el)
+{
+  mesh->SetPointSearchStartElement(el);
+}
+
+
+int Ng_FindElementOfPoint (double * p, double * lami, int build_searchtree, 
+			   const int * const indices, const int numind)
+  
+{
+  ARRAY<int> * dummy(NULL);
+  int ind = -1;
+
+  if(indices != NULL)
+    {
+      dummy = new ARRAY<int>(numind);
+      for(int i=0; i<numind; i++) (*dummy)[i] = indices[i];
+    }
+
+  if (mesh->GetDimension() == 3)
+    {
+      Point3d p3d(p[0], p[1], p[2]);
+      ind = 
+	mesh->GetElementOfPoint(p3d, lami, dummy, build_searchtree != 0);
+    }
+  else
+    {
+      double lam3[3];
+      Point3d p2d(p[0], p[1], 0);
+      ind = 
+	mesh->GetElementOfPoint(p2d, lam3, dummy, build_searchtree != 0);
+      
+
+      if(mesh->SurfaceElement(ind).GetType()==QUAD)
+	{
+	  lami[0] = lam3[0];
+	  lami[1] = lam3[1];
+	}
+      else 
+	{
+	  lami[0] = 1-lam3[0]-lam3[1];
+	  lami[1] = lam3[0];
+	}
+    }
+
+  delete dummy;
+
+  return ind;
+}
+
+int Ng_FindSurfaceElementOfPoint (double * p, double * lami, int build_searchtree, 
+				  const int * const indices, const int numind)
+  
+{
+  ARRAY<int> * dummy(NULL);
+  int ind = -1;
+
+  if(indices != NULL)
+    {
+      dummy = new ARRAY<int>(numind);
+      for(int i=0; i<numind; i++) (*dummy)[i] = indices[i];
+    }
+
+  if (mesh->GetDimension() == 3)
+    {
+      Point3d p3d(p[0], p[1], p[2]);
+      ind = 
+	mesh->GetSurfaceElementOfPoint(p3d, lami, dummy, build_searchtree != 0);
+    }
+  else
+    {
+      //throw NgException("FindSurfaceElementOfPoint for 2D meshes not yet implemented");
+		cerr << "FindSurfaceElementOfPoint for 2D meshes not yet implemented" << endl;
+    }
+
+  delete dummy;
+
+  return ind;
+}
+
+
+int Ng_IsElementCurved (int ei)
+{
+  if (mesh->GetDimension() == 2)
+    return mesh->GetCurvedElements().IsSurfaceElementCurved (ei-1);
+  else
+    return mesh->GetCurvedElements().IsElementCurved (ei-1);
+}
+
+
+int Ng_IsSurfaceElementCurved (int sei)
+{
+  if (mesh->GetDimension() == 2)
+    return mesh->GetCurvedElements().IsSegmentCurved (sei-1);
+  else
+    return mesh->GetCurvedElements().IsSurfaceElementCurved (sei-1);
+}
+
+
+
+
+void Ng_GetElementTransformation (int ei, const double * xi, 
+				  double * x, double * dxdxi)
+{
+  if (mesh->GetDimension() == 2)
+    {
+      Point<2> xl(xi[0], xi[1]);
+      Point<3> xg;
+      Mat<3,2> dx;
+
+      mesh->GetCurvedElements().CalcSurfaceTransformation (xl, ei-1, xg, dx);
+
+      if (x)
+	{
+	  for (int i = 0; i < 2; i++)
+	    x[i] = xg(i);
+	}
+	  
+      if (dxdxi)
+	{
+	  for (int i=0; i<2; i++)
+	    {
+	      dxdxi[2*i] = dx(i,0);
+	      dxdxi[2*i+1] = dx(i,1);
+	    }
+	}
+    }
+  else
+    {
+      Point<3> xl(xi[0], xi[1], xi[2]);
+      Point<3> xg;
+      Mat<3,3> dx;
+
+      mesh->GetCurvedElements().CalcElementTransformation (xl, ei-1, xg, dx);
+
+      // still 1-based arrays
+      if (x)
+	{
+	  for (int i = 0; i < 3; i++)
+	    x[i] = xg(i);
+	}
+
+      if (dxdxi)
+	{
+	  for (int i=0; i<3; i++)
+	    {
+	      dxdxi[3*i] = dx(i,0);
+	      dxdxi[3*i+1] = dx(i,1);
+              dxdxi[3*i+2] = dx(i,2);
+	    }
+	}
+    }
+}
+
+
+
+void Ng_GetBufferedElementTransformation (int ei, const double * xi, 
+                                          double * x, double * dxdxi,
+                                          void * buffer, int buffervalid)
+{
+  // buffer = 0;
+  // buffervalid = 0;
+  if (mesh->GetDimension() == 2)
+    {
+      return Ng_GetElementTransformation (ei, xi, x, dxdxi);
+    }
+  else
+    {
+      mesh->GetCurvedElements().CalcElementTransformation (reinterpret_cast<const Point<3> &> (*xi), 
+                                                           ei-1, 
+                                                           reinterpret_cast<Point<3> &> (*x), 
+                                                           reinterpret_cast<Mat<3,3> &> (*dxdxi), 
+                                                           buffer, (buffervalid != 0));
+
+      /*
+      Point<3> xl(xi[0], xi[1], xi[2]);
+      Point<3> xg;
+      Mat<3,3> dx;
+      // buffervalid = 0;
+      mesh->GetCurvedElements().CalcElementTransformation (xl, ei-1, xg, dx, buffer, buffervalid);
+
+      // still 1-based arrays
+      if (x)
+	{
+	  for (int i = 0; i < 3; i++)
+	    x[i] = xg(i);
+	}
+
+      if (dxdxi)
+	{
+	  for (int i=0; i<3; i++)
+	    {
+	      dxdxi[3*i] = dx(i,0);
+	      dxdxi[3*i+1] = dx(i,1);
+              dxdxi[3*i+2] = dx(i,2);
+	    }
+	}
+      */
+    }
+}
+
+
+
+
+
+
+
+
+void Ng_GetMultiElementTransformation (int ei, int n,
+                                       const double * xi, int sxi,
+                                       double * x, int sx,
+                                       double * dxdxi, int sdxdxi)
+{
+  if (mesh->GetDimension() == 2)
+    {
+      for (int i = 0; i < n; i++)
+        {
+          Point<2> xl(xi[i*sxi], xi[i*sxi+1]);
+          Point<3> xg;
+          Mat<3,2> dx;
+
+          mesh->GetCurvedElements().CalcSurfaceTransformation (xl, ei-1, xg, dx);
+
+          if (x)
+            {
+              x[i*sx  ] = xg(0);
+              x[i*sx+1] = xg(1);
+            }
+	  
+          if (dxdxi)
+            {
+              dxdxi[i*sdxdxi  ] = dx(0,0);
+              dxdxi[i*sdxdxi+1] = dx(0,1);
+              dxdxi[i*sdxdxi+2] = dx(1,0);
+              dxdxi[i*sdxdxi+3] = dx(1,1);
+            }
+        }
+    }
+  else
+    {
+      mesh->GetCurvedElements().CalcMultiPointElementTransformation (ei-1, n, xi, sxi, x, sx, dxdxi, sdxdxi);
+    }
+}
+
+
+
+
+
+
+
+
+void Ng_GetSurfaceElementTransformation (int sei, const double * xi, 
+					 double * x, double * dxdxi)
+{
+  if (mesh->GetDimension() == 2)
+    {
+      Point<3> xg;
+      Vec<3> dx;
+
+      mesh->GetCurvedElements().CalcSegmentTransformation (xi[0], sei-1, xg, dx);
+
+      if (x)
+        for (int i = 0; i < 2; i++)
+	  x[i] = xg(i);
+	  
+      if (dxdxi)
+        for (int i=0; i<2; i++)
+	  dxdxi[i] = dx(i);
+
+    }
+  else
+    {
+      Point<2> xl(xi[0], xi[1]);
+      Point<3> xg;
+      Mat<3,2> dx;
+      
+      mesh->GetCurvedElements().CalcSurfaceTransformation (xl, sei-1, xg, dx);
+      
+      for (int i=0; i<3; i++)
+	{
+	  if (x)
+	    x[i] = xg(i);
+	  if (dxdxi)
+	    {
+	      dxdxi[2*i] = dx(i,0);
+	      dxdxi[2*i+1] = dx(i,1);
+	    }
+	}
+    }
+}
+
+
+
+void Ng_GetSurfaceElementNeighbouringDomains(const int selnr, int & in, int & out)
+{
+  if ( mesh->GetDimension() == 3 )
+    {
+      in = mesh->GetFaceDescriptor(mesh->SurfaceElement(selnr).GetIndex()).DomainIn();
+      out = mesh->GetFaceDescriptor(mesh->SurfaceElement(selnr).GetIndex()).DomainOut();
+    }
+  else
+    {
+      in = mesh -> LineSegment(selnr) . domin;
+      out = mesh -> LineSegment(selnr) . domout;
+    }
+}
+
+
+#ifdef PARALLEL
+// Is Element ei an element of this processor ??
+bool Ng_IsGhostEl (int ei)
+{
+  if ( mesh->GetDimension() == 3 )
+    return mesh->VolumeElement(ei).IsGhost();
+  else
+    return false;
+}
+
+void Ng_SetGhostEl(const int ei, const bool aisghost )
+{
+  if ( mesh -> GetDimension () == 3 )
+    mesh -> VolumeElement(ei).SetGhost (aisghost);
+}
+
+bool Ng_IsGhostSEl (int ei)
+{
+  if ( mesh -> GetDimension () == 3 )
+    return mesh->SurfaceElement(ei).IsGhost();
+  else
+    return false;
+}
+
+void Ng_SetGhostSEl(const int ei, const bool aisghost )
+{
+  if ( mesh -> GetDimension () == 3 )
+    mesh -> SurfaceElement(ei).SetGhost (aisghost);
+}
+
+
+bool Ng_IsGhostVert ( int pnum )
+{
+  return mesh -> Point ( pnum ).IsGhost() ;  
+}
+bool Ng_IsGhostEdge ( int ednum )
+{
+  return mesh -> GetParallelTopology() . IsGhostEdge ( ednum ); 
+}
+
+bool Ng_IsGhostFace ( int fanum )
+{
+  return mesh -> GetParallelTopology() . IsGhostFace ( fanum ); 
+}
+
+// void Ng_SetGhostVert ( const int pnum, const bool aisghost );
+// void Ng_SetGhostEdge ( const int ednum, const bool aisghost );
+// void Ng_SetGhostFace ( const int fanum, const bool aisghost );
+
+
+bool Ng_IsExchangeEl ( int elnum )
+{ return mesh -> GetParallelTopology() . IsExchangeElement ( elnum ); }
+
+bool Ng_IsExchangeSEl ( int selnum )
+{ return mesh -> GetParallelTopology() . IsExchangeSEl ( selnum ); }
+
+void Ng_UpdateOverlap()
+{ mesh->UpdateOverlap(); }
+
+int Ng_Overlap ()
+{ return mesh->GetParallelTopology() . Overlap(); }
+
+#endif
+
+void Ng_SetRefinementFlag (int ei, int flag)
+{
+  if (mesh->GetDimension() == 3)
+    {
+      mesh->VolumeElement(ei).SetRefinementFlag (flag != 0);
+      mesh->VolumeElement(ei).SetStrongRefinementFlag (flag >= 10);
+    }
+  else
+    {
+      mesh->SurfaceElement(ei).SetRefinementFlag (flag != 0);
+      mesh->SurfaceElement(ei).SetStrongRefinementFlag (flag >= 10);
+    }
+}
+
+void Ng_SetSurfaceRefinementFlag (int ei, int flag)
+{
+  if (mesh->GetDimension() == 3)
+    {
+      mesh->SurfaceElement(ei).SetRefinementFlag (flag != 0);
+      mesh->SurfaceElement(ei).SetStrongRefinementFlag (flag >= 10);
+    }
+}
+
+
+void Ng_Refine (NG_REFINEMENT_TYPE reftype)
+{
+  NgLock meshlock (mesh->MajorMutex(), 1);
+
+  BisectionOptions biopt;
+  biopt.usemarkedelements = 1;
+  biopt.refine_p = 0;
+  biopt.refine_hp = 0;
+  if (reftype == NG_REFINE_P)
+    biopt.refine_p = 1;
+  if (reftype == NG_REFINE_HP)
+    biopt.refine_hp = 1;
+  Refinement * ref;
+  MeshOptimize2d * opt = NULL;
+
+  if (geometry2d)
+    ref = new Refinement2d(*geometry2d);
+  else if (stlgeometry)
+    ref = new RefinementSTLGeometry(*stlgeometry);
+#ifdef OCCGEOMETRY
+  else if (occgeometry)
+    ref = new OCCRefinementSurfaces (*occgeometry);
+#endif
+#ifdef ACIS
+  else if (acisgeometry)
+    {
+      ref = new ACISRefinementSurfaces (*acisgeometry);
+      opt = new ACISMeshOptimize2dSurfaces(*acisgeometry);
+      ref->Set2dOptimizer(opt);
+    }
+#endif
+  else if (geometry && mesh->GetDimension() == 3)
+    {
+      ref = new RefinementSurfaces(*geometry);
+      opt = new MeshOptimize2dSurfaces(*geometry);
+      ref->Set2dOptimizer(opt);
+    }
+  else
+    {
+      ref = new Refinement();
+    }
+
+
+  ref -> Bisect (*mesh, biopt);
+
+  mesh -> UpdateTopology();
+
+  // mesh -> GetCurvedElements().BuildCurvedElements (ref, mparam.elementorder);
+  delete ref;
+  delete opt;
+}
+
+void Ng_SecondOrder ()
+{
+  if (stlgeometry)
+    {
+      RefinementSTLGeometry ref (*stlgeometry);
+      ref.MakeSecondOrder (*mesh);
+    }
+
+  else if (geometry2d)
+    {
+      Refinement2d ref (*geometry2d);
+      ref.MakeSecondOrder (*mesh);
+    }
+
+  else if (geometry && mesh->GetDimension() == 3)
+
+    {
+      RefinementSurfaces ref (*geometry);
+      ref.MakeSecondOrder (*mesh);
+    }
+  else
+    {
+      if (printmessage_importance>0)
+        cout << "no geom" << endl;
+      Refinement ref;
+      ref.MakeSecondOrder (*mesh);
+    }
+
+  mesh -> UpdateTopology();
+}
+
+/*
+void Ng_HPRefinement (int levels)
+{
+  Refinement * ref;
+
+  if (stlgeometry)
+    ref = new RefinementSTLGeometry (*stlgeometry);
+  else if (geometry2d)
+    ref = new Refinement2d (*geometry2d);
+  else
+    ref = new RefinementSurfaces (*geometry);
+
+
+  HPRefinement (*mesh, ref, levels);
+}
+
+void Ng_HPRefinement (int levels, double parameter)
+{
+  Refinement * ref;
+
+  if (stlgeometry)
+    ref = new RefinementSTLGeometry (*stlgeometry);
+  else if (geometry2d)
+    ref = new Refinement2d (*geometry2d);
+  else
+    ref = new RefinementSurfaces (*geometry);
+
+
+  HPRefinement (*mesh, ref, levels, parameter);
+}
+*/
+
+void Ng_HPRefinement (int levels, double parameter, bool setorders,
+                      bool ref_level)
+{
+  Refinement * ref;
+
+  if (stlgeometry)
+    ref = new RefinementSTLGeometry (*stlgeometry);
+  else if (geometry2d)
+    ref = new Refinement2d (*geometry2d);
+  else
+    ref = new RefinementSurfaces (*geometry);
+
+
+  HPRefinement (*mesh, ref, levels, parameter, setorders, ref_level);
+}
+
+
+void Ng_HighOrder (int order, bool rational)
+{
+  NgLock meshlock (mesh->MajorMutex(), true);
+
+  Refinement * ref;
+
+  if (stlgeometry)
+    ref = new RefinementSTLGeometry (*stlgeometry);
+#ifdef OCCGEOMETRY
+  else if (occgeometry)
+    ref = new OCCRefinementSurfaces (*occgeometry);
+#endif
+#ifdef ACIS
+  else if (acisgeometry)
+    {
+      ref = new ACISRefinementSurfaces (*acisgeometry);
+    }
+#endif
+  else if (geometry2d)
+    ref = new Refinement2d (*geometry2d);
+  else
+    {
+       ref = new RefinementSurfaces (*geometry);
+    }
+ 
+  // cout << "parameter 1: " << argv[1] << " (conversion to int = " << atoi(argv[1]) << ")" << endl;
+ 
+
+  mesh -> GetCurvedElements().BuildCurvedElements (ref, order, rational);
+
+
+  /*
+  if(mesh)
+    mesh -> GetCurvedElements().BuildCurvedElements (ref, order, rational);
+  */
+
+  delete ref;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+int Ng_ME_GetNVertices (NG_ELEMENT_TYPE et)
+{
+  switch (et)
+    {
+    case NG_SEGM:
+    case NG_SEGM3:
+      return 2;
+
+    case NG_TRIG:
+    case NG_TRIG6:
+      return 3;
+
+    case NG_QUAD:
+      return 4;
+
+    case NG_TET:
+    case NG_TET10:
+      return 4;
+
+    case NG_PYRAMID:
+      return 5;
+
+    case NG_PRISM:
+   case NG_PRISM12:
+      return 6;
+
+    case NG_HEX:
+      return 8;
+
+    default:
+      cerr << "Ng_ME_GetNVertices, illegal element type " << et << endl;
+    }
+  return 0;
+}
+
+int Ng_ME_GetNEdges (NG_ELEMENT_TYPE et)
+{
+  switch (et)
+    {
+    case NG_SEGM:
+    case NG_SEGM3:
+      return 1;
+
+    case NG_TRIG:
+    case NG_TRIG6:
+      return 3;
+
+    case NG_QUAD:
+      return 4;
+
+    case NG_TET:
+    case NG_TET10:
+      return 6;
+
+    case NG_PYRAMID:
+      return 8;
+
+    case NG_PRISM:
+    case NG_PRISM12:
+      return 9;
+
+    case NG_HEX:
+      return 12;
+
+    default:
+      cerr << "Ng_ME_GetNEdges, illegal element type " << et << endl;
+    }
+  return 0;
+}
+
+
+int Ng_ME_GetNFaces (NG_ELEMENT_TYPE et)
+{
+  switch (et)
+    {
+    case NG_SEGM:
+    case NG_SEGM3:
+      return 0;
+
+    case NG_TRIG:
+    case NG_TRIG6:
+      return 1;
+
+    case NG_QUAD:
+    case NG_QUAD6:
+      return 1;
+
+    case NG_TET:
+    case NG_TET10:
+      return 4;
+
+    case NG_PYRAMID:
+      return 5;
+
+    case NG_PRISM:
+    case NG_PRISM12:
+      return 5;
+
+    case NG_HEX:
+      return 6;
+
+    default:
+      cerr << "Ng_ME_GetNVertices, illegal element type " << et << endl;
+    }
+  return 0;
+}
+
+
+const NG_POINT * Ng_ME_GetVertices (NG_ELEMENT_TYPE et)
+{
+  static double segm_points [][3] = 
+    { { 1, 0, 0 },
+      { 0, 0, 0 } };
+
+  static double trig_points [][3] = 
+    { { 1, 0, 0 },
+      { 0, 1, 0 },
+      { 0, 0, 0 } };
+
+  static double quad_points [][3] = 
+    { { 0, 0, 0 },
+      { 1, 0, 0 },
+      { 1, 1, 0 },
+      { 0, 1, 0 } };
+
+  static double tet_points [][3] = 
+    { { 1, 0, 0 },
+      { 0, 1, 0 },
+      { 0, 0, 1 },
+      { 0, 0, 0 } };
+
+  static double pyramid_points [][3] =
+    {
+      { 0, 0, 0 },
+      { 1, 0, 0 },
+      { 1, 1, 0 },
+      { 0, 1, 0 },
+      { 0, 0, 1-1e-7 },
+    };    
+  
+  static double prism_points[][3] = 
+    {
+      { 1, 0, 0 },
+      { 0, 1, 0 },
+      { 0, 0, 0 },
+      { 1, 0, 1 },
+      { 0, 1, 1 },
+      { 0, 0, 1 }
+    };
+
+  switch (et)
+    {
+    case NG_SEGM:
+    case NG_SEGM3:
+      return segm_points;
+
+    case NG_TRIG:
+    case NG_TRIG6:
+      return trig_points;
+
+    case NG_QUAD:
+    case NG_QUAD6:
+      return quad_points;
+
+    case NG_TET:
+    case NG_TET10:
+      return tet_points;
+
+    case NG_PYRAMID:
+      return pyramid_points;
+
+    case NG_PRISM:
+    case NG_PRISM12:
+      return prism_points;
+
+    case NG_HEX:
+    default:
+      cerr << "Ng_ME_GetVertices, illegal element type " << et << endl;
+    }
+  return 0;
+}
+
+
+
+const NG_EDGE * Ng_ME_GetEdges (NG_ELEMENT_TYPE et)
+{
+  static int segm_edges[1][2] =
+    { { 1, 2 }};
+
+  static int trig_edges[3][2] =
+    { { 3, 1 },
+      { 3, 2 },
+      { 1, 2 }};
+
+  static int quad_edges[4][2] =
+    { { 1, 2 },
+      { 4, 3 },
+      { 1, 4 },
+      { 2, 3 }};
+
+
+  static int tet_edges[6][2] =
+    { { 4, 1 },
+      { 4, 2 },
+      { 4, 3 }, 
+      { 1, 2 },
+      { 1, 3 },
+      { 2, 3 }};
+
+  static int prism_edges[9][2] =
+    { { 3, 1 },
+      { 1, 2 },
+      { 3, 2 },
+      { 6, 4 },
+      { 4, 5 },
+      { 6, 5 },
+      { 3, 6 },
+      { 1, 4 },
+      { 2, 5 }};
+
+  static int pyramid_edges[8][2] =
+    { { 1, 2 },
+      { 2, 3 },
+      { 1, 4 },
+      { 4, 3 },
+      { 1, 5 },
+      { 2, 5 },
+      { 3, 5 },
+      { 4, 5 }};
+
+
+
+  switch (et)
+    {
+    case NG_SEGM:
+    case NG_SEGM3:
+      return segm_edges;
+
+    case NG_TRIG:
+    case NG_TRIG6:
+      return trig_edges;
+
+    case NG_QUAD:
+    case NG_QUAD6:
+      return quad_edges;
+
+    case NG_TET:
+    case NG_TET10:
+      return tet_edges;
+
+    case NG_PYRAMID:
+      return pyramid_edges;
+
+    case NG_PRISM:
+    case NG_PRISM12:
+      return prism_edges;
+
+    case NG_HEX:
+    default:
+      cerr << "Ng_ME_GetEdges, illegal element type " << et << endl;
+    }
+  return 0;  
+}
+
+
+const NG_FACE * Ng_ME_GetFaces (NG_ELEMENT_TYPE et)
+{
+  static int tet_faces[4][4] =
+    { { 4, 2, 3, 0 },
+      { 4, 1, 3, 0 },
+      { 4, 1, 2, 0 },
+      { 1, 2, 3, 0 } };
+  
+  static int prism_faces[5][4] =
+    {
+      { 1, 2, 3, 0 },
+      { 4, 5, 6, 0 },
+      { 3, 1, 4, 6 },
+      { 1, 2, 5, 4 },
+      { 2, 3, 6, 5 } 
+    };
+  
+  static int pyramid_faces[5][4] =
+    {
+      { 1, 2, 5, 0 },
+      { 2, 3, 5, 0 },
+      { 3, 4, 5, 0 },
+      { 4, 1, 5, 0 },
+      { 1, 2, 3, 4 } 
+    };
+  
+  static int trig_faces[1][4] = 
+    {
+      { 1, 2, 3, 0 },
+    };
+
+  switch (et)
+    {
+    case NG_TET:
+    case NG_TET10:
+      return tet_faces;
+
+    case NG_PRISM:
+    case NG_PRISM12:
+      return prism_faces;
+
+    case NG_PYRAMID:
+      return pyramid_faces;
+
+
+    case NG_SEGM:
+    case NG_SEGM3:
+
+    case NG_TRIG:
+    case NG_TRIG6:
+      return trig_faces;
+    case NG_QUAD:
+
+
+    case NG_HEX:
+
+    default:
+      cerr << "Ng_ME_GetFaces, illegal element type " << et << endl;
+    }
+  return 0;
+}
+
+
+int Ng_GetNEdges()
+{
+  return mesh->GetTopology().GetNEdges();
+}
+int Ng_GetNFaces()
+{
+  return mesh->GetTopology().GetNFaces();
+}
+
+
+
+int Ng_GetElement_Edges (int elnr, int * edges, int * orient)
+{
+  const MeshTopology & topology = mesh->GetTopology();
+  if (mesh->GetDimension() == 3)
+    return topology.GetElementEdges (elnr, edges, orient);
+  else
+    return topology.GetSurfaceElementEdges (elnr, edges, orient);
+}
+
+int Ng_GetElement_Faces (int elnr, int * faces, int * orient)
+{
+  const MeshTopology & topology = mesh->GetTopology();
+  if (mesh->GetDimension() == 3)
+    return topology.GetElementFaces (elnr, faces, orient);
+  else
+    {
+      faces[0] = elnr;
+      if (orient) orient[0] = 0;
+      return 1;
+    }
+}
+
+int Ng_GetSurfaceElement_Edges (int elnr, int * edges, int * orient)
+{
+  const MeshTopology & topology = mesh->GetTopology();
+  if (mesh->GetDimension() == 3)
+    return topology.GetSurfaceElementEdges (elnr, edges, orient);
+  else
+    {
+      if (orient)
+	topology.GetSegmentEdge(elnr, edges[0], orient[0]);
+      else
+	edges[0] = topology.GetSegmentEdge(elnr);
+    }
+  return 1;
+  /*
+    int i, ned;
+    const MeshTopology & topology = mesh->GetTopology();
+    ARRAY<int> ia;
+    topology.GetSurfaceElementEdges (elnr, ia);
+    ned = ia.Size();
+    for (i = 1; i <= ned; i++)
+    edges[i-1] = ia.Get(i);
+
+    if (orient)
+    {
+    topology.GetSurfaceElementEdgeOrientations (elnr, ia);
+    for (i = 1; i <= ned; i++)
+    orient[i-1] = ia.Get(i);
+    }
+    return ned;
+  */
+}
+
+int Ng_GetSurfaceElement_Face (int selnr, int * orient)
+{
+  if (mesh->GetDimension() == 3)
+    {
+      const MeshTopology & topology = mesh->GetTopology();
+      if (orient)
+	*orient = topology.GetSurfaceElementFaceOrientation (selnr);
+      return topology.GetSurfaceElementFace (selnr);
+    }
+  return -1;
+}
+
+int Ng_GetFace_Vertices (int fnr, int * vert)
+{
+  const MeshTopology & topology = mesh->GetTopology();
+  ArrayMem<int,4> ia;
+  topology.GetFaceVertices (fnr, ia);
+  for (int i = 0; i < ia.Size(); i++)
+    vert[i] = ia[i];
+  //  cout << "face verts = " << ia << endl;
+  return ia.Size();
+}
+
+
+int Ng_GetFace_Edges (int fnr, int * edge)
+{
+  const MeshTopology & topology = mesh->GetTopology();
+  ArrayMem<int,4> ia;
+  topology.GetFaceEdges (fnr, ia);
+  for (int i = 0; i < ia.Size(); i++)
+    edge[i] = ia[i];
+  return ia.Size();
+}
+
+void Ng_GetEdge_Vertices (int ednr, int * vert)
+{
+  const MeshTopology & topology = mesh->GetTopology();
+  topology.GetEdgeVertices (ednr, vert[0], vert[1]);
+}
+
+
+int Ng_GetNVertexElements (int vnr)
+{
+  if (mesh->GetDimension() == 3)
+    return mesh->GetTopology().GetVertexElements(vnr).Size();
+  else
+    return mesh->GetTopology().GetVertexSurfaceElements(vnr).Size();
+}
+
+void Ng_GetVertexElements (int vnr, int * els)
+{
+  FlatArray<int> ia(0,0);
+  if (mesh->GetDimension() == 3)
+    ia = mesh->GetTopology().GetVertexElements(vnr);
+  else
+    ia = mesh->GetTopology().GetVertexSurfaceElements(vnr);
+  for (int i = 0; i < ia.Size(); i++)
+    els[i] = ia[i];
+}
+
+
+int Ng_GetElementOrder (int enr)
+{
+  if (mesh->GetDimension() == 3)
+    return mesh->VolumeElement(enr).GetOrder();
+  else
+    return mesh->SurfaceElement(enr).GetOrder();
+}
+
+void Ng_GetElementOrders (int enr, int * ox, int * oy, int * oz)
+{
+  if (mesh->GetDimension() == 3)
+    mesh->VolumeElement(enr).GetOrder(*ox, *oy, *oz);
+  else
+    mesh->SurfaceElement(enr).GetOrder(*ox, *oy, *oz);
+}
+
+void Ng_SetElementOrder (int enr, int order)
+{
+  if (mesh->GetDimension() == 3)
+    return mesh->VolumeElement(enr).SetOrder(order);
+  else
+    return mesh->SurfaceElement(enr).SetOrder(order);
+}
+
+void Ng_SetElementOrders (int enr, int ox, int oy, int oz)
+{
+  if (mesh->GetDimension() == 3)
+    mesh->VolumeElement(enr).SetOrder(ox, oy, oz);
+  else
+    mesh->SurfaceElement(enr).SetOrder(ox, oy);
+}
+
+
+int Ng_GetSurfaceElementOrder (int enr)
+{
+  return mesh->SurfaceElement(enr).GetOrder();
+}
+
+//HERBERT: falsche Anzahl von Argumenten
+//void Ng_GetSurfaceElementOrders (int enr, int * ox, int * oy, int * oz)
+void Ng_GetSurfaceElementOrders (int enr, int * ox, int * oy)
+{
+  int d; 
+  mesh->SurfaceElement(enr).GetOrder(*ox, *oy, d);
+}
+
+void Ng_SetSurfaceElementOrder (int enr, int order)
+{
+  return mesh->SurfaceElement(enr).SetOrder(order);
+}
+
+void Ng_SetSurfaceElementOrders (int enr, int ox, int oy)
+{
+  mesh->SurfaceElement(enr).SetOrder(ox, oy);
+}
+
+
+int Ng_GetNLevels ()
+{
+  return (mesh) ? mesh->mglevels : 0;
+}
+
+
+void Ng_GetParentNodes (int ni, int * parents)
+{
+  if (ni <= mesh->mlbetweennodes.Size())
+    {
+      parents[0] = mesh->mlbetweennodes.Get(ni).I1();
+      parents[1] = mesh->mlbetweennodes.Get(ni).I2();
+    }
+  else
+    parents[0] = parents[1] = 0;
+}
+
+
+int Ng_GetParentElement (int ei)
+{
+  if (mesh->GetDimension() == 3)
+    {
+      if (ei <= mesh->mlparentelement.Size())
+	return mesh->mlparentelement.Get(ei);
+    }
+  else
+    {
+      if (ei <= mesh->mlparentsurfaceelement.Size())
+	return mesh->mlparentsurfaceelement.Get(ei);
+    }
+  return 0;
+}
+
+
+int Ng_GetParentSElement (int ei)
+{
+  if (mesh->GetDimension() == 3)
+    {
+      if (ei <= mesh->mlparentsurfaceelement.Size())
+	return mesh->mlparentsurfaceelement.Get(ei);
+    }
+  else
+    {
+      return 0;
+    }
+  return 0;
+}
+
+
+
+
+
+int Ng_GetClusterRepVertex (int pi)
+{
+  return mesh->GetClusters().GetVertexRepresentant(pi);
+}
+
+int Ng_GetClusterRepEdge (int pi)
+{
+  return mesh->GetClusters().GetEdgeRepresentant(pi);
+}
+
+int Ng_GetClusterRepFace (int pi)
+{
+  return mesh->GetClusters().GetFaceRepresentant(pi);
+}
+
+int Ng_GetClusterRepElement (int pi)
+{
+  return mesh->GetClusters().GetElementRepresentant(pi);
+}
+
+
+
+
+
+
+void Ng_InitSolutionData (Ng_SolutionData * soldata)
+{
+  soldata -> name = NULL;
+  soldata -> data = NULL;
+  soldata -> components = 1;
+  soldata -> dist = 1;
+  soldata -> order = 1;
+  soldata -> iscomplex = 0;
+  soldata -> draw_surface = 1;
+  soldata -> draw_volume = 1;
+  soldata -> soltype = NG_SOLUTION_NODAL;
+  soldata -> solclass = 0;
+}
+
+void Ng_SetSolutionData (Ng_SolutionData * soldata)
+{
+#ifdef OPENGL
+  //   vssolution.ClearSolutionData ();
+  VisualSceneSolution::SolData * vss = new VisualSceneSolution::SolData;
+
+  //  cout << "Add solution " << soldata->name << ", type = " << soldata->soltype << endl;
+
+  vss->name = new char[strlen (soldata->name)+1];
+  strcpy (vss->name, soldata->name);
+
+  vss->data = soldata->data;
+  vss->components = soldata->components;
+  vss->dist = soldata->dist;
+  vss->order = soldata->order;
+  vss->iscomplex = bool(soldata->iscomplex);
+  vss->draw_surface = soldata->draw_surface;
+  vss->draw_volume = soldata->draw_volume;
+  vss->soltype = VisualSceneSolution::SolType (soldata->soltype);
+  vss->solclass = soldata->solclass;
+  vssolution.AddSolutionData (vss);
+#endif
+}
+
+void Ng_ClearSolutionData ()
+{
+#ifdef OPENGL
+  vssolution.ClearSolutionData();
+#endif
+}
+
+
+
+void Ng_Redraw ()
+{
+#ifdef OPENGL
+  extern bool nodisplay; // he: global in ngappinit.cpp
+  if (!nodisplay)
+  {
+    vssolution.UpdateSolutionTimeStamp();
+    Render();
+  }
+#endif
+}
+
+
+void Ng_SetVisualizationParameter (const char * name, const char * value)
+{
+#ifdef OPENGL
+#ifndef NOTCL
+  char buf[100];
+  sprintf (buf, "visoptions.%s", name);
+  if (printmessage_importance>0)
+  {
+    cout << "name = " << name << ", value = " << value << endl;
+    cout << "set tcl-variable " << buf << " to " << value << endl;
+  }
+  Tcl_SetVar (tcl_interp, buf, const_cast<char*> (value), 0);
+  Tcl_Eval (tcl_interp, "Ng_Vis_Set parameters;");
+#endif
+#endif
+}
+
+
+
+
+int firsttime = 1;
+int animcnt = 0;
+void PlayAnimFile(const char* name, int speed, int maxcnt)
+{
+  //extern Mesh * mesh;
+
+  /*
+  if (mesh.Ptr()) mesh->DeleteMesh();
+  if (!mesh.Ptr()) mesh = new Mesh();
+  */
+  mesh.Reset (new Mesh());
+
+  int ne, np, i;
+
+  char str[80];
+  char str2[80];
+
+  //int tend = 5000;
+  //  for (ti = 1; ti <= tend; ti++)
+  //{
+  int rti = (animcnt%(maxcnt-1)) + 1;
+  animcnt+=speed;
+  
+  sprintf(str2,"%05i.sol",rti);
+  strcpy(str,"mbssol/");
+  strcat(str,name);
+  strcat(str,str2);
+
+  if (printmessage_importance>0)
+    cout << "read file '" << str << "'" << endl;
+  
+  ifstream infile(str);
+  infile >> ne;
+  for (i = 1; i <= ne; i++)
+    {
+      int j;
+      Element2d tri(TRIG);
+      tri.SetIndex(1); //faceind
+      
+      for (j = 1; j <= 3; j++)
+	infile >> tri.PNum(j);
+
+      infile >> np;
+      for (i = 1; i <= np; i++)
+	{
+	  Point3d p;
+	  infile >> p.X() >> p.Y() >> p.Z();
+	  if (firsttime)
+	    mesh->AddPoint (p);
+	  else
+	    mesh->Point(i) = Point<3> (p);
+	}
+
+      //firsttime = 0;
+      Ng_Redraw();
+   }
+}
+
+		
+int Ng_GetNPeriodicVertices (int idnr)
+{
+  ARRAY<INDEX_2> apairs;
+  mesh->GetIdentifications().GetPairs (idnr, apairs);
+  return apairs.Size();
+}
+
+
+// pairs should be an integer array of 2*npairs
+void Ng_GetPeriodicVertices (int idnr, int * pairs)
+{
+  ARRAY<INDEX_2> apairs;
+  mesh->GetIdentifications().GetPairs (idnr, apairs);
+  for (int i = 0; i < apairs.Size(); i++)
+    {
+      pairs[2*i] = apairs[i].I1();
+      pairs[2*i+1] = apairs[i].I2();
+    }
+      
+}
+
+
+
+int Ng_GetNPeriodicEdges (int idnr)
+{
+  ARRAY<INDEX,PointIndex::BASE> map;
+  //const MeshTopology & top = mesh->GetTopology();
+  int nse = mesh->GetNSeg();
+
+  int cnt = 0;
+  //  for (int id = 1; id <= mesh->GetIdentifications().GetMaxNr(); id++)
+    {
+      mesh->GetIdentifications().GetMap(idnr, map);
+      //(*testout) << "ident-map " << id << ":" << endl << map << endl;
+
+      for (SegmentIndex si = 0; si < nse; si++)
+	{
+	  PointIndex other1 = map[(*mesh)[si].p1];
+	  PointIndex other2 = map[(*mesh)[si].p2];
+	  //  (*testout) << "seg = " << (*mesh)[si] << "; other = " 
+	  //     << other1 << "-" << other2 << endl;
+	  if (other1 && other2 && mesh->IsSegment (other1, other2))
+	    {
+	      cnt++;
+	    }
+	}
+    }
+  return cnt;
+}
+
+void Ng_GetPeriodicEdges (int idnr, int * pairs)
+{
+  ARRAY<INDEX,PointIndex::BASE> map;
+  const MeshTopology & top = mesh->GetTopology();
+  int nse = mesh->GetNSeg();
+
+  int cnt = 0;
+  //  for (int id = 1; id <= mesh->GetIdentifications().GetMaxNr(); id++)
+    {
+      mesh->GetIdentifications().GetMap(idnr, map);
+      
+      //(*testout) << "map = " << map << endl;
+
+      for (SegmentIndex si = 0; si < nse; si++)
+	{
+	  PointIndex other1 = map[(*mesh)[si].p1];
+	  PointIndex other2 = map[(*mesh)[si].p2];
+	  if (other1 && other2 && mesh->IsSegment (other1, other2))
+	    {
+	      SegmentIndex otherseg = mesh->SegmentNr (other1, other2);
+	      pairs[cnt++] = top.GetSegmentEdge (si+1);
+	      pairs[cnt++] = top.GetSegmentEdge (otherseg+1);
+	    }
+	}
+    }
+}
+
+
+
+void Ng_PushStatus (const char * str)
+{
+  PushStatus (MyStr (str));
+}
+
+void Ng_PopStatus ()
+{
+  PopStatus ();
+}
+
+void Ng_SetThreadPercentage (double percent)
+{
+  SetThreadPercent (percent);
+}
+
+void Ng_GetStatus (char ** str, double & percent)
+{
+  MyStr s;
+  GetStatus(s,percent);
+  *str = new char[s.Length()+1];
+  strcpy(*str,s.c_str());  
+}
+
+
+void Ng_SetTerminate(void)
+{
+  multithread.terminate = 1;
+}
+void Ng_UnSetTerminate(void)
+{
+  multithread.terminate = 0;
+}
+
+int Ng_ShouldTerminate(void)
+{
+  return multithread.terminate;
+}
+
+///// Added by Roman Stainko ....
+int Ng_GetVertex_Elements( int vnr, int* elems )
+{
+  const MeshTopology& topology = mesh->GetTopology();
+  ArrayMem<int,4> indexArray;
+  topology.GetVertexElements( vnr, indexArray );
+  
+  for( int i=0; i<indexArray.Size(); i++ )
+    elems[i] = indexArray[i];
+  
+  return indexArray.Size();
+}
+
+///// Added by Roman Stainko ....
+int Ng_GetVertex_SurfaceElements( int vnr, int* elems )
+{
+  const MeshTopology& topology = mesh->GetTopology();
+  ArrayMem<int,4> indexArray;
+  topology.GetVertexSurfaceElements( vnr, indexArray );
+  
+  for( int i=0; i<indexArray.Size(); i++ )
+    elems[i] = indexArray[i];
+  
+  return indexArray.Size();
+}
+
+///// Added by Roman Stainko ....
+int Ng_GetVertex_NElements( int vnr )
+{
+  const MeshTopology& topology = mesh->GetTopology();
+  ArrayMem<int,4> indexArray;
+  topology.GetVertexElements( vnr, indexArray );
+  
+  return indexArray.Size();
+}
+
+///// Added by Roman Stainko ....
+int Ng_GetVertex_NSurfaceElements( int vnr )
+{
+  const MeshTopology& topology = mesh->GetTopology();
+  ArrayMem<int,4> indexArray;
+  topology.GetVertexSurfaceElements( vnr, indexArray );
+
+  return indexArray.Size();
+}
+
+
+
+#ifdef SOCKETS
+int Ng_SocketClientOpen( const int port, const char * host )
+{
+  try
+    {
+      if(host)
+	clientsocket.Reset(new ClientSocket(port,host));
+      else
+	clientsocket.Reset(new ClientSocket(port));
+    }
+  catch( SocketException e)
+    {
+      cerr << e.Description() << endl;
+      return 0;
+    }
+  return 1;
+}
+ 
+void Ng_SocketClientWrite( const char * write, char** reply)
+{
+  string output = write;
+  (*clientsocket) << output;
+  string sreply;
+  (*clientsocket) >> sreply;
+  *reply = new char[sreply.size()+1];
+  strcpy(*reply,sreply.c_str());
+}
+
+
+void Ng_SocketClientClose ( void )
+{
+  clientsocket.Reset(NULL);
+}
+
+
+void Ng_SocketClientGetServerHost ( const int number, char ** host )
+{
+  *host = new char[servers[number]->host.size()+1];
+  strcpy(*host,servers[number]->host.c_str());
+}
+
+void Ng_SocketClientGetServerPort ( const int number, int * port )
+{
+  *port = servers[number]->port;
+}
+
+void Ng_SocketClientGetServerClientID ( const int number, int * id )
+{
+  *id = servers[number]->clientid;
+}
+
+#endif // SOCKETS
+
+
+
+
+#ifdef PARALLEL
+void Ng_SetElementPartition ( const int elnr, const int part )
+{
+  mesh->VolumeElement(elnr+1).SetPartition(part);
+
+}
+int Ng_GetElementPartition ( const int elnr )
+{
+  return mesh->VolumeElement(elnr+1).GetPartition();
+}
+#endif
+
+
+void Ng_InitPointCurve(double red, double green, double blue)
+{
+  mesh->InitPointCurve(red, green, blue);
+}
+
+void Ng_AddPointCurvePoint(const double * point)
+{
+  Point3d pt;
+  pt.X() = point[0];
+  pt.Y() = point[1];
+  pt.Z() = point[2];
+  mesh->AddPointCurvePoint(pt);
+}
+
+
+void Ng_SaveMesh ( const char * meshfile )
+{
+  mesh -> Save(string(meshfile));
+}
+
+
+int Ng_Bisect_WithInfo ( const char * refinementfile, double ** qualityloss, int * qualityloss_size )
+{
+  BisectionOptions biopt;
+  biopt.outfilename = NULL; // "ngfepp.vol";
+  biopt.femcode = "fepp";
+  biopt.refinementfilename = refinementfile;
+  
+  Refinement * ref;
+  MeshOptimize2d * opt = NULL;
+  if (stlgeometry)
+    ref = new RefinementSTLGeometry(*stlgeometry);
+#ifdef OCCGEOMETRY
+  else if (occgeometry)
+    ref = new OCCRefinementSurfaces (*occgeometry);
+#endif
+#ifdef ACIS
+  else if (acisgeometry)
+    {
+      ref = new ACISRefinementSurfaces(*acisgeometry);
+      opt = new ACISMeshOptimize2dSurfaces(*acisgeometry);
+      ref->Set2dOptimizer(opt);
+    }
+#endif
+  else
+    {
+      ref = new RefinementSurfaces(*geometry);
+      opt = new MeshOptimize2dSurfaces(*geometry);
+      ref->Set2dOptimizer(opt);
+    }
+  
+  if(!mesh->LocalHFunctionGenerated())
+    mesh->CalcLocalH();
+  
+  mesh->LocalHFunction().SetGrading (mparam.grading);
+
+  ARRAY<double> * qualityloss_arr = NULL;
+  if(qualityloss != NULL)
+    qualityloss_arr = new ARRAY<double>;
+
+  ref -> Bisect (*mesh, biopt, qualityloss_arr);
+
+  int retval = 0;
+
+  if(qualityloss != NULL)
+    {
+      *qualityloss = new double[qualityloss_arr->Size()+1];
+
+      for(int i = 0; i<qualityloss_arr->Size(); i++)
+	(*qualityloss)[i+1] = (*qualityloss_arr)[i];
+
+      retval = qualityloss_arr->Size();
+
+      delete qualityloss_arr;
+    }
+
+  mesh -> UpdateTopology();
+  mesh -> GetCurvedElements().BuildCurvedElements (ref, mparam.elementorder);
+  
+  multithread.running = 0;
+  delete ref;
+  delete opt;
+
+  return retval;
+}
+
+void Ng_Bisect ( const char * refinementfile )
+{
+  Ng_Bisect_WithInfo( refinementfile, NULL, NULL );
+}
+
+
+
+
+
+/*
+  number of nodes of type nt
+  nt = 0 is Vertex
+  nt = 1 is Edge
+  nt = 2 is Face
+  nt = 3 is Cell
+*/
+int Ng_GetNNodes (int nt)
+{
+  switch (nt)
+    {
+    case 0: return mesh -> GetNV();
+    case 1: return mesh->GetTopology().GetNEdges();
+    case 2: return mesh->GetTopology().GetNFaces();
+    case 3: return mesh -> GetNE();
+    }
+  return -1;
+}
+
+
+int Ng_GetClosureNodes (int nt, int nodenr, int nodeset, int * nodes)
+{
+  switch (nt)
+    {
+    case 3:  // The closure of a cell
+      {
+        int cnt = 0;
+        if (nodeset & 1)  // Vertices
+          {
+            const Element & el = (*mesh)[ElementIndex(nodenr)];
+            for (int i = 0; i < el.GetNP(); i++)
+              { 
+                nodes[cnt++] = 0;
+                nodes[cnt++] = el[i] - PointIndex::BASE;
+              }
+          }
+
+        if (nodeset & 2)  // Edges
+          {
+            int edges[12];
+            int ned;
+            ned = mesh->GetTopology().GetElementEdges (nodenr+1, edges, 0);
+            for (int i = 0; i < ned; i++)
+              {
+                nodes[cnt++] = 1;
+                nodes[cnt++] = edges[i]-1;
+              }
+          }
+
+        if (nodeset & 4)  // Faces
+          {
+            int faces[12];
+            int nfa;
+            nfa = mesh->GetTopology().GetElementFaces (nodenr+1, faces, 0);
+            for (int i = 0; i < nfa; i++)
+              {
+                nodes[cnt++] = 2;
+                nodes[cnt++] = faces[i]-1;
+              }
+          }
+
+        if (nodeset & 8)  // Cell
+          {
+            nodes[cnt++] = 3;
+            nodes[cnt++] = nodenr;
+          }
+
+        return cnt/2;
+      }
+    default:
+      {
+        cerr << "GetClosureNodes not implemented for Nodetype " << nt << endl;
+      }
+    }
+  return 0;
+}
+
+
+
+int Ng_GetNElements (int dim)
+{
+  switch (dim)
+    {
+    case 0: return mesh -> GetNV();
+    case 1: return mesh -> GetNSeg();
+    case 2: return mesh -> GetNSE();
+    case 3: return mesh -> GetNE();
+    }
+  return -1;
+}
+
+
+
+  /*
+    closure nodes of element
+    nodeset is bit-coded, bit 0 includes Vertices, bit 1 edges, etc
+    E.g., nodeset = 6 includes edge and face nodes
+    nodes is pair of integers (nodetype, nodenr) 
+    return value is number of nodes
+   */
+int Ng_GetElementClosureNodes (int dim, int elementnr, int nodeset, int * nodes)
+{
+  switch (dim)
+    {
+    case 3:  // The closure of a volume element = CELL
+      {
+        return Ng_GetClosureNodes (3, elementnr, nodeset, nodes);
+      }
+    case 2:
+      {
+        int cnt = 0;
+        if (nodeset & 1)  // Vertices
+          {
+            const Element2d & el = (*mesh)[SurfaceElementIndex(elementnr)];
+            for (int i = 0; i < el.GetNP(); i++)
+              { 
+                nodes[cnt++] = 0;
+                nodes[cnt++] = el[i] - PointIndex::BASE;
+              }
+          }
+
+        if (nodeset & 2)  // Edges
+          {
+            int edges[12];
+            int ned;
+            ned = mesh->GetTopology().GetSurfaceElementEdges (elementnr+1, edges, 0);
+            for (int i = 0; i < ned; i++)
+              {
+                nodes[cnt++] = 1;
+                nodes[cnt++] = edges[i]-1;
+              }
+          }
+
+        if (nodeset & 4)  // Faces
+          {
+            int face = mesh->GetTopology().GetSurfaceElementFace (elementnr+1);
+            nodes[cnt++] = 2;
+            nodes[cnt++] = face-1;
+          }
+
+        return cnt/2;
+      }
+    default:
+      {
+        cerr << "GetClosureNodes not implemented for Element of dimension " << dim << endl;
+      }
+    }
+  return 0;
+}
diff --git a/contrib/Netgen/libsrc/interface/nginterface.h b/contrib/Netgen/libsrc/interface/nginterface.h
new file mode 100644
index 0000000000000000000000000000000000000000..6301c23d822d6658f87892abb1218cec4e341fa4
--- /dev/null
+++ b/contrib/Netgen/libsrc/interface/nginterface.h
@@ -0,0 +1,422 @@
+#ifndef NGINTERFACE
+#define NGINTERFACE
+
+
+/**************************************************************************/
+/* File:   nginterface.h                                                  */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   20. Nov. 99                                                    */
+/**************************************************************************/
+
+/*
+  Application program interface to Netgen
+
+*/
+
+
+
+// max number of nodes per element
+#define NG_ELEMENT_MAXPOINTS 12
+
+// max number of nodes per surface element
+#define NG_SURFACE_ELEMENT_MAXPOINTS 8
+
+
+
+// implemented element types:
+enum NG_ELEMENT_TYPE { 
+  NG_SEGM = 1, NG_SEGM3 = 2,
+  NG_TRIG = 10, NG_QUAD=11, NG_TRIG6 = 12, NG_QUAD6 = 13,
+  NG_TET = 20, NG_TET10 = 21, 
+  NG_PYRAMID = 22, NG_PRISM = 23, NG_PRISM12 = 24,
+  NG_HEX = 25
+};
+
+typedef double NG_POINT[3];  // coordinates
+typedef int NG_EDGE[2];      // initial point, end point
+typedef int NG_FACE[4];      // points, last one is 0 for trig
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+  
+  // load geomtry from file 
+  void Ng_LoadGeometry (const char * filename);
+  
+  // load netgen mesh
+  void Ng_LoadMesh (const char * filename);
+
+  // load netgen mesh
+  void Ng_LoadMeshFromString (const char * mesh_as_string);
+
+  // space dimension (2 or 3)
+  int Ng_GetDimension ();
+
+  // number of mesh points
+  int Ng_GetNP ();
+  
+  // number of mesh vertices (differs from GetNP for 2nd order elements)
+  int Ng_GetNV ();
+  
+  // number of mesh elements
+  int Ng_GetNE ();
+  
+  // number of surface triangles
+  int Ng_GetNSE ();
+  
+  // Get Point coordintes, index from 1 .. np
+  void Ng_GetPoint (int pi, double * p);
+  
+  // Get Element Points
+  NG_ELEMENT_TYPE Ng_GetElement (int ei, int * epi, int * np = 0);
+
+  // Get Element Type
+  NG_ELEMENT_TYPE Ng_GetElementType (int ei);
+
+  // Get sub-domain of element ei
+  int Ng_GetElementIndex (int ei);
+
+  void Ng_SetElementIndex(const int ei, const int index);
+
+  // Get Material of element ei
+  char * Ng_GetElementMaterial (int ei);
+
+  // Get Material of domain dom
+  char * Ng_GetDomainMaterial (int dom);
+
+  // Get Surface Element Points
+  NG_ELEMENT_TYPE Ng_GetSurfaceElement (int ei, int * epi, int * np = 0);
+
+  // Get Surface Element Type
+  NG_ELEMENT_TYPE Ng_GetSurfaceElementType (int ei);
+
+  // Get Surface Element Index
+  int Ng_GetSurfaceElementIndex (int ei);
+
+  // Get Surface Element Surface Number
+  int Ng_GetSurfaceElementSurfaceNumber (int ei);
+  
+  // Get Surface Element Number
+  int Ng_GetSurfaceElementFDNumber (int ei);
+
+  // Get BCName for Surface Element  
+  char * Ng_GetSurfaceElementBCName (int ei);
+  //void Ng_GetSurfaceElementBCName (int ei, char * name);
+
+  // Get BCName for bc-number
+  char * Ng_GetBCNumBCName (int bcnr);
+  //void Ng_GetBCNumBCName (int bcnr, char * name);
+
+  // Get normal vector of surface element node
+  void Ng_GetNormalVector (int sei, int locpi, double * nv);     
+  
+
+  void Ng_SetPointSearchStartElement(int el);
+  
+  // Find element of point, returns local coordinates
+  int Ng_FindElementOfPoint (double * p, double * lami,
+			     int build_searchtrees = 0, 
+			     const int * const indices = NULL, const int numind = 0);
+  
+  // Find surface element of point, returns local coordinates
+  int Ng_FindSurfaceElementOfPoint (double * p, double * lami,
+				    int build_searchtrees = 0, 
+				    const int * const indices = NULL, const int numind = 0);
+  
+
+  // is elment ei curved ?
+  int Ng_IsElementCurved (int ei);
+  // is elment sei curved ?
+  int Ng_IsSurfaceElementCurved (int sei);
+
+  /// Curved Elemens:
+  /// xi..local coordinates
+  /// x ..global coordinates
+  /// dxdxi...D x D Jacobian matrix (row major storage)
+  void Ng_GetElementTransformation (int ei, const double * xi, 
+				    double * x, double * dxdxi);
+
+  
+  /// buffer must be at least 100 doubles, alignment of double
+  void Ng_GetBufferedElementTransformation (int ei, const double * xi, 
+                                            double * x, double * dxdxi,
+                                            void * buffer, int buffervalid);
+  
+
+
+  /// Curved Elemens:
+  /// xi..local coordinates
+  /// x ..global coordinates
+  /// dxdxi...D x D-1 Jacobian matrix (row major storage)
+  /// curved ...is element curved ?
+  void Ng_GetSurfaceElementTransformation (int sei, const double * xi, 
+                                           double * x, double * dxdxi);
+
+  /// Curved Elemens:
+  /// xi..local coordinates
+  /// sxi..step xi
+  /// x ..global coordinates
+  /// dxdxi...D x D Jacobian matrix (row major storage)
+  void Ng_GetMultiElementTransformation (int ei, int n,
+                                         const double * xi, int sxi,
+                                         double * x, int sx,
+                                         double * dxdxi, int sdxdxi);
+
+  
+  // Mark element for refinement
+  void Ng_SetRefinementFlag (int ei, int flag);
+  void Ng_SetSurfaceRefinementFlag (int sei, int flag);
+
+  // Do local refinement
+  enum NG_REFINEMENT_TYPE { NG_REFINE_H = 0, NG_REFINE_P = 1, NG_REFINE_HP = 2 };
+  void Ng_Refine (NG_REFINEMENT_TYPE reftype);
+
+  // Use second order elements
+  void Ng_SecondOrder ();
+  void Ng_HighOrder (int order, bool rational = false);
+  //void Ng_HPRefinement (int levels, double parameter = 0.125);
+  void Ng_HPRefinement (int levels, double parameter = 0.125,
+			bool setorders = true,bool ref_level = false);
+  // void Ng_HPRefinement (int levels);
+  // void Ng_HPRefinement (int levels, double parameter);
+
+
+  // Topology and coordinate information of master element:
+
+  int Ng_ME_GetNVertices (NG_ELEMENT_TYPE et);
+  int Ng_ME_GetNEdges (NG_ELEMENT_TYPE et);
+  int Ng_ME_GetNFaces (NG_ELEMENT_TYPE et);
+
+  const NG_POINT * Ng_ME_GetVertices (NG_ELEMENT_TYPE et);
+  const NG_EDGE * Ng_ME_GetEdges (NG_ELEMENT_TYPE et);
+  const NG_FACE * Ng_ME_GetFaces (NG_ELEMENT_TYPE et);
+
+  int Ng_GetNEdges();
+  int Ng_GetNFaces();
+
+  
+  int Ng_GetElement_Edges (int elnr, int * edges, int * orient = 0);
+  int Ng_GetElement_Faces (int elnr, int * faces, int * orient = 0);
+
+  int Ng_GetSurfaceElement_Edges (int selnr, int * edges, int * orient = 0);
+  int Ng_GetSurfaceElement_Face (int selnr, int * orient = 0);
+
+  void Ng_GetSurfaceElementNeighbouringDomains(const int selnr, int & in, int & out);
+       
+  int Ng_GetFace_Vertices (int fnr, int * vert);
+  void Ng_GetEdge_Vertices (int ednr, int * vert);
+  int Ng_GetFace_Edges (int fnr, int * edge);
+
+  int Ng_GetNVertexElements (int vnr);
+  void Ng_GetVertexElements (int vnr, int * els);
+
+  int Ng_GetElementOrder (int enr);
+  void Ng_GetElementOrders (int enr, int * ox, int * oy, int * oz);
+
+  void Ng_SetElementOrder (int enr, int order);
+  void Ng_SetElementOrders (int enr, int ox, int oy, int oz);
+
+  int Ng_GetSurfaceElementOrder (int enr);
+  void Ng_GetSurfaceElementOrders (int enr, int * ox, int * oy);
+
+  void Ng_SetSurfaceElementOrder (int enr, int order);
+  void Ng_SetSurfaceElementOrders (int enr, int ox, int oy);
+
+  // Multilevel functions:
+
+  // number of levels:
+  int Ng_GetNLevels ();
+  // get two parent nodes (indeed vertices !) of node ni
+  void Ng_GetParentNodes (int ni, int * parents);
+
+  // get parent element (first child has always same number)
+  int Ng_GetParentElement (int ei);
+
+  // get parent surface element (first child has always same number)
+  int Ng_GetParentSElement (int ei);
+
+  // representant of anisotropic cluster
+  int Ng_GetClusterRepVertex (int vi);
+  int Ng_GetClusterRepEdge (int edi);
+  int Ng_GetClusterRepFace (int fai);
+  int Ng_GetClusterRepElement (int eli);
+
+
+  void Ng_SurfaceElementTransformation (int eli, double x, double y, 
+					double * p3d, double * jacobian);
+
+#ifdef PARALLEL
+  // Is Element ei an element of this processor ??
+  bool Ng_IsGhostEl (int ei);
+
+  void Ng_SetGhostEl(const int ei, const bool aisghost );
+
+  bool Ng_IsGhostSEl (int ei);
+
+  void Ng_SetGhostSEl(const int ei, const bool aisghost );
+
+  bool Ng_IsGhostVert ( int pnum );
+  bool Ng_IsGhostEdge ( int ednum );
+  bool Ng_IsGhostFace ( int fanum );
+
+  bool Ng_IsExchangeEl ( int elnum );
+  bool Ng_IsExchangeSEl ( int selnr );
+
+  void Ng_UpdateOverlap ();
+  int Ng_Overlap();
+/*   void Ng_SetGhostVert ( const int pnum, const bool aisghost ); */
+/*   void Ng_SetGhostEdge ( const int ednum, const bool aisghost ); */
+/*   void Ng_SetGhostFace ( const int fanum, const bool aisghost ); */
+
+#endif
+  
+namespace netgen {
+#include "../visualization/soldata.hpp"
+}
+
+  enum Ng_SolutionType
+  { NG_SOLUTION_NODAL = 1, 
+    NG_SOLUTION_ELEMENT = 2, 
+    NG_SOLUTION_SURFACE_ELEMENT = 3, 
+    NG_SOLUTION_NONCONTINUOUS = 4,
+    NG_SOLUTION_SURFACE_NONCONTINUOUS = 5,
+    NG_SOLUTION_VIRTUAL_FUNCTION = 6,
+    NG_SOLUTION_MARKED_ELEMENTS = 10,
+    NG_SOLUTION_ELEMENT_ORDER = 11
+  };
+  
+  struct Ng_SolutionData
+  {
+    const char * name; // name of gridfunction
+    double * data;    // solution values
+    int components;   // relevant (double) components in solution vector
+    int dist;         // # doubles per entry alignment! 
+    int iscomplex;    // complex vector ? 
+    bool draw_surface;
+    bool draw_volume;
+    int order;        // order of elements, only partially supported 
+    Ng_SolutionType soltype;  // type of solution function
+    netgen::SolutionData * solclass;
+  };
+  
+  // initialize solution data with default arguments
+  void Ng_InitSolutionData (Ng_SolutionData * soldata);
+  // set solution data
+  void Ng_SetSolutionData (Ng_SolutionData * soldata);
+  /// delete gridfunctions
+  void Ng_ClearSolutionData();
+  // redraw 
+  void Ng_Redraw();
+  //
+  void Ng_SetVisualizationParameter (const char * name, 
+				     const char * value);
+
+
+  // number of periodic vertices  
+  int Ng_GetNPeriodicVertices (int idnr);
+  // pairs should be an integer array of 2*npairs
+  void Ng_GetPeriodicVertices (int idnr, int * pairs); 
+
+  // number of periodic edges  
+  int Ng_GetNPeriodicEdges (int idnr);
+  // pairs should be an integer array of 2*npairs
+  void Ng_GetPeriodicEdges (int idnr, int * pairs); 
+
+
+  void Ng_PushStatus (const char * str);
+  void Ng_PopStatus ();
+  void Ng_SetThreadPercentage (double percent);
+  void Ng_GetStatus (char ** str, double & percent);
+
+  void Ng_SetTerminate(void);
+  void Ng_UnSetTerminate(void);
+  int Ng_ShouldTerminate(void);
+  
+  
+  //// added by Roman Stainko ....
+  int Ng_GetVertex_Elements( int vnr, int* elems);
+  int Ng_GetVertex_SurfaceElements( int vnr, int* elems );
+  int Ng_GetVertex_NElements( int vnr );
+  int Ng_GetVertex_NSurfaceElements( int vnr );
+
+
+#ifdef SOCKETS
+  int Ng_SocketClientOpen( const int port, const char * host );
+  void Ng_SocketClientWrite( const char * write, char ** reply);
+  void Ng_SocketClientClose ( void );
+  void Ng_SocketClientGetServerHost ( const int number, char ** host );
+  void Ng_SocketClientGetServerPort ( const int number, int * port );
+  void Ng_SocketClientGetServerClientID ( const int number, int * id );
+#endif
+
+  void Ng_InitPointCurve(double red, double green, double blue);
+  void Ng_AddPointCurvePoint(const double * point);
+
+
+#ifdef PARALLEL
+  void Ng_SetElementPartition ( int elnr, int part );
+  int  Ng_GetElementPartition ( int elnr );
+#endif
+
+  void Ng_SaveMesh ( const char * meshfile );
+  void Ng_Bisect ( const char * refinementfile );
+
+  // if qualityloss is not equal to NULL at input, a (1-based) list of qualitylosses (due to projection)
+  // is saved in *qualityloss, its size is the return value
+  int Ng_Bisect_WithInfo ( const char * refinementfile, double ** qualityloss);
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+
+
+
+
+
+/*
+  The new node interface ...
+  it is 0-based !
+ */
+
+extern "C" {
+  
+  /*
+    number of nodes of type nt
+    nt = 0 is Vertex
+    nt = 1 is Edge
+    nt = 2 is Face
+    nt = 3 is Cell
+   */
+  int Ng_GetNNodes (int nt);
+
+  /*
+    closure nodes of node (nt, nodenr):
+    nodeset is bit-coded, bit 0 includes Vertices, bit 1 edges, etc
+    E.g., nodeset = 6 includes edge and face nodes
+    nodes consists of pairs of integers (nodetype, nodenr) 
+    return value is number of nodes
+   */
+  int Ng_GetClosureNodes (int nt, int nodenr, int nodeset, int * nodes);
+
+  
+  /*
+    number of dim-dimensional elements 
+    dim = 3 ... volume elements
+    dim = 2 ... surface elements
+    dim = 1 ... segments
+    dim = 0 ... not available
+  */
+  int Ng_GetNElements (int dim);
+
+  /*
+    closure nodes of dim-dimensional element elmentnr:
+    nodeset is bit-coded, bit 0 includes Vertices, bit 1 edges, etc
+    E.g., nodeset = 6 includes edge and face nodes
+    nodes consists of pairs of integers (nodetype, nodenr) 
+    return value is number of nodes
+   */
+  int Ng_GetElementClosureNodes (int dim, int elementnr, int nodeset, int * nodes);
+}
diff --git a/contrib/Netgen/libsrc/interface/nglib.cpp b/contrib/Netgen/libsrc/interface/nglib.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..861c62cd97f692521c5e8ec202a081c6b7ff5396
--- /dev/null
+++ b/contrib/Netgen/libsrc/interface/nglib.cpp
@@ -0,0 +1,602 @@
+/**************************************************************************/
+/* File:   nglib.cc                                                       */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   7. May. 2000                                                   */
+/**************************************************************************/
+
+/*
+  
+  Interface to the netgen meshing kernel
+  
+*/
+
+
+#include <mystdlib.h>
+#include <myadt.hpp>
+
+#include <linalg.hpp>
+
+// MODIFIED FOR GMSH
+//#include <csg.hpp>
+//#include <stlgeom.hpp>
+//#include <geometry2d.hpp>
+
+#include <meshing.hpp>
+
+
+
+// #include <FlexLexer.h>
+
+// MODIFIED FOR GMSH
+//namespace netgen {
+//  extern void MeshFromSpline2D (SplineGeometry2d & geometry,
+//				Mesh *& mesh, 
+//				MeshingParameters & mp);
+//}
+
+
+
+
+
+
+
+namespace nglib {
+#include "nglib.h"
+}
+
+using namespace netgen;
+
+// constants and types:
+
+namespace nglib
+{
+// initialize, deconstruct Netgen library:
+void Ng_Init ()
+{
+  mycout = &cout;
+  myerr = &cerr;
+  testout = new ofstream ("test.out");
+}
+
+void Ng_Exit ()
+{
+  ;
+}
+  
+
+
+Ng_Mesh * Ng_NewMesh ()
+{
+  Mesh * mesh = new Mesh;  
+  mesh->AddFaceDescriptor (FaceDescriptor (1, 1, 0, 1));
+  return (Ng_Mesh*)(void*)mesh;
+}
+
+void Ng_DeleteMesh (Ng_Mesh * mesh)
+{
+  delete (Mesh*)mesh;
+}
+
+
+// feeds points, surface elements and volume elements to the mesh
+void Ng_AddPoint (Ng_Mesh * mesh, double * x)
+{
+  Mesh * m = (Mesh*)mesh;
+  m->AddPoint (Point3d (x[0], x[1], x[2]));
+}
+  
+void Ng_AddSurfaceElement (Ng_Mesh * mesh, Ng_Surface_Element_Type et,
+			   int * pi)
+{
+  Mesh * m = (Mesh*)mesh;
+  Element2d el (3);
+  el.SetIndex (1);
+  el.PNum(1) = pi[0];
+  el.PNum(2) = pi[1];
+  el.PNum(3) = pi[2];
+  m->AddSurfaceElement (el);
+}
+
+void Ng_AddVolumeElement (Ng_Mesh * mesh, Ng_Volume_Element_Type et,
+			  int * pi)
+{
+  Mesh * m = (Mesh*)mesh;
+  Element el (4);
+  el.SetIndex (1);
+  el.PNum(1) = pi[0];
+  el.PNum(2) = pi[1];
+  el.PNum(3) = pi[2];
+  el.PNum(4) = pi[3];
+  m->AddVolumeElement (el);
+}
+
+// ask for number of points, surface and volume elements
+int Ng_GetNP (Ng_Mesh * mesh)
+{
+  return ((Mesh*)mesh) -> GetNP();
+}
+
+int Ng_GetNSE (Ng_Mesh * mesh)
+{
+  return ((Mesh*)mesh) -> GetNSE();
+}
+
+int Ng_GetNE (Ng_Mesh * mesh)
+{
+  return ((Mesh*)mesh) -> GetNE();
+}
+
+
+//  return point coordinates
+void Ng_GetPoint (Ng_Mesh * mesh, int num, double * x)
+{
+  const Point3d & p = ((Mesh*)mesh)->Point(num);
+  x[0] = p.X();
+  x[1] = p.Y();
+  x[2] = p.Z();
+}
+
+// return surface and volume element in pi
+Ng_Surface_Element_Type 
+Ng_GetSurfaceElement (Ng_Mesh * mesh, int num, int * pi)
+{
+  const Element2d & el = ((Mesh*)mesh)->SurfaceElement(num);
+  for (int i = 1; i <= el.GetNP(); i++)
+    pi[i-1] = el.PNum(i);
+  Ng_Surface_Element_Type et;
+  switch (el.GetNP())
+    {
+    case 3: et = NG_TRIG; break;
+    case 4: et = NG_QUAD; break;
+    case 6: et = NG_TRIG6; break;
+    }
+  return et;
+}
+
+Ng_Volume_Element_Type
+Ng_GetVolumeElement (Ng_Mesh * mesh, int num, int * pi)
+{
+  const Element & el = ((Mesh*)mesh)->VolumeElement(num);
+  for (int i = 1; i <= el.GetNP(); i++)
+    pi[i-1] = el.PNum(i);
+  Ng_Volume_Element_Type et;
+  switch (el.GetNP())
+    {
+    case 4: et = NG_TET; break;
+    case 5: et = NG_PYRAMID; break;
+    case 6: et = NG_PRISM; break;
+    case 10: et = NG_TET10; break;
+    }
+  return et;
+}
+
+void Ng_RestrictMeshSizeGlobal (Ng_Mesh * mesh, double h)
+{
+  ((Mesh*)mesh) -> SetGlobalH (h);
+}
+
+void Ng_RestrictMeshSizePoint (Ng_Mesh * mesh, double * p, double h)
+{
+  ((Mesh*)mesh) -> RestrictLocalH (Point3d (p[0], p[1], p[2]), h);
+}
+
+void Ng_RestrictMeshSizeBox (Ng_Mesh * mesh, double * pmin, double * pmax, double h)
+{
+  for (double x = pmin[0]; x < pmax[0]; x += h)
+    for (double y = pmin[1]; y < pmax[1]; y += h)
+      for (double z = pmin[2]; z < pmax[2]; z += h)
+        ((Mesh*)mesh) -> RestrictLocalH (Point3d (x, y, z), h);
+}
+
+
+// generates volume mesh from surface mesh
+Ng_Result Ng_GenerateVolumeMesh (Ng_Mesh * mesh, Ng_Meshing_Parameters * mp)
+{
+  Mesh * m = (Mesh*)mesh;
+  
+  
+  MeshingParameters mparam;
+  mparam.maxh = mp->maxh;
+  mparam.meshsizefilename = mp->meshsize_filename;
+
+  m->CalcLocalH();
+
+  MeshVolume (mparam, *m);
+  RemoveIllegalElements (*m);
+  OptimizeVolume (mparam, *m);
+
+  return NG_OK;
+}
+
+
+
+// 2D Meshing Functions:
+
+#if 0 // MODIFIED FOR GMSH
+
+void Ng_AddPoint_2D (Ng_Mesh * mesh, double * x)
+{
+  Mesh * m = (Mesh*)mesh;
+  
+  m->AddPoint (Point3d (x[0], x[1], 0));
+}
+
+void Ng_AddBoundarySeg_2D (Ng_Mesh * mesh, int pi1, int pi2)
+{
+  Mesh * m = (Mesh*)mesh;
+
+  Segment seg;
+  seg.p1 = pi1;
+  seg.p2 = pi2;
+  m->AddSegment (seg);
+}
+  
+
+int Ng_GetNP_2D (Ng_Mesh * mesh)
+{
+  Mesh * m = (Mesh*)mesh;
+  return m->GetNP();
+}
+
+int Ng_GetNE_2D (Ng_Mesh * mesh)
+{
+  Mesh * m = (Mesh*)mesh;
+  return m->GetNSE();
+}
+
+int Ng_GetNSeg_2D (Ng_Mesh * mesh)
+{
+  Mesh * m = (Mesh*)mesh;
+  return m->GetNSeg();
+}
+  
+void Ng_GetPoint_2D (Ng_Mesh * mesh, int num, double * x)
+{
+  Mesh * m = (Mesh*)mesh;
+
+  Point<3> & p = m->Point(num);
+  x[0] = p(0);
+  x[1] = p(1);
+}
+
+void Ng_GetElement_2D (Ng_Mesh * mesh, int num, int * pi, int * matnum)
+{
+  const Element2d & el = ((Mesh*)mesh)->SurfaceElement(num);
+  for (int i = 1; i <= 3; i++)
+    pi[i-1] = el.PNum(i);
+  if (matnum)
+    *matnum = el.GetIndex();
+}
+
+
+void Ng_GetSegment_2D (Ng_Mesh * mesh, int num, int * pi, int * matnum)
+{
+  const Segment & seg = ((Mesh*)mesh)->LineSegment(num);
+  pi[0] = seg.p1;
+  pi[1] = seg.p2;
+
+  if (matnum)
+    *matnum = seg.edgenr;
+}
+
+
+
+
+Ng_Geometry_2D * Ng_LoadGeometry_2D (const char * filename)
+{
+  SplineGeometry2d * geom = new SplineGeometry2d();
+  geom -> Load (filename);
+  return (Ng_Geometry_2D *)geom;
+}
+
+Ng_Result Ng_GenerateMesh_2D (Ng_Geometry_2D * geom,
+			      Ng_Mesh ** mesh,
+			      Ng_Meshing_Parameters * mp)
+{
+  // use global variable mparam
+  //  MeshingParameters mparam;  
+  mparam.maxh = mp->maxh;
+  mparam.meshsizefilename = mp->meshsize_filename;
+  mparam.quad = mp->quad_dominated;
+
+  Mesh * m;
+  MeshFromSpline2D (*(SplineGeometry2d*)geom, m, mparam);
+  
+  cout << m->GetNSE() << " elements, " << m->GetNP() << " points" << endl;
+  
+  *mesh = (Ng_Mesh*)m;
+  return NG_OK;
+}
+
+void Ng_HP_Refinement (Ng_Geometry_2D * geom,
+		       Ng_Mesh * mesh,
+		       int levels)
+{
+  Refinement2d ref(*(SplineGeometry2d*)geom);
+  HPRefinement (*(Mesh*)mesh, &ref, levels);
+}
+
+void Ng_HP_Refinement (Ng_Geometry_2D * geom,
+		       Ng_Mesh * mesh,
+		       int levels, double parameter)
+{
+  Refinement2d ref(*(SplineGeometry2d*)geom);
+  HPRefinement (*(Mesh*)mesh, &ref, levels, parameter);
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ARRAY<STLReadTriangle> readtrias; //only before initstlgeometry
+ARRAY<Point<3> > readedges; //only before init stlgeometry
+ 
+void Ng_SaveMesh(Ng_Mesh * mesh, const char* filename)
+{
+  ((Mesh*)mesh)->Save(filename);
+}
+
+Ng_Mesh * Ng_LoadMesh(const char* filename)
+{
+  Mesh * mesh = new Mesh;
+  mesh->Load(filename);
+  return ( (Ng_Mesh*)mesh );
+}
+
+// loads geometry from STL file
+Ng_STL_Geometry * Ng_STL_LoadGeometry (const char * filename, int binary)
+{
+  int i;
+  STLGeometry geom;
+  STLGeometry* geo;
+  ifstream ist(filename);
+
+  if (binary)
+    {
+      geo = geom.LoadBinary(ist);
+    }
+  else
+    {
+      geo = geom.Load(ist);
+    }
+
+  readtrias.SetSize(0);
+  readedges.SetSize(0);
+
+  Point3d p;
+  Vec3d normal;
+  double p1[3];
+  double p2[3];
+  double p3[3];
+  double n[3];
+
+  Ng_STL_Geometry * geo2 = Ng_STL_NewGeometry();
+
+  for (i = 1; i <= geo->GetNT(); i++)
+    {
+      const STLTriangle& t = geo->GetTriangle(i);
+      p = geo->GetPoint(t.PNum(1));
+      p1[0] = p.X(); p1[1] = p.Y(); p1[2] = p.Z(); 
+      p = geo->GetPoint(t.PNum(2));
+      p2[0] = p.X(); p2[1] = p.Y(); p2[2] = p.Z(); 
+      p = geo->GetPoint(t.PNum(3));
+      p3[0] = p.X(); p3[1] = p.Y(); p3[2] = p.Z();
+      normal = t.Normal();
+      n[0] = normal.X(); n[1] = normal.Y(); n[2] = normal.Z();
+      
+      Ng_STL_AddTriangle(geo2, p1, p2, p3, n);
+    }
+
+  return geo2;
+}
+
+// generate new STL Geometry
+Ng_STL_Geometry * Ng_STL_NewGeometry ()
+{
+  return (Ng_STL_Geometry*)(void*)new STLGeometry;
+} 
+
+// after adding triangles (and edges) initialize
+Ng_Result Ng_STL_InitSTLGeometry (Ng_STL_Geometry * geom)
+{
+  STLGeometry* geo = (STLGeometry*)geom;
+  geo->InitSTLGeometry(readtrias);
+  readtrias.SetSize(0);
+
+  if (readedges.Size() != 0)
+    {
+      int i;
+      /*
+      for (i = 1; i <= readedges.Size(); i+=2)
+	{
+	  cout << "e(" << readedges.Get(i) << "," << readedges.Get(i+1) << ")" << endl;
+	}
+      */
+      geo->AddEdges(readedges);
+    }
+
+  if (geo->GetStatus() == STLTopology::STL_GOOD || geo->GetStatus() == STLTopology::STL_WARNING) return NG_OK;
+  return NG_SURFACE_INPUT_ERROR;
+}
+
+  // automatically generates edges:
+Ng_Result Ng_STL_MakeEdges (Ng_STL_Geometry * geom,
+		       Ng_Mesh* mesh,
+		       Ng_Meshing_Parameters * mp)
+{
+  STLGeometry* stlgeometry = (STLGeometry*)geom;
+  Mesh* me = (Mesh*)mesh;
+  
+  MeshingParameters mparam;
+
+  mparam.maxh = mp->maxh;
+  mparam.meshsizefilename = mp->meshsize_filename;
+
+  me -> SetGlobalH (mparam.maxh);
+  me -> SetLocalH (stlgeometry->GetBoundingBox().PMin() - Vec3d(10, 10, 10),
+		   stlgeometry->GetBoundingBox().PMax() + Vec3d(10, 10, 10),
+		   0.3);
+
+  me -> LoadLocalMeshSize (mp->meshsize_filename);
+  /*
+  if (mp->meshsize_filename)
+    {
+      ifstream infile (mp->meshsize_filename);
+      if (!infile.good()) return NG_FILE_NOT_FOUND;
+      me -> LoadLocalMeshSize (infile);
+    }
+  */
+
+  STLMeshing (*stlgeometry, *me);
+  
+  stlgeometry->edgesfound = 1;
+  stlgeometry->surfacemeshed = 0;
+  stlgeometry->surfaceoptimized = 0;
+  stlgeometry->volumemeshed = 0;
+  
+  return NG_OK;
+}
+
+  
+// generates mesh, empty mesh be already created.
+Ng_Result Ng_STL_GenerateSurfaceMesh (Ng_STL_Geometry * geom,
+				      Ng_Mesh* mesh,
+				      Ng_Meshing_Parameters * mp)
+{
+  STLGeometry* stlgeometry = (STLGeometry*)geom;
+  Mesh* me = (Mesh*)mesh;
+
+  MeshingParameters mparam;
+
+  mparam.maxh = mp->maxh;
+  mparam.meshsizefilename = mp->meshsize_filename;
+
+  /*
+  me -> SetGlobalH (mparam.maxh);
+  me -> SetLocalH (stlgeometry->GetBoundingBox().PMin() - Vec3d(10, 10, 10),
+		   stlgeometry->GetBoundingBox().PMax() + Vec3d(10, 10, 10),
+		   0.3);
+  */
+  /*
+  STLMeshing (*stlgeometry, *me);
+  
+  stlgeometry->edgesfound = 1;
+  stlgeometry->surfacemeshed = 0;
+  stlgeometry->surfaceoptimized = 0;
+  stlgeometry->volumemeshed = 0;
+  */  
+  int retval = STLSurfaceMeshing (*stlgeometry, *me);
+  if (retval == MESHING3_OK)
+    {
+      (*mycout) << "Success !!!!" << endl;
+      stlgeometry->surfacemeshed = 1;
+      stlgeometry->surfaceoptimized = 0;
+      stlgeometry->volumemeshed = 0;
+    } 
+  else if (retval == MESHING3_OUTERSTEPSEXCEEDED)
+    {
+      (*mycout) << "ERROR: Give up because of too many trials. Meshing aborted!" << endl;
+    }
+  else if (retval == MESHING3_TERMINATE)
+    {
+      (*mycout) << "Meshing Stopped!" << endl;
+    }
+  else
+    {
+      (*mycout) << "ERROR: Surface meshing not successful. Meshing aborted!" << endl;
+    }
+
+
+  STLSurfaceOptimization (*stlgeometry, *me, mparam);
+
+  return NG_OK;
+}
+
+
+  // fills STL Geometry
+  // positive orientation
+  // normal vector may be null-pointer
+void Ng_STL_AddTriangle (Ng_STL_Geometry * geom, 
+			 double * p1, double * p2, double * p3, double * nv)
+{
+  Point<3> apts[3];
+  apts[0] = Point<3>(p1[0],p1[1],p1[2]);
+  apts[1] = Point<3>(p2[0],p2[1],p2[2]);
+  apts[2] = Point<3>(p3[0],p3[1],p3[2]);
+
+  Vec<3> n;
+  if (!nv)
+    n = Cross (apts[0]-apts[1], apts[0]-apts[2]);
+  else
+    n = Vec<3>(nv[0],nv[1],nv[2]);
+
+  readtrias.Append(STLReadTriangle(apts,n));
+}
+
+  // add (optional) edges:
+void Ng_STL_AddEdge (Ng_STL_Geometry * geom, 
+		     double * p1, double * p2)
+{
+  readedges.Append(Point3d(p1[0],p1[1],p1[2]));
+  readedges.Append(Point3d(p2[0],p2[1],p2[2]));
+}
+
+#endif // MODIFIED FOR GMSH
+
+Ng_Meshing_Parameters :: Ng_Meshing_Parameters()
+{
+  maxh = 1000;
+  fineness = 0.5;
+  secondorder = 0;
+  meshsize_filename = 0;
+  quad_dominated = 0;
+}
+
+
+}
+
+
+// compatibility functions:
+
+namespace netgen 
+{
+
+  char geomfilename[255];
+
+void MyError (const char * ch)
+{
+  cerr << ch;
+}
+
+//Destination for messages, errors, ...
+void Ng_PrintDest(const char * s)
+{
+  (*mycout) << s << flush;
+}
+
+double GetTime ()
+{
+  return 0;
+}
+
+void ResetTime ()
+{
+  ;
+}
+
+void MyBeep (int i)
+{
+  ;
+}
+
+}
diff --git a/contrib/Netgen/libsrc/interface/nglib.h b/contrib/Netgen/libsrc/interface/nglib.h
new file mode 100644
index 0000000000000000000000000000000000000000..8c6285f619e841fab47ecea858391ce096d6a332
--- /dev/null
+++ b/contrib/Netgen/libsrc/interface/nglib.h
@@ -0,0 +1,221 @@
+#ifndef NGLIB
+#define NGLIB
+
+/**************************************************************************/
+/* File:   nglib.hh                                                       */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   7. May. 2000                                                   */
+/**************************************************************************/
+
+/*
+  
+Interface to the netgen meshing kernel
+  
+*/
+
+/// Data type for NETGEN mesh
+typedef void * Ng_Mesh;
+
+/// Data type for NETGEN CSG geomty
+typedef void * Ng_CSG_Geometry;
+
+/// Data type for NETGEN 2D geomty
+typedef void * Ng_Geometry_2D;
+
+/// Data type for NETGEN STL geomty
+typedef void * Ng_STL_Geometry;
+
+
+
+// max number of nodes per element
+#define NG_VOLUME_ELEMENT_MAXPOINTS 10
+
+// implemented element types:
+enum Ng_Volume_Element_Type { NG_TET = 1, NG_PYRAMID = 2, NG_PRISM = 3,
+                              NG_TET10 = 4 };
+
+// max number of nodes per surface element
+#define NG_SURFACE_ELEMENT_MAXPOINTS 6
+
+// implemented element types:
+enum Ng_Surface_Element_Type { NG_TRIG = 1, NG_QUAD = 2, 
+			       NG_TRIG6 = 3 };
+
+
+
+class Ng_Meshing_Parameters 
+{
+ public:
+  
+  double maxh;
+  double fineness;   // 0 .. coarse, 1 .. fine
+  int secondorder;
+  char * meshsize_filename;
+  int quad_dominated;
+
+  Ng_Meshing_Parameters();
+};
+
+
+enum Ng_Result { NG_OK = 0, 
+		 NG_SURFACE_INPUT_ERROR = 1,
+		 NG_VOLUME_FAILURE = 2, 
+		 NG_STL_INPUT_ERROR = 3,
+		 NG_SURFACE_FAILURE = 4,
+		 NG_FILE_NOT_FOUND = 5 };
+
+
+
+
+  
+// initialize, deconstruct Netgen library:
+void Ng_Init ();
+void Ng_Exit ();
+  
+
+
+// Generates new mesh structure
+Ng_Mesh * Ng_NewMesh ();
+void Ng_DeleteMesh (Ng_Mesh * mesh);
+  
+// feeds points, surface elements and volume elements to the mesh
+void Ng_AddPoint (Ng_Mesh * mesh, double * x);
+void Ng_AddSurfaceElement (Ng_Mesh * mesh, Ng_Surface_Element_Type et,
+                           int * pi);
+void Ng_AddVolumeElement (Ng_Mesh * mesh, Ng_Volume_Element_Type et,
+                          int * pi);
+  
+// ask for number of points, surface and volume elements
+int Ng_GetNP (Ng_Mesh * mesh);
+int Ng_GetNSE (Ng_Mesh * mesh);
+int Ng_GetNE (Ng_Mesh * mesh);
+
+  
+//  return point coordinates
+void Ng_GetPoint (Ng_Mesh * mesh, int num, double * x);
+
+// return surface and volume element in pi
+Ng_Surface_Element_Type 
+Ng_GetSurfaceElement (Ng_Mesh * mesh, int num, int * pi);
+
+Ng_Volume_Element_Type
+Ng_GetVolumeElement (Ng_Mesh * mesh, int num, int * pi);
+
+
+// Defines MeshSize Functions
+void Ng_RestrictMeshSizeGlobal (Ng_Mesh * mesh, double h);
+void Ng_RestrictMeshSizePoint (Ng_Mesh * mesh, double * p, double h);
+void Ng_RestrictMeshSizeBox (Ng_Mesh * mesh, double * pmin, double * pmax, double h);
+  
+// generates volume mesh from surface mesh
+Ng_Result Ng_GenerateVolumeMesh (Ng_Mesh * mesh, Ng_Meshing_Parameters * mp);
+
+void Ng_SaveMesh(Ng_Mesh * mesh, const char* filename);
+Ng_Mesh * Ng_LoadMesh(const char* filename);
+
+
+
+
+
+// **********************************************************
+// **   2D Meshing                                         **
+// **********************************************************
+
+
+// feeds points and boundary to mesh
+
+void Ng_AddPoint_2D (Ng_Mesh * mesh, double * x);
+void Ng_AddBoundarySeg_2D (Ng_Mesh * mesh, int pi1, int pi2);
+  
+// ask for number of points, elements and boundary segments
+int Ng_GetNP_2D (Ng_Mesh * mesh);
+int Ng_GetNE_2D (Ng_Mesh * mesh);
+int Ng_GetNSeg_2D (Ng_Mesh * mesh);
+  
+//  return point coordinates
+void Ng_GetPoint_2D (Ng_Mesh * mesh, int num, double * x);
+
+// return 2d triangles
+void Ng_GetElement_2D (Ng_Mesh * mesh, int num, int * pi, int * matnum = NULL);
+
+// return 2d boundary segment
+void Ng_GetSegment_2D (Ng_Mesh * mesh, int num, int * pi, int * matnum = NULL);
+
+
+// load 2d netgen spline geometry
+Ng_Geometry_2D * Ng_LoadGeometry_2D (const char * filename);
+
+// generate 2d mesh, mesh is allocated by function
+Ng_Result Ng_GenerateMesh_2D (Ng_Geometry_2D * geom,
+                              Ng_Mesh ** mesh,
+                              Ng_Meshing_Parameters * mp);
+  
+void Ng_HP_Refinement (Ng_Geometry_2D * geom,
+                       Ng_Mesh * mesh,
+                       int levels);
+  
+
+
+
+
+// **********************************************************
+// **   STL Meshing                                        **
+// **********************************************************
+
+
+// loads geometry from STL file
+Ng_STL_Geometry * Ng_STL_LoadGeometry (const char * filename, int binary = 0);
+
+
+// generate new STL Geometry
+Ng_STL_Geometry * Ng_STL_NewGeometry ();
+  
+
+// fills STL Geometry
+// positive orientation
+// normal vector may be null-pointer
+void Ng_STL_AddTriangle (Ng_STL_Geometry * geom, 
+                         double * p1, double * p2, double * p3, 
+                         double * nv = NULL);
+
+// add (optional) edges :
+void Ng_STL_AddEdge (Ng_STL_Geometry * geom, 
+                     double * p1, double * p2);
+
+// after adding triangles (and edges) initialize
+Ng_Result Ng_STL_InitSTLGeometry (Ng_STL_Geometry * geom);
+
+// automatically generates edges:
+Ng_Result Ng_STL_MakeEdges (Ng_STL_Geometry * geom,
+                            Ng_Mesh* mesh,
+                            Ng_Meshing_Parameters * mp);
+
+
+// generates mesh, empty mesh must be already created.
+Ng_Result Ng_STL_GenerateSurfaceMesh (Ng_STL_Geometry * geom,
+                                      Ng_Mesh * mesh,
+                                      Ng_Meshing_Parameters * mp);
+
+
+#ifdef ACIS
+
+// **********************************************************
+// **   ACIS Meshing                                       **
+// **********************************************************
+
+/// Data type for NETGEN STL geomty
+typedef void * Ng_ACIS_Geometry;
+
+// loads geometry from STL file
+Ng_ACIS_Geometry * Ng_ACIS_LoadGeometry (const char * filename);
+  
+// generates mesh, empty mesh must be already created.
+Ng_Result Ng_ACIS_GenerateSurfaceMesh (Ng_ACIS_Geometry * geom,
+                                       Ng_Mesh * mesh,
+                                       Ng_Meshing_Parameters * mp);
+
+
+#endif
+
+
+#endif
\ No newline at end of file
diff --git a/contrib/Netgen/libsrc/interface/readtetmesh.cpp b/contrib/Netgen/libsrc/interface/readtetmesh.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..4a81e5e7ab107f9294726f0b5a320d7033a94067
--- /dev/null
+++ b/contrib/Netgen/libsrc/interface/readtetmesh.cpp
@@ -0,0 +1,797 @@
+
+//
+//  Read CST file format
+//
+
+#include <mystdlib.h>
+
+#include <myadt.hpp>
+#include <linalg.hpp>
+#include <csg.hpp>
+#include <meshing.hpp>
+#include <sys/stat.h>
+
+
+namespace netgen
+{
+#include "writeuser.hpp"
+
+
+
+
+  void ReadTETFormat (Mesh & mesh, 
+                      const string & hfilename)
+  {
+    const char * filename = hfilename.c_str();
+
+    cout << "Reading .tet mesh" << endl;
+
+    ifstream in (filename);
+
+    int inputsection = 0;
+    bool done = false;
+
+    char ch;
+    string str;
+
+    string version;
+
+    int unitcode;
+    double tolerance;
+    double dS1, dS2, alphaDeg, x3D, y3D, z3D;
+    int nelts,nfaces,nedges,nnodes;
+    int nperiodicmasternodes,ncornerperiodicmasternodes,ncubicperiodicmasternodes;
+    int nperiodicmasteredges,ncornerperiodicmasteredges;
+    int nperiodicmasterfaces;
+    int nodeid,type,pid;
+    int dummyint;
+    int modelverts,modeledges,modelfaces,modelcells;
+    Point3d p;
+    int numObj3D,numObj2D,numObj1D,numObj0D;
+    bool nullstarted;
+    ARRAY<int> eldom;
+    int minId3D,minId2D;
+    int maxId3D(-1), maxId2D(-1), maxId1D(-1), maxId0D(-1);
+    ARRAY<ARRAY<int> *> segmentdata;
+    ARRAY<Element2d* > tris;
+
+    ARRAY<int> userdata_int;  // just save data for 1:1 output
+    ARRAY<double> userdata_double;
+    ARRAY<int> point_pids;
+    ARRAY<int> tetfacedata;
+    ARRAY<int> uid_to_group_3D, uid_to_group_2D, uid_to_group_1D, uid_to_group_0D;
+
+    while(!done)
+      {
+        // skip "//" comment
+        bool comment = true;
+        while(comment)
+          {
+            ch = in.get();
+            while(ch == ' ' || ch == '\n' || ch == '\t' || ch =='\r')
+              ch = in.get();
+	      
+            if(ch != '/')
+              {
+                comment = false;
+                in.putback(ch);
+              }
+            else
+              {
+                ch = in.get();
+                if(ch != '/')
+                  {
+                    comment = false;
+                    in.putback(ch);
+                    in.putback('/');
+                  }
+                else
+                  {
+                    in.ignore(10000,'\n');
+                  }
+              }
+          }
+
+	  
+        switch(inputsection)
+          {
+          case 0:
+            // version number
+            in >> version;
+            cout << "Version number " << version << endl;
+            if(version != "1.1" && version != "2" && version != "2.0")
+              {
+                cerr << "WARNING: import only tested for versions 1.1 and 2" << endl;
+                //done = true;
+              }
+            userdata_double.Append(atof(version.c_str()));
+            break;
+
+          case 1:
+            // unit code (1=CM 2=MM 3=M 4=MIC 5=NM 6=FT 7=IN 8=MIL)
+            in >> unitcode;
+            cout << "unit code " << unitcode << endl;
+            userdata_int.Append(unitcode);
+            break;
+
+          case 2:
+            // Geometric coord "zero" tolerance threshold
+            in >> tolerance;
+            cout << "tolerance " << tolerance << endl;
+            userdata_double.Append(tolerance);
+            break;
+
+          case 3:
+            // Periodic UnitCell dS1 , dS2 , alphaDeg
+            in >> dS1 >> dS2 >> alphaDeg;
+            userdata_double.Append(dS1);
+            userdata_double.Append(dS2);
+            userdata_double.Append(alphaDeg);
+            break;
+
+          case 4:
+            // Periodic UnitCell origin in global coords (x3D,y3D,z3D)
+            in >> x3D >> y3D >> z3D;
+            userdata_double.Append(x3D);
+            userdata_double.Append(y3D);
+            userdata_double.Append(z3D);
+            break;
+
+          case 5:
+            // Model entity count: Vertices, Edges, Faces, Cells (Version 2)
+            in >> modelverts >> modeledges >> modelfaces >> modelcells;
+            userdata_int.Append(modelverts);
+            userdata_int.Append(modeledges);
+            userdata_int.Append(modelfaces);
+            userdata_int.Append(modelcells);
+            break;
+
+          case 6:
+            // Topological mesh-entity counts (#elements,#faces,#edges,#nodes)
+            in >> nelts >> nfaces >> nedges >> nnodes;
+            cout << nelts << " elements, " << nfaces << " faces, " << nedges << " edges, " << nnodes << " nodes" << endl;
+            mesh.SetAllocSize(nnodes,2*nedges,nfaces,nelts);
+            break;
+
+          case 7:
+            // NodeID, X, Y, Z, Type (0=Reg 1=PMaster 2=PSlave 3=CPMaster 4=CPSlave), PID:
+            {
+              cout << "read nodes" << endl;
+              for(int i=0; i<nnodes; i++)
+                {
+                  in >> nodeid >> p.X() >> p.Y() >> p.Z() >> type >> pid;
+                  mesh.AddPoint(p);		  
+                  point_pids.Append(pid);
+                  if(pid > maxId0D)
+                    maxId0D = pid;
+                  //(*testout) << "point " << p << " type " << type << " mastersexist " << mastersexist << endl;
+                }
+            }
+            break;
+
+          case 8:
+            // Number of Periodic Master Nodes
+            in >> nperiodicmasternodes;
+            break;
+
+          case 9:
+            // MasterNodeID, SlaveNodeID, TranslCode (1=dS1 2=dS2 3=dS1+dS2)
+            for(int i=0; i<nperiodicmasternodes; i++)
+              {
+                for(int j=0; j<2; j++)
+                  in >> dummyint;
+
+                in >> dummyint;
+              }
+            break;
+
+          case 10:
+            // Number of Corner Periodic Master Nodes
+            in >> ncornerperiodicmasternodes;
+            break;
+
+          case 11:
+            // MasterNodeID, 3-SlaveNodeID's, 3-TranslCodes (1=dS1 2=dS2 3=dS1+dS2)
+            for(int i=0; i<ncornerperiodicmasternodes; i++)
+              {
+                for(int j=0; j<4; j++)
+                  in >> dummyint;
+
+                for(int j=0; j<3; j++)
+                  in >> dummyint;
+              }
+            break;
+
+          case 12:
+            // Number of Cubic Periodic Master Nodes
+            in >> ncubicperiodicmasternodes;
+            break;
+
+          case 13:
+            //MasterNodeID, 7-SlaveNodeID's, TranslCodes
+            for(int i=0; i<ncubicperiodicmasternodes; i++)
+              {
+                for(int j=0; j<8; j++)
+                  in >> dummyint;
+
+                for(int j=0; j<7; j++)
+                  in >> dummyint;
+              }
+            break;
+
+          case 14:
+            // EdgeID, NodeID0, NodeID1, Type (0=Reg 1=PMaster 2=PSlave 3=CPMaster 4=CPSlave), PID
+            cout << "read edges" << endl;
+            nullstarted = false;
+            segmentdata.SetSize(nedges);
+            for(int i=0; i<nedges; i++)
+              {
+                segmentdata[i] = new ARRAY<int>(7);
+                *segmentdata[i] = -1;
+                in >> dummyint;
+                in >> (*segmentdata[i])[0] >> (*segmentdata[i])[1];
+                in >> type;
+                in >> (*segmentdata[i])[2];
+                if((*segmentdata[i])[2] > maxId1D)
+                  maxId1D = (*segmentdata[i])[2];
+              }
+            break;
+
+          case 15:
+            // Number of Periodic Master Edges
+            in >> nperiodicmasteredges;
+            break;
+
+          case 16:
+            // MasterEdgeID, SlaveEdgeID, TranslCode (1=dS1 2=dS2 3=dS1+dS2)
+            for(int i=0; i<nperiodicmasteredges; i++)
+              in >> dummyint >> dummyint >> dummyint;
+            break;
+
+          case 17:
+            // Number of Corner Periodic Master Edges
+            in >> ncornerperiodicmasteredges;
+            break;
+
+          case 18:
+            // MasterEdgeID, 3 SlaveEdgeID's, 3 TranslCode (1=dS1 2=dS2 3=dS1+dS2)
+            for(int i=0; i<ncornerperiodicmasteredges; i++)
+              {
+                in >> dummyint;
+                for(int j=0; j<3; j++)
+                  in >> dummyint;
+                for(int j=0; j<3; j++)
+                  in >> dummyint;
+              }
+            break;
+
+          case 19:
+            // FaceID, EdgeID0, EdgeID1, EdgeID2, FaceType (0=Reg 1=PMaster 2=PSlave), PID
+            {
+              //Segment seg;
+              int segnum_ng[3];
+              bool neg[3];
+              cout << "read faces" << endl;
+              nullstarted = false;
+              for(int i=0; i<nfaces; i++)
+                {
+                  int trinum;
+                  int segnum;
+		    
+                  tris.Append(new Element2d(TRIG));
+
+                  in >> trinum;
+                  for(int j=0; j<3; j++)
+                    {
+                      in >> segnum;
+                      neg[j] = (segnum<0);
+                      if(!neg[j])
+                        segnum_ng[j] = segnum-1;
+                      else
+                        segnum_ng[j] = -segnum-1;
+			
+                      if(neg[j])
+                        tris.Last()->PNum(j+1) = (*segmentdata[segnum_ng[j]])[1];
+                      else
+                        tris.Last()->PNum(j+1) = (*segmentdata[segnum_ng[j]])[0];
+
+                      tris.Last()->GeomInfoPi(j+1).trignum = trinum;
+                    }
+                  in >> type;
+                  int faceid;
+                  in >> faceid;
+		    
+                  if(faceid > maxId2D)
+                    maxId2D = faceid;
+
+                  if(i==0 || faceid < minId2D)
+                    minId2D = faceid;
+		    
+                  tris.Last()->SetIndex(faceid);
+
+                  if(faceid > 0)
+                    {
+                      //if(nullstarted)
+                      //  {
+                      //    cout << "Faces: Assumption about index 0 wrong (face"<<trinum <<")" << endl;
+                      //  }
+                      //mesh.AddSurfaceElement(tri);
+			
+                      for(int j=0; j<3; j++)
+                        {
+                          if(neg[j])
+                            {
+                              (*segmentdata[segnum_ng[j]])[4] = faceid;
+                              (*segmentdata[segnum_ng[j]])[6] = trinum;
+                            }
+                          else
+                            {
+                              (*segmentdata[segnum_ng[j]])[3] = faceid;
+                              (*segmentdata[segnum_ng[j]])[5] = trinum;
+                            }
+                        }
+                    }
+                  else
+                    nullstarted = true;
+                }
+            }
+            break;
+
+          case 20:
+            // Number of Periodic Master Faces
+            in >> nperiodicmasterfaces;
+            break;
+
+          case 21:
+            // MasterFaceID, SlaveFaceID, TranslCode (1=dS1 2=dS2)
+            {
+              Vec<3> randomvec(-1.32834,3.82399,0.5429151);
+              int maxtransl = -1;
+              for(int i=0; i<nperiodicmasterfaces; i++)
+                {
+                  int tri1,tri2,transl;
+                  ARRAY<PointIndex> nodes1(3),nodes2(3);
+                  ARRAY<double> sortval1(3),sortval2(3);
+                  in >> tri1 >> tri2 >> transl;
+
+                  if(transl > maxtransl)
+                    maxtransl = transl;
+		    
+		    
+                  for(int j=0; j<3; j++)
+                    {
+                      nodes1[j] = tris[tri1-1]->PNum(j+1);
+                      sortval1[j] = Vec<3>(mesh[nodes1[j]])*randomvec;
+                      nodes2[j] = tris[tri2-1]->PNum(j+1);
+                      sortval2[j] = Vec<3>(mesh[nodes2[j]])*randomvec;
+                    }
+
+                  BubbleSort(sortval1,nodes1);
+                  BubbleSort(sortval2,nodes2);
+
+                  for(int j=0; j<3; j++)
+                    mesh.GetIdentifications().Add(nodes1[j],nodes2[j],transl);
+			
+                }
+              for(int i=1; i<= maxtransl; i++)
+                mesh.GetIdentifications().SetType(i,Identifications::PERIODIC);
+            }	      
+            break;
+
+          case 22:
+            // ElemID, FaceID0, FaceID1, FaceID2, FaceID3, PID
+            {
+              cout << "read elements (1)" << endl;
+
+              //SurfaceElementIndex surf[4];
+              bool neg[4];
+              int elemid;
+              int domain;
+		
+              eldom.SetSize(nelts);
+
+              for(int i=0; i<nelts; i++)
+                {
+                  if(int(100.*i/nelts) % 5 == 0)
+                    cout << int(100.*i/nelts)
+#ifdef WIN32
+                         << "%%\r"
+#else
+                         << "\%\r"
+#endif 
+                         << flush;
+                  in >> elemid;
+                  for(int j=0; j<4;j++)
+                    {
+                      in >> dummyint;
+                      neg[j] = (dummyint < 0);
+                      if(neg[j])
+                        tetfacedata.Append(-dummyint-1);
+                      //surf[j] = -dummyint-1;
+                      else
+                        tetfacedata.Append(dummyint-1);
+                      tetfacedata.Append(((neg[j]) ? 1 : 0));
+                      //surf[j] = dummyint-1;
+                    }
+		    
+                  in >> domain;
+                  eldom[i] = domain;
+                  tetfacedata.Append(domain);
+
+                  if(i==0 || domain < minId3D)
+                    minId3D = domain;
+
+                  if(domain > maxId3D)
+                    maxId3D = domain;
+		    
+                  // 		    for(int j=0; j<4; j++)
+                  // 		      {
+                  // 			if(mesh.GetNSE() <= surf[j])
+                  // 			  continue;
+
+                  // 			int faceind = 0;
+                  // 			for(int k=1; k<=mesh.GetNFD(); k++)
+                  // 			  {
+                  // 			    if(mesh.GetFaceDescriptor(k).SurfNr() == mesh[surf[j]].GetIndex())
+                  // 			      faceind = k;
+                  // 			  }
+                  // 			if(faceind)
+                  // 			  {
+                  // 			    if(neg[j])
+                  // 			      mesh.GetFaceDescriptor(faceind).SetDomainOut(domain);
+                  // 			    else
+                  // 			      mesh.GetFaceDescriptor(faceind).SetDomainIn(domain);
+                  // 			  }
+                  // 			else
+                  // 			  {
+                  // 			    if(neg[j])
+                  // 			      faceind = mesh.AddFaceDescriptor(FaceDescriptor(mesh[surf[j]].GetIndex(),0,domain,0));
+                  // 			    else
+                  // 			      faceind = mesh.AddFaceDescriptor(FaceDescriptor(mesh[surf[j]].GetIndex(),domain,0,0));
+                  // 			    mesh.GetFaceDescriptor(faceind).SetBCProperty(mesh[surf[j]].GetIndex());
+                  // 			  }
+                  // 		      }
+                }
+              cout << endl;
+		
+		
+              // 		ARRAY<int> indextodescriptor(maxId2D+1);
+		
+              // 		for(int i=1; i<=mesh.GetNFD(); i++)
+              // 		  indextodescriptor[mesh.GetFaceDescriptor(i).SurfNr()] = i;
+		
+		
+              // 		for(SurfaceElementIndex i=0; i<mesh.GetNSE(); i++)
+              // 		  mesh[i].SetIndex(indextodescriptor[mesh[i].GetIndex()]);
+            }
+            break;
+
+          case 23:
+            // ElemID, NodeID0, NodeID1, NodeID2, NodeID3
+            { 
+              cout << "read elements (2)" << endl;
+              Element el(TET);
+              for(ElementIndex i=0; i<nelts; i++)
+                {
+                  in >> dummyint;
+                  for(int j=1; j<=4; j++)
+                    in >> el.PNum(j);
+                  swap(el.PNum(1),el.PNum(2));
+		    
+                  el.SetIndex(eldom[i]);
+                  mesh.AddVolumeElement(el);
+                }	
+            }	  
+            break;
+	      
+          case 24:
+            // Physical Object counts (#Obj3D,#Obj2D,#Obj1D,#Obj0D)
+            {
+              in >> numObj3D;
+              userdata_int.Append(numObj3D);
+              in >> numObj2D;
+              userdata_int.Append(numObj2D);
+              in >> numObj1D;
+              userdata_int.Append(numObj1D);
+              in >> numObj0D;
+              userdata_int.Append(numObj0D);
+            }
+            break;
+
+          case 25:
+            // Number of Ports (Ports are a subset of Object2D list)
+            {
+              in >> dummyint;
+              //userdata_int.Append(dummyint);
+            }
+            break;
+
+          case 26:
+            // Object3D GroupID, #Elems <immediately followed by> ElemID List
+            {
+              uid_to_group_3D.SetSize(maxId3D+1);
+              uid_to_group_3D = -1;
+              for(int i=0; i<numObj3D; i++)
+                {
+                  int groupid;
+                  in >> groupid;
+                  (*testout) << "3d groupid " << groupid << endl;
+                  //userdata_int.Append(groupid);
+                  int nelems;
+                  in >> nelems;
+                  //userdata_int.Append(nelems);
+                  for(int j=0; j<nelems; j++)
+                    {
+                      in >> dummyint;
+			
+                      (*testout) << "read " << dummyint << endl;
+                      //userdata_int.Append(dummyint);
+			
+                      if(dummyint < 0) 
+                        dummyint *= -1;
+                      uid_to_group_3D[eldom[dummyint-1]] = groupid;
+                    }
+                }
+            }
+            break;
+
+          case 27:
+            // Object2D GroupID, #Faces <immediately followed by> FaceID List
+            {
+              ARRAY<int> ports;
+              //int totnum = 0;
+              uid_to_group_2D.SetSize(maxId2D+1);
+              uid_to_group_2D = -1;
+
+              for(int i=0; i<numObj2D; i++)
+                {
+                  int groupid;
+                  in >> groupid;
+                  (*testout) << "2d groupid " << groupid << endl;
+                  //userdata_int.Append(groupid);
+                  int nelems;
+                  in >> nelems;
+                  //userdata_int.Append(nelems);
+                  for(int j=0; j<nelems; j++)
+                    {
+                      in >> dummyint;
+                      char port;
+                      while((port = in.get()) == ' ')
+                        ;
+
+                      (*testout) << "read " << dummyint << endl;
+                      if(dummyint < 0) 
+                        dummyint *= -1;
+                      int uid = tris[dummyint-1]->GetIndex();
+
+                      if(port == 'P' || port == 'p')
+                        {
+                          if(!ports.Contains(uid))
+                            ports.Append(uid);
+                        }
+                      else
+                        in.putback(port);
+			
+                      //userdata_int.Append(dummyint);
+			
+                      uid_to_group_2D[uid] = groupid;
+                      (*testout) << "setting " << uid << endl;
+
+                      //totnum++;
+                    }
+                }
+              mesh.SetUserData("TETmesh:ports",ports);
+            }
+            break;
+
+          case 28:
+            // Object1D GroupID, #Edges <immediately followed by> EdgeID List
+            {
+              uid_to_group_1D.SetSize(maxId1D+1);
+              uid_to_group_1D = -1;
+
+              for(int i=0; i<numObj1D; i++)
+                {
+                  int groupid;
+                  in >> groupid;
+                  //userdata_int.Append(groupid);
+                  int nelems;
+                  in >> nelems;
+                  //userdata_int.Append(nelems);
+                  for(int j=0; j<nelems; j++)
+                    {
+                      in >> dummyint;
+                      //userdata_int.Append(dummyint);
+
+                      if(dummyint < 0) 
+                        dummyint *= -1;
+                      uid_to_group_1D[(*segmentdata[dummyint-1])[2]] = groupid;
+                    }
+                }
+            }
+            break;
+
+          case 29:
+            // Object0D GroupID, #Nodes <immediately followed by> NodeID List
+            {
+              uid_to_group_0D.SetSize(maxId0D+1);
+              uid_to_group_0D = -1;
+              for(int i=0; i<numObj0D; i++)
+                {
+                  int groupid;
+                  in >> groupid;
+                  //userdata_int.Append(groupid);
+                  int nelems;
+                  in >> nelems;
+                  //userdata_int.Append(nelems);
+                  for(int j=0; j<nelems; j++)
+                    {
+                      in >> dummyint;
+                      //userdata_int.Append(dummyint);
+
+                      if(dummyint < 0) 
+                        dummyint *= -1;
+                      uid_to_group_0D[point_pids[dummyint-1]] = groupid;
+                    }
+                }
+            }
+            break;
+
+
+
+          default:
+            done = true;
+	      
+          }
+	  
+        if(inputsection == 4 && version == "1.1")
+          inputsection++;
+
+        inputsection++;
+      }
+    in.close();
+
+
+    mesh.SetUserData("TETmesh:double",userdata_double);
+    userdata_int.Append(minId2D);
+    userdata_int.Append(minId3D);
+    mesh.SetUserData("TETmesh:int",userdata_int);   
+    //if(version == "1.1")
+    mesh.SetUserData("TETmesh:point_id",point_pids);
+
+    mesh.SetUserData("TETmesh:uid_to_group_3D",uid_to_group_3D);
+    mesh.SetUserData("TETmesh:uid_to_group_2D",uid_to_group_2D);
+    mesh.SetUserData("TETmesh:uid_to_group_1D",uid_to_group_1D);
+    mesh.SetUserData("TETmesh:uid_to_group_0D",uid_to_group_0D);
+
+
+    ARRAY<SurfaceElementIndex> surfindices(tris.Size());
+    surfindices = -1;
+
+    for(int i=0; i<tris.Size(); i++)
+      {
+        if(atof(version.c_str()) <= 1.999999)
+          {
+            if(tris[i]->GetIndex() > 0)
+              surfindices[i] = mesh.AddSurfaceElement(*tris[i]);
+          }
+        else
+          {
+            if(tris[i]->GetIndex() > 0 &&
+               tris[i]->GetIndex() < minId3D)
+              {
+                tris[i]->SetIndex(tris[i]->GetIndex()-minId2D+1);
+                surfindices[i] = mesh.AddSurfaceElement(*tris[i]);
+              }
+          }
+        delete tris[i];
+      }
+
+      
+    mesh.ClearFaceDescriptors();
+    if(atof(version.c_str()) <= 1.999999)
+      for(int i = 1; i <= maxId2D; i++)
+        mesh.AddFaceDescriptor(FaceDescriptor(i,0,0,0));
+    else
+      for(int i=minId2D; i<minId3D; i++)
+        mesh.AddFaceDescriptor(FaceDescriptor(i,0,0,0));
+	
+
+    for(int i=0; i<tetfacedata.Size(); i+=9)
+      {
+        for(int j=0; j<4; j++)
+          {
+            SurfaceElementIndex surf = surfindices[tetfacedata[i+2*j]];
+	      
+            //if(mesh.GetNSE() <= surf)
+            if(surf == -1)
+              continue;
+
+            if(tetfacedata[i+2*j+1] == 1)
+              mesh.GetFaceDescriptor(mesh[surf].GetIndex()).SetDomainOut(tetfacedata[i+8]);
+            else
+              mesh.GetFaceDescriptor(mesh[surf].GetIndex()).SetDomainIn(tetfacedata[i+8]);
+			
+
+            /*
+	      int faceind = 0;
+	      for(int k=1; k<=mesh.GetNFD(); k++)
+              {
+              if(mesh.GetFaceDescriptor(k).SurfNr() == mesh[surf].GetIndex())
+              faceind = k;
+              }
+	      if(faceind)
+              {
+              if(tetfacedata[i+4+j] == 1)
+              mesh.GetFaceDescriptor(faceind).SetDomainOut(tetfacedata[i+8]);
+              else
+              mesh.GetFaceDescriptor(faceind).SetDomainIn(tetfacedata[i+8]);
+              }
+	      else
+              {
+              if(tetfacedata[i+4+j] == 1)
+              faceind = mesh.AddFaceDescriptor(FaceDescriptor(mesh[surf].GetIndex(),0,tetfacedata[i+8],0));
+              else
+              faceind = mesh.AddFaceDescriptor(FaceDescriptor(mesh[surf].GetIndex(),tetfacedata[i+8],0,0));
+              mesh.GetFaceDescriptor(faceind).SetBCProperty(mesh[surf].GetIndex());
+              }
+            */
+          }
+
+      }
+      
+    //       ARRAY<int> indextodescriptor(maxId2D+1);
+		
+    //       for(int i=1; i<=mesh.GetNFD(); i++)
+    // 	indextodescriptor[mesh.GetFaceDescriptor(i).SurfNr()] = i;
+		
+		
+    //       for(SurfaceElementIndex i=0; i<mesh.GetNSE(); i++)
+    // 	mesh[i].SetIndex(indextodescriptor[mesh[i].GetIndex()]);
+
+
+    for(int i=0; i<segmentdata.Size(); i++)
+      {
+        Segment seg;
+
+	  
+        if((atof(version.c_str()) <= 1.999999 && (*segmentdata[i])[2] > 0) ||
+           (atof(version.c_str()) > 1.999999  && (*segmentdata[i])[2] > 0 && (*segmentdata[i])[2] < minId2D))
+          {
+            seg.p1 = (*segmentdata[i])[0];
+            seg.p2 = (*segmentdata[i])[1];
+            seg.edgenr = (*segmentdata[i])[2];
+            seg.epgeominfo[0].edgenr = (*segmentdata[i])[2];
+            seg.epgeominfo[1].edgenr = (*segmentdata[i])[2];
+            seg.si = (*segmentdata[i])[3]-minId2D+1;
+            seg.surfnr1 = -1;//(*segmentdata[i])[3];
+            seg.surfnr2 = -1;//(*segmentdata[i])[4];
+            seg.geominfo[0].trignum = (*segmentdata[i])[5];
+            seg.geominfo[1].trignum = (*segmentdata[i])[5];
+            mesh.AddSegment(seg);
+
+            seg.p1 = (*segmentdata[i])[1];
+            seg.p2 = (*segmentdata[i])[0];
+            seg.si = (*segmentdata[i])[4]-minId2D+1;
+            seg.surfnr1 = -1;//(*segmentdata[i])[3];
+            seg.surfnr2 = -1;//(*segmentdata[i])[4];
+            seg.geominfo[0].trignum = (*segmentdata[i])[6];
+            seg.geominfo[1].trignum = (*segmentdata[i])[6];
+            mesh.AddSegment(seg);
+          }
+        delete segmentdata[i];
+      }
+
+    /*
+      for(int i=mesh.GetNSeg(); i>=1; i--)
+      if(mesh.LineSegment(i).epgeominfo[0].edgenr == 0 ||
+      mesh.LineSegment(i).epgeominfo[1].edgenr == 0)
+      mesh.FullDeleteSegment(i);
+    */	
+  
+    mesh.CalcSurfacesOfNode();
+      
+  }
+}
+
+
diff --git a/contrib/Netgen/libsrc/interface/readuser.cpp b/contrib/Netgen/libsrc/interface/readuser.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..cb677d8d72421cf35bce5f96dd8fb64a72478688
--- /dev/null
+++ b/contrib/Netgen/libsrc/interface/readuser.cpp
@@ -0,0 +1,407 @@
+//
+//  Read user dependent output file
+//
+
+
+#include <mystdlib.h>
+
+
+#include <myadt.hpp>
+#include <linalg.hpp>
+#include <csg.hpp>
+#include <meshing.hpp>
+
+namespace netgen
+{
+#include "writeuser.hpp"
+
+  void ReadFile (Mesh & mesh,
+                 const string & hfilename)
+  {
+    cout << "Read User File" << endl;
+
+    const char * filename = hfilename.c_str();
+
+    int i, j;
+
+    char reco[100];
+    int np, nbe;
+
+
+
+    // ".surf" - mesh
+  
+    if ( (strlen (filename) > 5) &&
+         strcmp (&filename[strlen (filename)-5], ".surf") == 0 )
+    
+      {
+        cout << "Surface file" << endl;
+      
+        ifstream in (filename);
+      
+        in >> reco;
+        in >> np;
+        for (i = 1; i <= np; i++)
+          {
+            Point3d p;
+            in >> p.X() >> p.Y() >> p.Z();
+            mesh.AddPoint (p);
+          }
+
+        mesh.ClearFaceDescriptors();
+        mesh.AddFaceDescriptor (FaceDescriptor(0,1,0,0));
+      
+        in >> nbe;
+        //      int invert = globflags.GetDefineFlag ("invertsurfacemesh");
+        for (i = 1; i <= nbe; i++)
+          {
+            Element2d el;
+            int hi;
+	  
+            el.SetIndex(1);
+	  
+            // in >> hi; 
+            for (j = 1; j <= 3; j++)
+              {
+                in >> el.PNum(j);
+                // el.PNum(j)++;
+                if (el.PNum(j) < PointIndex(1) || 
+                    el.PNum(j) > PointIndex(np))
+                  {
+                    cerr << "Point Number " << el.PNum(j) << " out of range 1..."
+                         << np << endl;
+                    return;
+                  }
+              }
+	  
+            /*
+              if (invert)
+              swap (el.PNum(2), el.PNum(3));
+            */
+	  
+            mesh.AddSurfaceElement (el);
+          }
+      
+      
+        cout << "points: " << np << " faces: " << nbe << endl;
+      }
+  
+  
+  
+
+  
+    // Universal mesh (AVL)
+    if ( (strlen (filename) > 4) &&
+         strcmp (&filename[strlen (filename)-4], ".unv") == 0 )
+      {  
+        int i, j, k;
+      
+        double h;
+        char reco[100];
+        int np, nbe;
+        int invert;
+      
+      
+        ifstream in(filename);
+
+        invert = 0;    // globflags.GetDefineFlag ("invertsurfacemesh");
+        double scale = 1;  // globflags.GetNumFlag ("scale", 1);
+
+        mesh.ClearFaceDescriptors();
+        mesh.AddFaceDescriptor (FaceDescriptor(0,1,0,0));
+
+
+        while (in.good())
+          {
+            in >> reco;
+            if (strcmp (reco, "NODES") == 0)
+              {
+                cout << "nodes found" << endl;
+                for (j = 1; j <= 4; j++)
+                  in >> reco;  // read dummy
+
+                while (1)
+                  {
+                    int pi, hi;
+                    double x, y, z;
+                    Point3d p;
+
+                    in >> pi;
+                    if (pi == -1)
+                      break;
+
+                    in >> hi >> hi >> hi;
+                    in >> p.X() >> p.Y() >> p.Z();
+
+                    p.X() *= scale;
+                    p.Y() *= scale;
+                    p.Z() *= scale;
+
+
+                    mesh.AddPoint (p);
+                  }
+              }
+
+            if (strcmp (reco, "ELEMENTS") == 0)
+              {
+                cout << "elements found" << endl;
+                for (j = 1; j <= 4; j++)
+                  in >> reco;  // read dummy
+
+                while (1)
+                  {
+                    int hi;
+                    in >> hi;
+                    if (hi == -1) break;
+                    for (j = 1; j <= 7; j++)
+                      in >> hi;
+	      
+                    Element2d el;
+                    el.SetIndex(1);
+                    in >> el.PNum(1) >> el.PNum(2) >> el.PNum(3);
+	      
+                    if (invert)
+                      swap (el.PNum(2), el.PNum(3));
+                    mesh.AddSurfaceElement (el);	  
+	      
+                    for (j = 1; j <= 5; j++)
+                      in >> hi;
+                  }
+              }
+          }
+      
+
+        Point3d pmin, pmax;
+        mesh.GetBox (pmin, pmax);
+        cout << "bounding-box = " << pmin << "-" << pmax << endl;
+      }
+
+
+
+    // fepp format2d:
+  
+    if ( (strlen (filename) > 7) &&
+         strcmp (&filename[strlen (filename)-7], ".mesh2d") == 0 )
+      {
+        cout << "Reading FEPP2D Mesh" << endl;
+      
+        char buf[100];
+        int np, ne, nseg, i, j;
+
+        ifstream in (filename);
+
+        in >> buf;
+
+        in >> nseg;
+        for (i = 1; i <= nseg; i++)
+          {
+            int bound, p1, p2;
+            in >> bound >> p1 >> p2;
+            // forget them
+          }
+
+        in >> ne;
+        for (i = 1; i <= ne; i++)
+          {
+            int mat, nelp;
+            in >> mat >> nelp;
+            Element2d el (nelp == 3 ? TRIG : QUAD);
+            el.SetIndex (mat);
+            for (j = 1; j <= nelp; j++)
+              in >> el.PNum(j);
+            mesh.AddSurfaceElement (el);
+          }
+
+        in >> np;
+        for (i = 1; i <= np; i++)
+          {
+            Point3d p(0,0,0);
+            in >> p.X() >> p.Y();
+            mesh.AddPoint (p);
+          }
+      }
+
+  
+    else if ( (strlen (filename) > 5) &&
+              strcmp (&filename[strlen (filename)-5], ".mesh") == 0 )
+      {
+        cout << "Reading Neutral Format" << endl;
+      
+        int np, ne, nse, i, j;
+
+        ifstream in (filename);
+
+        in >> np;
+
+        if (in.good())
+          {
+            // file starts with an integer
+
+            for (i = 1; i <= np; i++)
+              {
+                Point3d p(0,0,0);
+                in >> p.X() >> p.Y() >> p.Z();
+                mesh.AddPoint (p);
+              }
+	  
+            in >> ne;
+            for (i = 1; i <= ne; i++)
+              {
+                int mat;
+                in >> mat;
+                Element el (4);
+                el.SetIndex (mat);
+                for (j = 1; j <= 4; j++)
+                  in >> el.PNum(j);
+                mesh.AddVolumeElement (el);
+              }
+
+            mesh.AddFaceDescriptor (FaceDescriptor (1, 1, 0, 0));
+	  
+            in >> nse;
+            for (i = 1; i <= nse; i++)
+              {
+                int mat, nelp;
+                in >> mat;
+                Element2d el (TRIG);
+                el.SetIndex (mat);
+                for (j = 1; j <= 3; j++)
+                  in >> el.PNum(j);
+                mesh.AddSurfaceElement (el);
+              }
+          }
+        else
+          {
+            char buf[100];
+            in.clear();
+            do
+              {
+                in >> buf;
+                cout << "buf = " << buf << endl;
+                if (strcmp (buf, "points") == 0)
+                  {
+                    in >> np;
+                    cout << "np = " << np << endl;
+                  }
+              }
+            while (in.good());
+          }
+      }
+
+
+    if ( (strlen (filename) > 4) &&
+         strcmp (&filename[strlen (filename)-4], ".emt") == 0 )
+      {
+        ifstream inemt (filename);
+      
+        string pktfile = filename;
+        int len = strlen (filename);
+        pktfile[len-3] = 'p';
+        pktfile[len-2] = 'k';
+        pktfile[len-1] = 't';
+        cout << "pktfile = " << pktfile << endl;
+
+        int np, nse, i;
+        int num, bcprop;
+        ifstream inpkt (pktfile.c_str());
+        inpkt >> np;
+        ARRAY<double> values(np);
+        for (i = 1; i <= np; i++)
+          {
+            Point3d p(0,0,0);
+            inpkt >> p.X() >> p.Y() >> p.Z()
+                  >> bcprop >> values.Elem(i);
+            mesh.AddPoint (p);
+          }      
+
+        mesh.ClearFaceDescriptors();
+        mesh.AddFaceDescriptor (FaceDescriptor(0,1,0,0));
+        mesh.GetFaceDescriptor(1).SetBCProperty (1);
+        mesh.AddFaceDescriptor (FaceDescriptor(0,1,0,0));
+        mesh.GetFaceDescriptor(2).SetBCProperty (2);
+        mesh.AddFaceDescriptor (FaceDescriptor(0,1,0,0));
+        mesh.GetFaceDescriptor(3).SetBCProperty (3);
+        mesh.AddFaceDescriptor (FaceDescriptor(0,1,0,0));
+        mesh.GetFaceDescriptor(4).SetBCProperty (4);
+        mesh.AddFaceDescriptor (FaceDescriptor(0,1,0,0));
+        mesh.GetFaceDescriptor(5).SetBCProperty (5);
+
+        int p1, p2, p3;
+        double value;
+        inemt >> nse;
+        for (i = 1; i <= nse; i++)
+          {
+            inemt >> p1 >> p2 >> p3 >> bcprop >> value;
+
+            if (bcprop < 1 || bcprop > 4)
+              cerr << "bcprop out of range, bcprop = " << bcprop << endl;
+            p1++;
+            p2++;
+            p3++;
+            if (p1 < 1 || p1 > np || p2 < 1 || p2 > np || p3 < 1 || p3 > np)
+              {
+                cout << "p1 = " << p1 << " p2 = " << p2 << " p3 = " << p3 << endl;
+              }
+
+            if (i > 110354) Swap (p2, p3);
+            if (mesh.Point(p1)(0) < 0.25)
+              Swap (p2,p3);
+
+            Element2d el(TRIG);
+
+            if (bcprop == 1)
+              {
+                if (values.Get(p1) < -69999)
+                  el.SetIndex(1);
+                else
+                  el.SetIndex(2);
+              }
+            else
+              el.SetIndex(3);
+
+
+            el.PNum(1) = p1;
+            el.PNum(2) = p2;
+            el.PNum(3) = p3;
+            mesh.AddSurfaceElement (el);
+          }
+
+
+        ifstream incyl ("ngusers/guenter/cylinder.surf");
+        int npcyl, nsecyl; 
+        incyl >> npcyl;
+        cout << "npcyl = " << npcyl << endl;
+        for (i = 1; i <= npcyl; i++)
+          {
+            Point3d p(0,0,0);
+            incyl >> p.X() >> p.Y() >> p.Z();
+            mesh.AddPoint (p);
+          }
+        incyl >> nsecyl;
+        cout << "nsecyl = " << nsecyl << endl;
+        for (i = 1; i <= nsecyl; i++)
+          {
+            incyl >> p1 >> p2 >> p3;
+            p1 += np;
+            p2 += np;
+            p3 += np;
+            Element2d el(TRIG);
+            el.SetIndex(5);
+            el.PNum(1) = p1;
+            el.PNum(2) = p2;
+            el.PNum(3) = p3;
+            mesh.AddSurfaceElement (el);
+          }
+      }
+
+
+    // .tet mesh
+    if ( (strlen (filename) > 4) &&
+         strcmp (&filename[strlen (filename)-4], ".tet") == 0 )
+      {
+        ReadTETFormat (mesh, filename);
+      }
+  }
+  
+}
+
diff --git a/contrib/Netgen/libsrc/interface/writeabaqus.cpp b/contrib/Netgen/libsrc/interface/writeabaqus.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..2564da0be6af9523482a487cdda872a81f32f0e5
--- /dev/null
+++ b/contrib/Netgen/libsrc/interface/writeabaqus.cpp
@@ -0,0 +1,237 @@
+//
+//  Write Abaqus file
+//
+//
+
+#include <mystdlib.h>
+
+#include <myadt.hpp>
+#include <linalg.hpp>
+#include <csg.hpp>
+#include <meshing.hpp>
+
+namespace netgen
+{
+#include "writeuser.hpp"
+
+
+
+
+void WriteAbaqusFormat (const Mesh & mesh,
+			const string & filename)
+
+{
+      
+  cout << "\nWrite Abaqus Volume Mesh" << endl;
+
+  ofstream outfile (filename.c_str());
+
+  outfile << "*Heading" << endl;
+  outfile << " " << filename << endl;
+
+  outfile.precision(8);
+
+  outfile << "*Node" << endl;
+
+  int np = mesh.GetNP();
+  int ne = mesh.GetNE();
+  int i, j, k;
+
+  for (i = 1; i <= np; i++)
+    {
+      outfile << i << ", ";
+      outfile << mesh.Point(i)(0) << ", ";
+      outfile << mesh.Point(i)(1) << ", ";
+      outfile << mesh.Point(i)(2) << "\n";
+    }
+
+  int elemcnt = 0; //element counter
+  int finished = 0;
+  int indcnt = 1; //index counter
+
+  while (!finished)
+    {
+      int actcnt = 0;
+      const Element & el1 = mesh.VolumeElement(1);
+      int non = el1.GetNP();
+      if (non == 4)
+	{
+	  outfile << "*Element, type=C3D4, ELSET=PART" << indcnt << endl;
+	} 
+      else if (non == 10)
+	{
+	  outfile << "*Element, type=C3D10, ELSET=PART" << indcnt << endl;
+	} 
+      else
+	{
+	  cout << "unsupported Element type!!!" << endl;	  
+	}
+
+      for (i = 1; i <= ne; i++)
+	{
+	  const Element & el = mesh.VolumeElement(i);
+	      
+	  if (el.GetIndex() == indcnt)
+	    {
+	      actcnt++;
+	      if (el.GetNP() != non) 
+		{
+		  cout << "different element-types in a subdomain are not possible!!!" << endl;
+		  continue;
+		}
+		  
+	      elemcnt++;
+	      outfile << elemcnt << ", ";
+	      if (non == 4)
+		{
+		  outfile << el.PNum(1) << ", ";
+		  outfile << el.PNum(2) << ", ";
+		  outfile << el.PNum(4) << ", ";
+		  outfile << el.PNum(3) << "\n";
+		}
+	      else if (non == 10)
+		{
+		  outfile << el.PNum(1) << ", ";
+		  outfile << el.PNum(2) << ", ";
+		  outfile << el.PNum(4) << ", ";
+		  outfile << el.PNum(3) << ", ";
+		  outfile << el.PNum(5) << ", ";
+		  outfile << el.PNum(9) << ", ";
+		  outfile << el.PNum(7) << ", " << "\n";
+		  outfile << el.PNum(6) << ", ";
+		  outfile << el.PNum(8) << ", ";
+		  outfile << el.PNum(10) << "\n";
+		}
+	      else
+		{
+		  cout << "unsupported Element type!!!" << endl;
+		  for (j = 1; j <= el.GetNP(); j++)
+		    {
+		      outfile << el.PNum(j);
+		      if (j != el.GetNP()) outfile << ", ";
+		    }
+		  outfile << "\n";
+		}
+	    }
+	}	  
+      indcnt++;
+      if (elemcnt == ne) {finished = 1; cout << "all elements found by Index!" << endl;}
+      if (actcnt == 0) {finished = 1;}
+    }
+
+  if (mesh.GetIdentifications().GetMaxNr())
+    {
+      // periodic identification, implementation for
+      // Helmut J. Boehm, TU Vienna
+	  
+      char cfilename[255];
+      strcpy (cfilename, filename.c_str());
+
+      char mpcfilename[255];
+      strcpy (mpcfilename, cfilename);
+      size_t len = strlen (cfilename);
+      if (len >= 4 && (strcmp (mpcfilename+len-4, ".inp") == 0))
+	strcpy (mpcfilename+len-4, ".mpc");
+      else
+	strcat (mpcfilename, ".mpc");
+	  
+      ofstream mpc (mpcfilename);
+
+      int masternode(0);
+
+      ARRAY<INDEX_2> pairs;
+      BitArray master(np), help(np);
+      master.Set();
+      for (i = 1; i <= 3; i++)
+	{
+	  mesh.GetIdentifications().GetPairs (i, pairs);
+	  help.Clear();
+	  for (j = 1; j <= pairs.Size(); j++)
+	    {
+	      help.Set (pairs.Get(j).I1());
+	    }
+	  master.And (help);
+	}
+      for (i = 1; i <= np; i++)
+	if (master.Test(i))
+	  masternode = i;
+
+      cout << "masternode = " << masternode << " = "
+	   << mesh.Point(masternode) << endl;
+      ARRAY<int> slaves(3);
+      for (i = 1; i <= 3; i++)
+	{
+	  mesh.GetIdentifications().GetPairs (i, pairs);
+	  for (j = 1; j <= pairs.Size(); j++)
+	    {
+	      if (pairs.Get(j).I1() == masternode)
+		slaves.Elem(i) = pairs.Get(j).I2();
+	    }
+	  cout << "slave(" << i << ") = " << slaves.Get(i)
+	       << " = " << mesh.Point(slaves.Get(i)) << endl;
+	}
+	  
+	  
+      outfile << "**\n"
+	      << "*NSET,NSET=CTENODS\n"
+	      << slaves.Get(1) << ", " 
+	      << slaves.Get(2) << ", " 
+	      << slaves.Get(3) << endl;
+
+	  
+      outfile << "**\n"
+	      << "**POINT_fixed\n"
+	      << "**\n"
+	      << "*BOUNDARY, OP=NEW\n";
+      for (j = 1; j <= 3; j++)
+	outfile << masternode << ", " << j << ",,    0.\n";
+
+      outfile << "**\n"
+	      << "*BOUNDARY, OP=NEW\n";
+      for (j = 1; j <= 3; j++)
+	{
+	  Vec3d v(mesh.Point(masternode), mesh.Point(slaves.Get(j)));
+	  double vlen = v.Length();
+	  int dir = 0;
+	  if (fabs (v.X()) > 0.9 * vlen) dir = 2;
+	  if (fabs (v.Y()) > 0.9 * vlen) dir = 3;
+	  if (fabs (v.Z()) > 0.9 * vlen) dir = 1;
+	  if (!dir)
+	    cout << "ERROR: Problem with rigid body constraints" << endl;
+	  outfile << slaves.Get(j) << ", " << dir << ",,    0.\n";
+	}
+
+      outfile << "**\n"
+	      << "*EQUATION, INPUT=" << mpcfilename << endl;
+	  
+
+      BitArray eliminated(np);
+      eliminated.Clear();
+      for (i = 1; i <= mesh.GetIdentifications().GetMaxNr(); i++)
+	{
+	  mesh.GetIdentifications().GetPairs (i, pairs);
+	  if (!pairs.Size())
+	    continue;
+	      
+	  for (j = 1; j <= pairs.Size(); j++)
+	    if (pairs.Get(j).I1() != masternode && 
+		!eliminated.Test(pairs.Get(j).I2()))
+	      {
+		eliminated.Set (pairs.Get(j).I2());
+		for (k = 1; k <= 3; k++)
+		  {
+		    mpc << "4" << "\n";
+		    mpc << pairs.Get(j).I2() << "," << k << ", -1.0, ";
+		    mpc << pairs.Get(j).I1() << "," << k << ", 1.0, ";
+		    mpc << slaves.Get(i) << "," << k << ", 1.0, ";
+		    mpc << masternode << "," << k << ", -1.0 \n";
+		  }
+	      }
+	}
+    }
+
+
+  cout << "done" << endl;
+}
+
+}
diff --git a/contrib/Netgen/libsrc/interface/writediffpack.cpp b/contrib/Netgen/libsrc/interface/writediffpack.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..649702521ff5568baf2e2531c7132cc8da4e707c
--- /dev/null
+++ b/contrib/Netgen/libsrc/interface/writediffpack.cpp
@@ -0,0 +1,296 @@
+//
+//  Write diffpack file
+//
+//  by
+//  Bartosz Sawicki <sawickib@ee.pw.edu.pl>
+//  extended by
+//  Jacques Lechelle <jacques.lechelle@wanadoo.fr>
+//
+#include <mystdlib.h>
+
+#include <myadt.hpp>
+#include <linalg.hpp>
+#include <csg.hpp>
+#include <meshing.hpp>
+
+
+namespace netgen
+{
+#include "writeuser.hpp"
+
+
+void WriteDiffPackFormat (const Mesh & mesh,
+			  const CSGeometry & geom,
+			  const string & filename)
+{
+  //   double scale = globflags.GetNumFlag ("scale", 1);
+  double scale = 1;
+
+  ofstream outfile(filename.c_str());
+
+  if (mesh.GetDimension() == 3)
+
+    {
+      // Output compatible to Diffpack grid format
+      // Bartosz Sawicki <sawickib@ee.pw.edu.pl>
+
+      int np = mesh.GetNP();
+      int ne = mesh.GetNE();
+      int nse = mesh.GetNSE();
+      ARRAY <int> BIname;
+      ARRAY <int> BCsinpoint;
+      int i, j, k, l;
+
+
+      outfile.precision(6);
+      outfile.setf (ios::fixed, ios::floatfield);
+      outfile.setf (ios::showpoint);
+
+      const Element & eldummy = mesh.VolumeElement((int)1);
+      outfile << "\n\n"
+	"Finite element mesh (GridFE):\n\n"
+	"  Number of space dim. =   3\n"
+	"  Number of elements   =  " << ne << "\n"
+	"  Number of nodes      =  " << np << "\n\n"
+	"  All elements are of the same type : dpTRUE\n"
+	"  Max number of nodes in an element: "<< eldummy.GetNP() << "\n"
+	"  Only one subdomain               : dpFALSE\n"
+	"  Lattice data                     ? 0\n\n\n\n";
+      
+      for (i = 1; i <= nse; i++) 
+	{
+	  int BI=mesh.GetFaceDescriptor(mesh.SurfaceElement(i).GetIndex()).BCProperty();
+	  int nbi=BIname.Size();
+	  int found=0;
+	  for (j = 1; j <= nbi; j++)
+	    if(BI == BIname.Get(j)) found = 1;
+	  if( ! found ) BIname.Append(BI);	    	     
+	}
+      
+      outfile << "  " << BIname.Size() <<  " Boundary indicators:  ";
+      for (i =1 ; i <= BIname.Size(); i++)
+	outfile << BIname.Get(i) << " ";
+      outfile << "\n\n\n";
+      
+      outfile << "  Nodal coordinates and nodal boundary indicators,\n"
+	"  the columns contain:\n"
+	"   - node number\n"
+	"   - coordinates\n"
+	"   - no of boundary indicators that are set (ON)\n"
+	"   - the boundary indicators that are set (ON) if any.\n"
+	"#\n";
+
+      for (i = 1; i <= np; i++)
+        {
+          const Point3d & p = mesh.Point(i);
+
+          outfile.width(4);
+          outfile << i << "  (";
+          outfile.width(10);
+          outfile << p.X()/scale << ", ";
+          outfile.width(9);
+          outfile << p.Y()/scale << ", ";
+          outfile.width(9);
+          outfile << p.Z()/scale << ") ";
+	 
+	  if(mesh[PointIndex(i)].Type() != INNERPOINT) 
+	    {
+	      BCsinpoint.DeleteAll();
+	      for (j = 1; j <= nse; j++) 
+		{
+		  for (k = 1; k <= mesh.SurfaceElement(j).GetNP(); k++) 
+		    {
+		      if(mesh.SurfaceElement(j).PNum(k)==i) 
+			{
+			  int BC=mesh.GetFaceDescriptor(mesh.SurfaceElement(j).GetIndex()).BCProperty();
+			  int nbcsp=BCsinpoint.Size();
+			  int found = 0;
+			  for (l = 1; l <= nbcsp; l++)
+			    if(BC == BCsinpoint.Get(l)) found = 1;
+			  if( ! found ) BCsinpoint.Append(BC); 	    	     
+			}
+		    }
+		}
+	      int nbcsp = BCsinpoint.Size();
+	      outfile << "[" << nbcsp << "] ";
+	      for (j = 1; j <= nbcsp; j++)
+		outfile << BCsinpoint.Get(j) << " ";
+	      outfile << "\n";
+            }
+          else outfile << "[0]\n";
+
+        }
+
+      outfile << "\n"
+	"  Element types and connectivity\n"
+	"  the columns contain:\n"
+	"   - element number\n"
+	"   - element type\n"
+	"   - subdomain number\n"
+	"   - the global node numbers of the nodes in the element.\n"
+	"#\n";
+
+      for (i = 1; i <= ne; i++)
+        {
+          const Element & el = mesh.VolumeElement(i);
+          outfile.width(5);
+          if(el.GetNP()==4)
+            outfile << i << "  ElmT4n3D ";
+          else
+            outfile << i << "  ElmT10n3D ";
+          outfile.width(4);
+          outfile << el.GetIndex() << "    ";
+          if(el.GetNP()==10)
+            {
+	      outfile.width(8);
+	      outfile << el.PNum(1);
+	      outfile.width(8);
+	      outfile << el.PNum(3);
+	      outfile.width(8);
+	      outfile << el.PNum(2);
+	      outfile.width(8);
+	      outfile << el.PNum(4);
+	      outfile.width(8);
+	      outfile << el.PNum(6);
+	      outfile.width(8);
+	      outfile << el.PNum(8);
+	      outfile.width(8);
+	      outfile << el.PNum(5);
+	      outfile.width(8);
+	      outfile << el.PNum(7);
+	      outfile.width(8);
+	      outfile << el.PNum(10);
+	      outfile.width(8);
+	      outfile << el.PNum(9);
+            }
+          else
+            {
+	      outfile.width(8);
+	      outfile << el.PNum(1);
+	      outfile.width(8);
+	      outfile << el.PNum(3);
+	      outfile.width(8);
+	      outfile << el.PNum(2);
+	      outfile.width(8);
+	      outfile << el.PNum(4);
+            }
+          outfile << "\n";
+        }
+    } /* Diffpack */
+
+  else
+
+    {
+      // Output compatible to Diffpack grid format 2D
+
+      int np = mesh.GetNP();
+      //int ne = mesh.GetNE();
+      int nse = mesh.GetNSE();
+      ARRAY <int> BIname;
+      ARRAY <int> BCsinpoint;
+      int i, j, k, l;
+
+
+      outfile.precision(6);
+      outfile.setf (ios::fixed, ios::floatfield);
+      outfile.setf (ios::showpoint);
+
+      outfile << "\n\n"
+	"Finite element mesh (GridFE):\n\n"
+	"  Number of space dim. =  2\n"
+	"  Number of elements   =  " << nse << "\n"
+	"  Number of nodes      =  " << np << "\n\n"
+	"  All elements are of the same type : dpTRUE\n"
+	"  Max number of nodes in an element: 3\n"
+	"  Only one subdomain               : dpFALSE\n"
+	"  Lattice data                     ? 0\n\n\n\n";
+      
+      for (i = 1; i <= nse; i++) 
+	{
+	  int BI=mesh.GetFaceDescriptor(mesh.SurfaceElement(i).GetIndex()).BCProperty();
+	  int nbi=BIname.Size();
+	  int found=0;
+	  for (j = 1; j <= nbi; j++)
+	    if(BI == BIname.Get(j)) found = 1;
+	  if( ! found ) BIname.Append(BI);	    	     
+	}
+      
+      outfile << "  " << BIname.Size() <<  " Boundary indicators:  ";
+      for (i =1 ; i <= BIname.Size(); i++)
+	outfile << BIname.Get(i) << " ";
+      outfile << "\n\n\n";
+      
+      outfile << "  Nodal coordinates and nodal boundary indicators,\n"
+	"  the columns contain:\n"
+	"   - node number\n"
+	"   - coordinates\n"
+	"   - no of boundary indicators that are set (ON)\n"
+	"   - the boundary indicators that are set (ON) if any.\n"
+	"#\n";
+
+      for (i = 1; i <= np; i++)
+        {
+          const Point3d & p = mesh.Point(i);
+
+          outfile.width(4);
+          outfile << i << "  (";
+          outfile.width(10);
+          outfile << p.X()/scale << ", ";
+          outfile.width(9);
+          outfile << p.Y()/scale << ", ";
+	 
+	  if(mesh[PointIndex(i)].Type() != INNERPOINT) 
+	    {
+	      BCsinpoint.DeleteAll();
+	      for (j = 1; j <= nse; j++) 
+		{
+		  for (k = 1; k <= 2; k++) 
+		    {
+		      if(mesh.SurfaceElement(j).PNum(k)==i) 
+			{
+			  int BC=mesh.GetFaceDescriptor(mesh.SurfaceElement(j).GetIndex()).BCProperty();
+			  int nbcsp=BCsinpoint.Size();
+			  int found = 0;
+			  for (l = 1; l <= nbcsp; l++)
+			    if(BC == BCsinpoint.Get(l)) found = 1;
+			  if( ! found ) BCsinpoint.Append(BC); 	    	     
+			}
+		    }
+		}
+	      int nbcsp = BCsinpoint.Size();
+	      outfile << "[" << nbcsp << "] ";
+	      for (j = 1; j <= nbcsp; j++)
+		outfile << BCsinpoint.Get(j) << " ";
+	      outfile << "\n";
+            }
+          else outfile << "[0]\n";
+
+        }
+
+      outfile << "\n"
+	"  Element types and connectivity\n"
+	"  the columns contain:\n"
+	"   - element number\n"
+	"   - element type\n"
+	"   - subdomain number\n"
+	"   - the global node numbers of the nodes in the element.\n"
+	"#\n";
+
+      for (i = 1; i <= nse; i++)
+        {
+          const Element2d & el = mesh.SurfaceElement(i);
+          outfile.width(5);
+          outfile << i << "  ElmT3n2D ";
+          outfile.width(4);
+          outfile << el.GetIndex() << "    ";
+	  outfile.width(8);
+	  outfile << el.PNum(1);
+	  outfile.width(8);
+	  outfile << el.PNum(3);
+	  outfile.width(8);
+	  outfile << el.PNum(2);
+          outfile << "\n";
+        }
+    }
+}
+}
diff --git a/contrib/Netgen/libsrc/interface/writedolfin.cpp b/contrib/Netgen/libsrc/interface/writedolfin.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..0fe36e94af8b45a9a49058967c262283968cf92b
--- /dev/null
+++ b/contrib/Netgen/libsrc/interface/writedolfin.cpp
@@ -0,0 +1,69 @@
+//
+//  Write dolfin file
+//
+//  by
+//  Kent-Andre Mardal <kent-and@simula.no>
+
+
+#include <mystdlib.h>
+
+#include <myadt.hpp>
+#include <linalg.hpp>
+#include <csg.hpp>
+#include <meshing.hpp>
+
+namespace netgen
+{
+
+#include "writeuser.hpp"
+
+
+
+  void WriteDolfinFormat (const Mesh & mesh, const string & filename)
+  {
+    cout << "start writing dolfin export" << endl;
+
+    int np = mesh.GetNP();
+    int ne = mesh.GetNE();
+    int nse = mesh.GetNSE();
+    int nsd = mesh.GetDimension(); 
+    int invertsurf = mparam.inverttrigs;
+    int i, j;
+
+    ofstream outfile (filename.c_str());
+
+    char str[100];
+    outfile.precision(8);
+    outfile.setf (ios::fixed, ios::floatfield);
+    outfile.setf (ios::showpoint);
+
+    if ( nsd == 3) {
+
+      outfile << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" <<endl; 
+      outfile << ""<<endl; 
+
+      outfile << "<dolfin xmlns:dolfin=\"http://www.phi.chalmers.se/dolfin/\">"<<endl;
+      outfile << "  <mesh celltype=\"tetrahedron\" dim=\"3\">" <<endl; 
+      outfile << "      <vertices size=\""<<np<<"\">"<<endl; 
+      for (i = 1; i <= np; i++) { 
+        const Point3d & p = mesh.Point(i);
+        outfile << "      <vertex index=\""<<i-1<<"\" x=\""<<p.X()<<"\" y=\""<<p.Y()<<"\" z=\""<<p.Z()<<"\"/>"<<endl; 
+      }
+      outfile << "      </vertices>"<<endl; 
+
+
+
+      outfile << "      <cells size=\""<<ne<<"\">"<<endl; 
+      for (i = 1; i <= ne; i++) {
+        const Element & el = mesh.VolumeElement(i);
+
+        outfile << "      <tetrahedron index=\""<<i-1<<"\" v0=\""<<el.PNum(1)-1<<"\" v1=\""<<el.PNum(2)-1<<"\" v2=\""<<el.PNum(3)-1<<"\" v3=\""<<el.PNum(4)-1<<"\"/>"<<endl; 
+      }
+      outfile << "      </cells>"<<endl; 
+    }
+    outfile << "   </mesh>"<<endl; 
+    outfile << "</dolfin>"<<endl; 
+
+    cout << "done writing dolfin export" << endl;
+  }
+}
diff --git a/contrib/Netgen/libsrc/interface/writeelmer.cpp b/contrib/Netgen/libsrc/interface/writeelmer.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..f902cdeb23c1ee06e0f74ed92c4344d381eb1822
--- /dev/null
+++ b/contrib/Netgen/libsrc/interface/writeelmer.cpp
@@ -0,0 +1,131 @@
+
+//
+//  Write Elmer file
+//
+//
+
+#include <mystdlib.h>
+
+#include <myadt.hpp>
+#include <linalg.hpp>
+#include <csg.hpp>
+#include <meshing.hpp>
+#include <sys/stat.h>
+
+
+namespace netgen
+{
+#include "writeuser.hpp"
+
+
+
+void WriteElmerFormat (const Mesh &mesh,
+			 const string &filename)
+{
+  cout << "write elmer mesh files" << endl;
+  int np = mesh.GetNP();
+  int ne = mesh.GetNE();
+  int nse = mesh.GetNSE();
+  int i, j;
+  char str[200];
+  
+  int inverttets = mparam.inverttets;
+  int invertsurf = mparam.inverttrigs;
+
+#ifdef WIN32
+  char a[256];
+  sprintf( a, "mkdir %s", filename.c_str() );
+  system( a );
+#else
+  int rc = mkdir(filename.c_str(), S_IRWXU|S_IRWXG);
+#endif
+
+  sprintf( str, "%s/mesh.header", filename.c_str() );
+  ofstream outfile_h(str);
+  sprintf( str, "%s/mesh.nodes", filename.c_str() );
+  ofstream outfile_n(str);
+  sprintf( str, "%s/mesh.elements", filename.c_str() );
+  ofstream outfile_e(str);
+  sprintf( str, "%s/mesh.boundary", filename.c_str() );
+  ofstream outfile_b(str);
+
+  // fill hashtable
+
+  INDEX_3_HASHTABLE<int> face2volelement(ne);
+
+  for (i = 1; i <= ne; i++)
+    {
+      const Element & el = mesh.VolumeElement(i);
+      INDEX_3 i3;
+      int k, l;
+      for (j = 1; j <= 4; j++)   // loop over faces of tet
+	{
+	  l = 0;
+	  for (k = 1; k <= 4; k++)
+	    if (k != j)
+	      {
+		l++;
+		i3.I(l) = el.PNum(k);
+	      }
+	  i3.Sort();
+	  face2volelement.Set (i3, i);
+	}
+    }
+
+//  outfile.precision(6);
+//  outfile.setf (ios::fixed, ios::floatfield);
+//  outfile.setf (ios::showpoint);
+  
+  outfile_h << np << " " << ne << " " << nse << "\n";
+  outfile_h << "2"     << "\n";
+  outfile_h << "303 " << nse << "\n";
+  outfile_h << "504 " << ne << "\n";
+  
+  for (i = 1; i <= np; i++)
+    {
+      const Point3d & p = mesh.Point(i);
+      
+      outfile_n << i << " -1 ";
+      outfile_n << p.X() << " ";
+      outfile_n << p.Y() << " ";
+      outfile_n << p.Z() << "\n";
+    }
+
+  for (i = 1; i <= ne; i++)
+    {
+      Element el = mesh.VolumeElement(i);
+      if (inverttets) el.Invert();
+      sprintf( str, "5%02d", (int)el.GetNP() );
+      outfile_e << i << " " << el.GetIndex() << " " << str <<  "  ";
+      for (j = 1; j <= el.GetNP(); j++)
+	{
+	  outfile_e << " ";
+	  outfile_e << el.PNum(j);
+	}
+      outfile_e << "\n";
+    }
+
+  for (i = 1; i <= nse; i++)
+    {
+      Element2d el = mesh.SurfaceElement(i);
+      if (invertsurf) el.Invert();
+      sprintf( str, "3%02d", (int)el.GetNP() );
+      {
+	  INDEX_3 i3;
+	  for (j = 1; j <= 3; j++) i3.I(j) = el.PNum(j);
+	  i3.Sort();
+	  
+	  int elind = face2volelement.Get(i3);
+          outfile_b << i << " " << mesh.GetFaceDescriptor(el.GetIndex()).BCProperty() << 
+         " " << elind << " 0 "  << str << "    ";
+      }
+      for (j = 1; j <= el.GetNP(); j++)
+	{
+	  outfile_b << " ";
+	  outfile_b << el.PNum(j);
+	}
+      outfile_b << "\n";
+    }
+}
+
+}
diff --git a/contrib/Netgen/libsrc/interface/writefeap.cpp b/contrib/Netgen/libsrc/interface/writefeap.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..85681aa0cf63d1ad1186864a8aefaf4f01aa5bb8
--- /dev/null
+++ b/contrib/Netgen/libsrc/interface/writefeap.cpp
@@ -0,0 +1,220 @@
+//
+// Write FEAP file
+// FEAP by Bob Taylor, Berkely
+//
+// contact Peter Wriggers or Albrecht Rieger, Hannover
+// rieger@ibnm.uni-hannover.de
+//
+
+#include <mystdlib.h>
+
+#include <myadt.hpp>
+#include <linalg.hpp>
+#include <csg.hpp>
+#include <meshing.hpp>
+
+namespace netgen
+{
+
+#include "writeuser.hpp"
+
+
+void WriteFEAPFormat (const Mesh & mesh,
+		      const string & filename)
+  
+{
+  // Feap format by A. Rieger 
+  // rieger@ibnm.uni-hannover.de
+
+  int inverttets = mparam.inverttets;
+  //int invertsurf = mparam.inverttrigs;
+
+  int i, j;
+
+  double scale = 1;   // globflags.GetNumFlag ("scale", 1);
+  
+  ofstream outfile(filename.c_str());
+ 
+  outfile << "feap" << "\n";
+  outfile << mesh.GetNP();
+  outfile << ",";
+  outfile << mesh.GetNE();
+  outfile << ",";
+  outfile << "1,3,3,4" << "\n" << "\n"; 
+  outfile << "!numnp,numel,nummat,ndm,ndf,nen";
+  outfile << "\n";
+      
+  outfile << "\n" << "\n";
+  outfile << "!node,,         X           Y           Z" << "\n";
+  outfile << "COOR" << "\n";
+  outfile.precision(4);
+  outfile.setf (ios::fixed, ios::floatfield);
+  outfile.setf (ios::showpoint);
+
+  for (i = 1; i <= mesh.GetNP(); i++)
+    {
+      outfile.width(5);
+      outfile << i;
+      outfile << ",,";
+      outfile.width(10);
+      outfile << mesh.Point(i)(0)/scale << "  ";
+      outfile.width(10);
+      outfile << mesh.Point(i)(1)/scale << "  ";
+      outfile.width(10);
+      outfile << mesh.Point(i)(2)/scale << "\n";
+    }   
+      
+  outfile << "\n" << "\n";
+  outfile << "!elm,,mat,     n1      n2      n3      n4" << "\n";
+  outfile << "ELEM" << "\n";
+
+  for (i = 1; i <= mesh.GetNE(); i++)
+    {
+      Element el = mesh.VolumeElement(i);
+      if (inverttets)
+	el.Invert();
+
+
+      outfile.width(5);
+      outfile << i;
+      outfile << ",,";
+      outfile << el.GetIndex();
+      outfile << ",";
+
+
+      for (j = 1; j <= el.NP(); j++)
+	{
+	  outfile.width(8);
+	  outfile << el.PNum(j);
+	}
+      outfile << "\n";
+    }
+      
+  outfile << "\n" << "\n";
+      
+      
+  /*
+
+  //outfile << "SLOA" << "\n";
+  //outfile << "2,3,3" << "\n";
+  //outfile << GetNSE() << "\n";
+  outfile << "selm" << "\n" << GetNSE() << "\n";
+  for (i = 1; i <= GetNSE(); i++)
+  {
+  if (SurfaceElement(i).GetIndex())
+  {
+  outfile.width(8);
+  outfile << facedecoding.Get(SurfaceElement(i).GetIndex ()).surfnr;
+  //outfile.width(8);	  
+  //outfile << facedecoding.Get(SurfaceElement(i).GetIndex ()).domin;
+  //outfile.width(8);	  
+  //outfile << facedecoding.Get(SurfaceElement(i).GetIndex ()).domout;
+  }
+  else
+  outfile << "       0       0       0";
+  
+  
+  Element2d sel = SurfaceElement(i);
+  if (invertsurf)
+  sel.Invert();
+  //outfile.width(8);
+  //outfile << sel.GetNP();
+  //if (facedecoding.Get(SurfaceElement(i).GetIndex ()).surfnr == 4)
+  //{
+  for (j = 1; j <= sel.GetNP(); j++)
+  {
+  outfile.width(8);	  
+  outfile << sel.PNum(j);
+  }
+  //outfile.width(8);	
+  //outfile << "0.0";
+  //outfile.width(8);	
+  //outfile << "0.0";
+  //outfile.width(8);	
+  //outfile << "1.0" << "\n";
+  //}
+  outfile << "\n";
+  //outfile << endl;
+  }
+  */
+
+
+
+  // BEGIN CONTACT OUTPUT
+  /*      
+	  int masterindex, slaveindex;
+	  cout << "Master Surface index = ";
+	  cin >> masterindex;
+	  cout << "Slave Surface index  = ";
+	  cin >> slaveindex;
+
+
+	  // CONTACT SURFACE 1
+	  outfile << "\n";
+	  outfile << "\n";
+	  outfile << "surface,1" << "\n";;
+	  outfile.width(6);
+	  outfile << "tria" << "\n";;
+	  outfile.width(13);
+	  outfile << "facet" << "\n";;
+	  zz = 0;
+	  for (i = 1; i <= mesh.GetNSE(); i++)
+	  {
+	  Element2d sel = mesh.SurfaceElement(i);
+	  if (invertsurf)
+	  sel.Invert();
+	  if (mesh.GetFaceDescriptor(sel.GetIndex ()).BCProperty() == masterindex)
+	  {
+	  zz++;
+	  outfile.width(14);
+	  outfile << zz;
+	  outfile << ",,";
+	  for (j = 1; j <= sel.GetNP(); j++)
+	  {
+	  outfile << sel.PNum(j);
+	  outfile << ",";
+	  }
+	  outfile << "\n";
+	  }
+	  }
+
+
+	  // CONTACT SURFACE 2
+	  outfile << "\n";
+	  outfile << "\n";
+	  outfile << "surface,2" << "\n";;
+	  outfile.width(6);
+	  outfile << "tria" << "\n";;
+	  outfile.width(13);
+	  outfile << "facet" << "\n";;
+	  zz = 0;
+	  for (i = 1; i <= mesh.GetNSE(); i++)
+	  {
+	  
+	  Element2d sel = mesh.SurfaceElement(i);
+	  if (invertsurf)
+	  sel.Invert();
+	  if (mesh.GetFaceDescriptor(sel.GetIndex ()).BCProperty() == slaveindex)
+	  {
+	  zz++;
+	  outfile.width(14);
+	  outfile << zz;
+	  outfile << ",,";
+	  for (j = 1; j <= sel.GetNP(); j++)
+	  {
+	  outfile << sel.PNum(j);
+	  outfile << ",";
+	  }
+	  outfile << "\n";
+	  }
+	  }
+      
+	  outfile << "\n";
+	  outfile << "\n";
+  */      
+      
+  // END CONTACT OUTPUT
+
+  cout << "done" << endl;
+}
+}
diff --git a/contrib/Netgen/libsrc/interface/writefluent.cpp b/contrib/Netgen/libsrc/interface/writefluent.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..5c08d59857596c0f38d2b2217db91b15b69600f2
--- /dev/null
+++ b/contrib/Netgen/libsrc/interface/writefluent.cpp
@@ -0,0 +1,193 @@
+//
+//  Write Fluent file
+//  Johannes Gerstmayr, University Linz
+//
+
+#include <mystdlib.h>
+
+#include <myadt.hpp>
+#include <linalg.hpp>
+#include <csg.hpp>
+#include <meshing.hpp>
+
+namespace netgen
+{
+
+#include "writeuser.hpp"
+
+
+
+void WriteFluentFormat (const Mesh & mesh,
+			const string & filename)
+
+{
+  cout << "start writing fluent export" << endl;
+      
+  int np = mesh.GetNP();
+  int ne = mesh.GetNE();
+  int nse = mesh.GetNSE();
+  int i, j;
+
+  ofstream outfile (filename.c_str());
+  char str[100];
+
+  outfile.precision(6);
+  //outfile.setf (ios::fixed, ios::floatfield);
+  //outfile.setf (ios::showpoint);
+      
+  outfile << "(0 \"Exported file from NETGEN \")" << endl;
+  outfile << "(0 \"Dimension:\")" << endl;
+  outfile << "(2 3)" << endl << endl;
+
+  outfile << "(0 \"Nodes:\")" << endl;
+
+  //number of nodes:
+  sprintf(str,"(10 (0 1 %x 1))",np); //hexadecimal!!!
+  outfile << str << endl;
+
+  //nodes of zone 1:
+  sprintf(str,"(10 (7 1 %x 1)(",np); //hexadecimal!!!
+  outfile << str << endl;
+  for (i = 1; i <= np; i++)
+    {
+      const Point3d & p = mesh.Point(i);
+
+      //outfile.width(10);
+      outfile << p.X() << " ";
+      outfile << p.Y() << " ";
+      outfile << p.Z() << "\n";
+    }
+  outfile << "))" << endl << endl;
+
+  //write faces with elements
+
+  outfile << "(0 \"Faces:\")" << endl;
+
+  Element2d face, face2;
+  int i2, j2;
+  ARRAY<INDEX_3> surfaceelp;
+  ARRAY<int> surfaceeli;
+  ARRAY<int> locels;
+
+  //no cells=no tets
+  //no faces=2*tets
+
+  int noverbface = 2*ne-nse/2;
+      
+  sprintf(str,"(13 (0 1 %x 0))",(noverbface+nse)); //hexadecimal!!!
+  outfile << str << endl;
+      
+  sprintf(str,"(13 (4 1 %x 2 3)(",noverbface); //hexadecimal!!!
+  outfile << str << endl;
+
+  const_cast<Mesh&> (mesh).BuildElementSearchTree();
+
+  for (i = 1; i <= ne; i++)
+    {
+      if (ne > 2000)
+	{
+	  if (i%2000 == 0)
+	    {
+	      cout << (double)i/(double)ne*100. << "%" << endl;
+	    }
+	}
+
+      Element el = mesh.VolumeElement(i);
+      //if (inverttets)
+      //  el.Invert();
+	  
+      //outfile << el.GetIndex() << "    ";
+      if (el.GetNP() != 4) {cout << "only tet-meshes supported in write fluent!" << endl;}
+	  
+      //faces:
+	  
+      Box3d box;
+      el.GetBox(mesh.Points(), box);
+      box.IncreaseRel(1e-6);
+
+      mesh.GetIntersectingVolEls(box.PMin(),box.PMax(),locels);
+      int nel = locels.Size();
+      int locind;
+
+      //cout << "nel=" << nel << endl;
+
+      for (j = 1; j <= el.GetNFaces(); j++)
+	{
+	  el.GetFace(j, face);
+	  face.Invert();
+	  int eli2 = 0;
+	  int stopsig = 0;
+	      
+	  for (i2 = 1; i2 <= nel; i2++)
+	    {
+	      locind = locels.Get(i2);
+	      //cout << "  locind=" << locind << endl;
+
+	      Element el2 = mesh.VolumeElement(locind);
+	      //if (inverttets)
+	      //  el2.Invert();
+
+	      for (j2 = 1; j2 <= el2.GetNFaces(); j2++)
+		{
+		  el2.GetFace(j2, face2);
+
+		  if (face2.HasFace(face)) {eli2 = locind; stopsig = 1; break;}
+		}
+	      if (stopsig) break;
+	    }
+	      
+	  if (eli2==i) cout << "error in WRITE_FLUENT!!!" << endl;
+	      
+	  if (eli2 > i) //dont write faces two times!
+	    {
+	      //i: left cell, eli: right cell
+	      outfile << hex << face.PNum(2) << " "
+		<< hex << face.PNum(1) << " "
+		<< hex << face.PNum(3) << " "
+		<< hex << i  << " "
+		<< hex << eli2 << "\n";
+	    }
+	  if (eli2 == 0) 
+	    {
+	      surfaceelp.Append(INDEX_3(face.PNum(2),face.PNum(1),face.PNum(3)));
+	      surfaceeli.Append(i);
+	    }
+	}
+    }
+  outfile << "))" << endl;
+      
+  sprintf(str,"(13 (2 %x %x 3 3)(",(noverbface+1),noverbface+nse); //hexadecimal!!!
+  outfile << str << endl;
+
+  for (i = 1; i <= surfaceelp.Size(); i++)
+    {
+      outfile << hex << surfaceelp.Get(i).I1() << " "
+	      << hex << surfaceelp.Get(i).I2() << " "
+	      << hex << surfaceelp.Get(i).I3() << " "
+	      << hex << surfaceeli.Get(i) << " " << 0 << "\n";
+    }
+
+  outfile << "))" << endl << endl;
+
+  outfile << "(0 \"Cells:\")" << endl;
+      
+  sprintf(str,"(12 (0 1 %x 0))",ne); //hexadecimal!!!
+  outfile << str << endl;
+
+  sprintf(str,"(12 (1 1 %x 1 2))",ne); //hexadecimal!!!
+  outfile << str << endl << endl;
+
+
+
+
+  outfile << "(0 \"Zones:\")\n"
+	  << "(45 (1 fluid fluid)())\n"
+    //      << "(45 (2 velocity-inlet velocity_inlet.1)())\n"
+    //      << "(45 (3 pressure-outlet pressure_outlet.2)())\n"
+	  << "(45 (2 wall wall)())\n"
+	  << "(45 (4 interior default-interior)())\n" << endl;
+
+  cout << "done" << endl;
+}
+
+}
diff --git a/contrib/Netgen/libsrc/interface/writegmsh.cpp b/contrib/Netgen/libsrc/interface/writegmsh.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..93def677835846f85917ccf3243f841e8d9480e6
--- /dev/null
+++ b/contrib/Netgen/libsrc/interface/writegmsh.cpp
@@ -0,0 +1,200 @@
+/*************************************
+ * Write Gmsh file
+ * First issue the 04/26/2004 by Paul CARRICO (paul.carrico@free.fr)
+ * At the moment, the GMSH format is available for
+ * linear tetrahedron elements i.e. in 3D
+ * (based on Neutral Format)
+ *
+ * Second issue the 05/05/2004 by Paul CARRICO
+ * Thanks to Joachim Schoeberl for the correction of a minor bug
+ * the 2 initial Gmsh Format (i.e. volume format and surface format) are group together)
+ * in only one file
+ **************************************/
+
+#include <mystdlib.h>
+
+#include <myadt.hpp>
+#include <linalg.hpp>
+#include <csg.hpp>
+#include <meshing.hpp>
+
+namespace netgen
+{
+#include "writeuser.hpp"
+
+
+
+/*
+ *  GMSH mesh format
+ *  points, elements, surface elements and physical entities
+ */
+
+void WriteGmshFormat (const Mesh & mesh,
+			 const CSGeometry & geom,
+			 const string & filename)
+{
+  ofstream outfile (filename.c_str());
+  outfile.precision(6);
+  outfile.setf (ios::fixed, ios::floatfield);
+  outfile.setf (ios::showpoint);
+
+  int np = mesh.GetNP();  /// number of point
+  int ne = mesh.GetNE();  /// number of element
+  int nse = mesh.GetNSE();  /// number of surface element (BC)
+  int i, j, k, l;
+
+
+  /*
+   * 3D section : Linear volume elements (only tetrahedra)
+   */
+
+   if (ne > 0 && mesh.VolumeElement(1).GetNP() == 4)
+      {
+      cout << "Write GMSH Format \n";
+      cout << "The GMSH format is available for linear tetrahedron elements only in 3D\n" << endl;
+
+      int inverttets = mparam.inverttets;
+      int invertsurf = mparam.inverttrigs;
+
+
+      /// Write nodes
+      outfile << "$NOD\n";
+      outfile << np << "\n";
+  
+      for (i = 1; i <= np; i++)
+          {
+          const Point3d & p = mesh.Point(i);
+          outfile << i << " "; /// node number
+          outfile << p.X() << " ";
+          outfile << p.Y() << " ";
+          outfile << p.Z() << "\n";
+          }
+      outfile << "$ENDNOD\n";
+
+      /// write elements
+      outfile << "$ELM\n";
+      outfile << ne + nse << "\n";  ////  number of elements + number of surfaces BC
+
+     for (i = 1; i <= nse; i++)
+         {
+         Element2d el = mesh.SurfaceElement(i);
+         if (invertsurf) el.Invert();
+         outfile << i;
+         outfile << " ";
+         outfile << "2";
+         outfile << " ";
+         outfile << mesh.GetFaceDescriptor (el.GetIndex()).BCProperty() << " ";
+         /// that means that physical entity = elementary entity (arbitrary approach)
+         outfile << mesh.GetFaceDescriptor (el.GetIndex()).BCProperty() << " ";
+         outfile << "3";
+         outfile << " ";
+                 for (j = 1; j <= el.GetNP(); j++)
+                     {
+                     outfile << " ";
+                     outfile << el.PNum(j);
+                     }
+                     outfile << "\n";
+         }
+
+
+         for (i = 1; i <= ne; i++)
+             {
+             Element el = mesh.VolumeElement(i);
+             if (inverttets) el.Invert();
+             outfile << nse + i; /// element number
+             outfile << " ";
+             outfile << "4"; /// element type i.e. Tetraedron == 4
+             outfile << " ";
+             outfile << 100000 + el.GetIndex();
+             /// that means that physical entity = elementary entity (arbitrary approach)
+             outfile << " ";
+             outfile << 100000 + el.GetIndex();   /// volume number
+             outfile << " ";
+             outfile << "4";  /// number of nodes i.e. 4 for a tetrahedron
+                                                                                                        
+             for (j = 1; j <= el.GetNP(); j++)
+                 {
+                 outfile << " ";
+                 outfile << el.PNum(j);
+                 }
+             outfile << "\n";
+             }
+
+
+             outfile << "$ENDELM\n";
+   }
+
+   /*
+    * End of 3D section
+    */
+
+
+
+
+
+  /*
+   * 2D section : available for triangles and quadrangles
+   */
+      else if (ne == 0)   /// means that there's no 3D element
+              {
+              cout << "\n Write Gmsh Surface Mesh (triangle and/or quadrangles)" << endl;
+
+              /// Write nodes
+              outfile << "$NOD\n";
+              outfile << np << "\n";
+
+              for (i = 1; i <= np; i++)
+              {
+              const Point3d & p = mesh.Point(i);
+              outfile << i << " "; /// node number
+              outfile << p.X() << " ";
+              outfile << p.Y() << " ";
+              outfile << p.Z() << "\n";
+              }
+              outfile << "$ENDNOD\n";
+
+
+              /// write triangles & quadrangles
+              outfile << "$ELM\n";
+              outfile << nse << "\n";
+
+              for (k = 1; k <= nse; k++)
+              {
+              const Element2d & el = mesh.SurfaceElement(k);
+
+
+              outfile << k;
+              outfile << " ";
+              outfile << (el.GetNP()-1);   // 2 for a triangle and 3 for a quadrangle
+              outfile << " ";
+              outfile << mesh.GetFaceDescriptor (el.GetIndex()).BCProperty() << " ";
+              /// that means that physical entity = elementary entity (arbitrary approach)
+              outfile << mesh.GetFaceDescriptor (el.GetIndex()).BCProperty() << " ";
+              outfile << (el.GetNP());    // number of node per surfacic element
+              outfile << " ";
+
+              for (l = 1; l <= el.GetNP(); l++)
+                  {
+                  outfile << " ";
+                  outfile << el.PNum(l);
+                  }
+	              outfile << "\n";
+		  
+               }
+               outfile << "$ENDELM$ \n";
+    }
+
+   /*
+    * End of 2D section
+    */
+
+     else
+    {
+    cout << " Invalide element type for Gmsh volume Format !\n";
+    }
+
+
+}
+}
+
+
diff --git a/contrib/Netgen/libsrc/interface/writejcm.cpp b/contrib/Netgen/libsrc/interface/writejcm.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..00ef4f9f49a3dc36d74b38ee51250defb4804672
--- /dev/null
+++ b/contrib/Netgen/libsrc/interface/writejcm.cpp
@@ -0,0 +1,430 @@
+//
+//  Write JCMwave file
+//  07.07.2005, Sven Burger, ZIB Berlin
+//
+
+
+#include <mystdlib.h>
+#include <myadt.hpp>
+#include <linalg.hpp>
+#include <csg.hpp>
+#include <meshing.hpp>
+#include <sys/stat.h>
+
+namespace netgen
+{
+#include "writeuser.hpp"
+
+void WriteJCMFormat (const Mesh & mesh,
+                     const CSGeometry & geom,
+                     const string & filename)
+{
+  if (mesh.GetDimension() != 3)
+  {
+    cout <<"\n Error: Dimension 3 only supported by this output format!"<<endl;
+    return;
+  }
+
+  int bc_at_infinity = 0;
+  int i, j, jj, ct(0), counter;
+  double dx1, dx2, dx3, dy1, dy2, dy3, dz1, dz2, dz3, vol;
+
+  // number of points
+  int np = mesh.GetNP();
+
+  // Identic points
+  ARRAY<int,1> identmap1, identmap2, identmap3;
+  mesh.GetIdentifications().GetMap(1, identmap1);
+  mesh.GetIdentifications().GetMap(2, identmap2);
+  mesh.GetIdentifications().GetMap(3, identmap3);
+
+  // number of volume elements
+  int ne = mesh.GetNE();
+  int ntets = 0;
+  int nprisms = 0;
+  for (i = 1; i <= ne; i++)
+  {
+    Element el = mesh.VolumeElement(i);
+    if (el.GetNP() == 4)
+    {
+      ntets++;
+      // Check that no two points on a tetrahedron are identified with each other
+      for (j = 1; j <= 4; j++)
+        for (jj = 1; jj <=4; jj++)
+        {
+          if (identmap1.Elem(el.PNum(j)) == el.PNum(jj))
+          {
+            cout << "\n Error: two points on a tetrahedron identified (1) with each other"
+                 << "\n REFINE MESH !" << endl;
+            return;
+          }
+          if (identmap2.Elem(el.PNum(j)) == el.PNum(jj))
+          {
+            cout << "\n Error: two points on a tetrahedron identified (2) with each other"
+                 << "\n REFINE MESH !" << endl;
+            return;
+          }
+          if (identmap3.Elem(el.PNum(j)) == el.PNum(jj))
+          {
+            cout << "\n Error: two points on a tetrahedron identified (3) with each other"
+                 << "\n REFINE MESH !" << endl;
+            return;
+          }
+        }      
+      
+    }
+    else if (el.GetNP() == 6)
+      nprisms++;
+  }
+  if ( ne != (ntets+nprisms))
+  {
+    cout<< "\n Error in determining number of volume elements!\n"
+        << "\n Prisms and tetrahedra only implemented in the JCMwave format!\n"<<endl;
+    return;
+  }
+
+  if (nprisms > 0)
+    cout << " Please note: Boundaries at infinity have to carry the bc-attribute '-bc="
+         << bc_at_infinity <<"'."<<endl; 
+
+  // number of surface elements
+  int nse = mesh.GetNSE();
+  // number of boundary triangles
+  int nbtri = 0;
+  // number of boundary quadrilaterals
+  int nbquad = 0;
+  // array with 1 if point on any tetra, 0 else 
+  // this is needed in order to arrange the prism points in the right order
+  ARRAY<int,1> pointsOnTetras;
+  pointsOnTetras.SetSize (mesh.GetNP());
+  pointsOnTetras = 0;
+  for (i = 1; i <= ne; i++)
+  {
+    Element el = mesh.VolumeElement(i);
+    if (el.GetNP() == 4)
+    {
+      for (j = 1; j <= 4; j++)
+        pointsOnTetras.Set(el.PNum(j).GetInt(),1);     
+    }
+  }
+
+  // number of boundary triangles and boundary quadrilaterals
+  for (i = 1; i <= nse; i++)
+  {
+    Element2d el = mesh.SurfaceElement(i);
+    if (el.GetNP() == 3 &&
+        ( mesh.GetFaceDescriptor (el.GetIndex()).DomainIn()==0  ||
+          mesh.GetFaceDescriptor (el.GetIndex()).DomainOut()==0 ) )
+      nbtri++;
+    else if (el.GetNP() == 4 &&
+             ( mesh.GetFaceDescriptor (el.GetIndex()).DomainIn()==0 ||
+               mesh.GetFaceDescriptor (el.GetIndex()).DomainOut()==0 ) )
+      nbquad++;
+  }
+  
+  ofstream outfile (filename.c_str());
+  outfile.precision(6);
+  outfile.setf (ios::fixed, ios::floatfield);
+  outfile.setf (ios::showpoint);
+  
+  outfile << "/* <BLOBHead>\n";
+  outfile << "__BLOBTYPE__=Grid\n";
+  outfile << "__OWNER__=JCMwave\n";
+  outfile << "<I>SpaceDim=3\n";
+  outfile << "<I>ManifoldDim=3\n";
+  outfile << "<I>NRefinementSteps=0\n";
+  outfile << "<I>NPoints="<<np<<"\n";
+  outfile << "<I>NTetrahedra="<<ntets<<"\n";
+  outfile << "<I>NPrisms="<<nprisms<<"\n";
+  outfile << "<I>NBoundaryTriangles="<<nbtri<<"\n";
+  outfile << "<I>NBoundaryQuadrilaterals="<<nbquad<<"\n";
+  outfile << "*/\n";
+  outfile << "\n";
+  outfile << "# output from Netgen\n\n";
+  int nDomains=mesh.GetNDomains();
+  for (i=1; i<=nDomains; i++)
+  {
+    if (mesh.GetMaterial(i))
+      outfile << "#" << mesh.GetMaterial(i) 
+              << ": Material ID = " 
+              << i << "\n";
+  }
+
+  outfile << "# Points\n";
+  cout << " Please note: The unit of length in the .geo file is assumed to be 'microns'."<<endl; 
+  for (i = 1; i <= np; i++)
+  {
+    const Point<3> & p = mesh.Point(i);
+    outfile << i << "\n";
+    outfile << p(0) << "e-6\n";
+    outfile << p(1) << "e-6\n";
+    outfile << p(2) << "e-6\n\n";
+  }
+
+  outfile << "\n";
+  outfile << "# Tetrahedra\n";
+  counter = 0;
+  for (i = 1; i <= ne; i++)
+  {
+    Element el = mesh.VolumeElement(i);
+    if (el.GetNP() == 4)
+    {
+      counter++;
+      dx1 = mesh.Point(el.PNum(2))(0) - mesh.Point(el.PNum(1))(0);
+      dx2 = mesh.Point(el.PNum(3))(0) - mesh.Point(el.PNum(1))(0);
+      dx3 = mesh.Point(el.PNum(4))(0) - mesh.Point(el.PNum(1))(0);
+      dy1 = mesh.Point(el.PNum(2))(1) - mesh.Point(el.PNum(1))(1);
+      dy2 = mesh.Point(el.PNum(3))(1) - mesh.Point(el.PNum(1))(1);
+      dy3 = mesh.Point(el.PNum(4))(1) - mesh.Point(el.PNum(1))(1);
+      dz1 = mesh.Point(el.PNum(2))(2) - mesh.Point(el.PNum(1))(2);
+      dz2 = mesh.Point(el.PNum(3))(2) - mesh.Point(el.PNum(1))(2);
+      dz3 = mesh.Point(el.PNum(4))(2) - mesh.Point(el.PNum(1))(2);
+      vol = (dy1*dz2-dz1*dy2)*dx3 + (dz1*dx2-dx1*dz2)*dy3 + (dx1*dy2-dy1*dx2)*dz3;
+
+      if ( vol > 0 )
+        for (j = 1; j <= 4; j++)
+          outfile << el.PNum(j)<<"\n";
+      else
+      {
+        for (j = 2; j >= 1; j--)
+          outfile << el.PNum(j)<<"\n";
+        for (j = 3; j <= 4; j++)
+          outfile << el.PNum(j)<<"\n";
+      }  
+      outfile << el.GetIndex() << "\n\n";
+    }
+  }
+  if ( counter != ntets)
+  {
+    cout<< "\n Error in determining number of tetras!\n"<<endl;
+    return;
+  }
+
+  outfile << "\n";
+  outfile << "# Prisms\n";
+  counter = 0;
+  for (i = 1; i <= ne; i++)
+  {
+    Element el = mesh.VolumeElement(i);
+    if (el.GetNP() == 6)
+    {
+      counter++;
+      dx1 = mesh.Point(el.PNum(2))(0) - mesh.Point(el.PNum(1))(0);
+      dx2 = mesh.Point(el.PNum(3))(0) - mesh.Point(el.PNum(1))(0);
+      dx3 = mesh.Point(el.PNum(4))(0) - mesh.Point(el.PNum(1))(0);
+      dy1 = mesh.Point(el.PNum(2))(1) - mesh.Point(el.PNum(1))(1);
+      dy2 = mesh.Point(el.PNum(3))(1) - mesh.Point(el.PNum(1))(1);
+      dy3 = mesh.Point(el.PNum(4))(1) - mesh.Point(el.PNum(1))(1);
+      dz1 = mesh.Point(el.PNum(2))(2) - mesh.Point(el.PNum(1))(2);
+      dz2 = mesh.Point(el.PNum(3))(2) - mesh.Point(el.PNum(1))(2);
+      dz3 = mesh.Point(el.PNum(4))(2) - mesh.Point(el.PNum(1))(2);
+      vol = (dy1*dz2-dz1*dy2)*dx3 + (dz1*dx2-dx1*dz2)*dy3 + (dx1*dy2-dy1*dx2)*dz3;
+
+      if (pointsOnTetras.Get(el.PNum(1)) &&
+          pointsOnTetras.Get(el.PNum(2)) &&
+          pointsOnTetras.Get(el.PNum(3)))
+      {
+        if (vol > 0)
+          for (j = 1; j <= 6; j++)
+            outfile << el.PNum(j)<<"\n";
+        else
+        {
+          for (j = 3; j >= 1; j--)
+            outfile << el.PNum(j)<<"\n";
+          for (j = 6; j >= 4; j--)
+            outfile << el.PNum(j)<<"\n";
+        }
+      }
+      else if ( pointsOnTetras.Get(el.PNum(4)) &&
+                pointsOnTetras.Get(el.PNum(5)) &&
+                pointsOnTetras.Get(el.PNum(6))    )
+      {
+        if ( vol < 0 )
+        {
+          for (j = 4; j <= 6; j++)
+            outfile << el.PNum(j)<<"\n";
+          for (j = 1; j <= 3; j++)
+            outfile << el.PNum(j)<<"\n";
+        }
+        else
+        {
+          for (j = 6; j >= 4; j--)
+            outfile << el.PNum(j)<<"\n";
+          for (j = 3; j >= 1; j--)
+            outfile << el.PNum(j)<<"\n";
+        }
+      }
+      else 
+      {
+        cout << "\n Error in determining prism point numbering!\n"<<endl;
+        return;
+      }
+      outfile << el.GetIndex() << "\n\n";
+    }
+  }
+  if ( counter != nprisms)
+  {
+    cout<< "\n Error in determining number of prisms!\n"<<endl;
+    return;
+  }
+
+  int npid1 = 0;
+  int npid2 = 0;
+  int npid3 = 0;
+  for (i=1; i<=np; i++)
+  {
+    if (identmap1.Elem(i))
+      npid1++;
+    if (identmap2.Elem(i))
+      npid2++;
+    if (identmap3.Elem(i))
+      npid3++;
+  }
+
+  outfile << "\n";
+  outfile << "# Boundary triangles\n";  
+  outfile << "# Number of identified points in 1-direction: " << npid1 << "\n";
+  outfile << "# Number of identified points in 2-direction: " << npid2 << "\n";
+  outfile << "# Number of identified points in 3-direction: " << npid3 << "\n";
+  for (i = 1; i <= nse; i++)
+  {
+    Element2d el = mesh.SurfaceElement(i);
+    if (el.GetNP() == 3
+        && (mesh.GetFaceDescriptor (el.GetIndex()).DomainIn()==0
+            || mesh.GetFaceDescriptor (el.GetIndex()).DomainOut()==0))
+    {
+      outfile <<"# T\n";
+      for (j = 1; j <= 3; j++)
+        outfile << el.PNum(j)<<"\n";
+      if (mesh.GetFaceDescriptor (el.GetIndex()).BCProperty()==bc_at_infinity)
+        outfile << 1000 << "\n";      
+      else
+        outfile << mesh.GetFaceDescriptor (el.GetIndex()).BCProperty() << "\n";      
+      if (mesh.GetFaceDescriptor (el.GetIndex()).BCProperty() == bc_at_infinity)
+        outfile << "-2\n\n";
+      else if (identmap1.Elem(el.PNum(1))
+               &&identmap1.Elem(el.PNum(2))
+               &&identmap1.Elem(el.PNum(3)))
+      {
+        outfile << "-1\n";
+        for (j = 1; j <= 3; j++)
+          outfile << identmap1.Elem(el.PNum(j))<<"\n";
+        outfile << "\n";
+      }
+      else if (identmap2.Elem(el.PNum(1))
+               &&identmap2.Elem(el.PNum(2))
+               &&identmap2.Elem(el.PNum(3)))
+      {
+        outfile << "-1\n";
+        for (j = 1; j <= 3; j++)
+          outfile << identmap2.Elem(el.PNum(j))<<"\n";
+        outfile << "\n";
+      }
+      else if (identmap3.Elem(el.PNum(1))
+               &&identmap3.Elem(el.PNum(2))
+               &&identmap3.Elem(el.PNum(3)))
+      {
+        outfile << "-1\n";
+        for (j = 1; j <= 3; j++)
+          outfile << identmap3.Elem(el.PNum(j))<<"\n";
+        outfile << "\n";
+      }
+      else
+        outfile << "1\n\n";
+        
+    }
+  }
+
+  outfile << "\n";
+  outfile << "# Boundary quadrilaterals\n";
+  for (i = 1; i <= nse; i++)
+  {
+    Element2d el = mesh.SurfaceElement(i);
+
+    if (el.GetNP() == 4
+        && (mesh.GetFaceDescriptor (el.GetIndex()).DomainIn()==0
+            || mesh.GetFaceDescriptor (el.GetIndex()).DomainOut()==0))
+    {
+      if      (pointsOnTetras.Get(el.PNum(1)) &&
+               pointsOnTetras.Get(el.PNum(2)))
+        ct = 0;
+      else if (pointsOnTetras.Get(el.PNum(2)) &&
+               pointsOnTetras.Get(el.PNum(3)))
+        ct = 1;
+      else if (pointsOnTetras.Get(el.PNum(3)) &&
+               pointsOnTetras.Get(el.PNum(4)))
+        ct = 2;
+      else if (pointsOnTetras.Get(el.PNum(4)) &&
+               pointsOnTetras.Get(el.PNum(1)))
+        ct = 3;
+      else
+        cout << "\nWarning: Quadrilateral with inconsistent points found!"<<endl;
+      
+      for (j = 1; j <= 4; j++)
+      {
+        jj = j + ct;
+        if ( jj >= 5 )
+          jj = jj - 4;
+        outfile << el.PNum(jj)<<"\n";
+      }
+      outfile << mesh.GetFaceDescriptor (el.GetIndex()).BCProperty() << "\n";      
+      if (mesh.GetFaceDescriptor (el.GetIndex()).BCProperty() == bc_at_infinity)
+      {
+        outfile << "-2\n\n";
+        cout << "\nWarning: Quadrilateral at infinity found (this should not occur)!"<<endl;
+      }
+      else if ( identmap1.Elem(el.PNum(1)) &&
+                identmap1.Elem(el.PNum(2)) &&
+                identmap1.Elem(el.PNum(3)) &&
+                identmap1.Elem(el.PNum(4))    )
+      {
+        outfile << "-1\n";
+        for (j = 1; j <= 4; j++)
+        {
+          jj = j + ct;
+          if ( jj >= 5 )
+            jj = jj - 4;
+          outfile << identmap1.Elem(el.PNum(jj))<<"\n";
+        }
+        outfile << "\n";
+      }
+      else if ( identmap2.Elem(el.PNum(1)) &&
+                identmap2.Elem(el.PNum(2)) &&
+                identmap2.Elem(el.PNum(3)) &&
+                identmap2.Elem(el.PNum(4))    )
+      {
+        outfile << "-1\n";
+        for (j = 1; j <= 4; j++)
+        {
+          jj = j + ct;
+          if ( jj >= 5 )
+            jj = jj - 4;
+          outfile << identmap2.Elem(el.PNum(jj))<<"\n";
+        }
+        outfile << "\n";
+      }
+      else if ( identmap3.Elem(el.PNum(1)) &&
+                identmap3.Elem(el.PNum(2)) &&
+                identmap3.Elem(el.PNum(3)) &&
+                identmap3.Elem(el.PNum(4))    )
+      {
+        outfile << "-1\n";
+        for (j = 1; j <= 4; j++)
+        {
+          jj = j + ct;
+          if ( jj >= 5 )
+            jj = jj - 4;
+          outfile << identmap3.Elem(el.PNum(jj))<<"\n";
+        }
+        outfile << "\n";
+      }
+      else
+        outfile << "1\n\n";
+    }
+  }
+
+  cout << " JCMwave grid file written." << endl;
+}
+
+}
+
diff --git a/contrib/Netgen/libsrc/interface/writepermas.cpp b/contrib/Netgen/libsrc/interface/writepermas.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..fc46e87cd9c9e225d4cb2a961d4e27e570ac9ccb
--- /dev/null
+++ b/contrib/Netgen/libsrc/interface/writepermas.cpp
@@ -0,0 +1,208 @@
+//
+// Write Permas file
+// for Intes GmbH, Stuttgart
+//
+
+#include <mystdlib.h>
+
+#include <myadt.hpp>
+#include <linalg.hpp>
+#include <csg.hpp>
+#include <meshing.hpp>
+
+#include <string>
+
+using namespace std;
+
+namespace netgen
+{
+#include "writeuser.hpp"
+    // Forward declarations (don't know, where to define them, sorry)
+    int addComponent(string &strComp, string &strSitu, ofstream &out);
+
+
+    // This should be the new function to export a PERMAS file
+    void WritePermasFormat (const Mesh &mesh, const string &filename, 
+                            string &strComp, string &strSitu) 
+    {
+        ofstream outfile (filename.c_str());
+        addComponent(strComp, strSitu, outfile);
+        WritePermasFormat ( mesh, filename);
+    }
+
+    void WritePermasFormat (const Mesh &mesh, const string &filename)
+    {
+        string strComp, strSitu;
+        ofstream outfile (filename.c_str());
+        
+        outfile.precision(8);
+
+        strSitu = strComp = "";
+        if (addComponent(strComp, strSitu, outfile) == 1) {
+            printf("Error while exporting PERMAS dat!\n");
+            return;
+        }
+    
+        int np = mesh.GetNP();
+        int ne = mesh.GetNE();
+        int nse = mesh.GetNSE();
+        int i, j, k;
+    
+        if (ne == 0)
+        {
+            // pure surface mesh
+            cout << "\nWrite Permas Surface Mesh" << endl;
+            
+            int elnr = 0;
+            for (j = 1; j <= 2; j++)
+            {
+                int nelp(0);
+                switch (j)
+                {
+                case 1:
+                    nelp = 3;
+                    outfile << "$ELEMENT TYPE = TRIA3  ESET = ALLQUAD" << endl;		  
+                    break;
+                case 2:
+                    nelp = 4;
+                    outfile << "$ELEMENT TYPE = QUAD4  ESET = ALLQUAD" << endl;		  
+                    break;
+                }
+                
+                for (i = 1; i <= nse; i++)
+                {
+                    const Element2d & el = mesh.SurfaceElement(i);
+                    if (el.GetNP() != nelp)
+                        continue;
+                    
+                    elnr++;
+                    outfile << elnr << "  ";
+                    for (k = 1; k <= nelp; k++)
+                        outfile << " " << el.PNum(k);
+                    outfile << endl;
+                    
+                }
+            }
+        }
+        else
+        {
+            cout << "\nWrite Permas Volume Mesh" << endl;
+            
+            int secondorder = (mesh.VolumeElement(1).GetNP() == 10);
+            
+            if (!secondorder)
+            {
+                outfile << "$ELEMENT TYPE = TET4  ESET = ALLTET" << endl;
+                for (i = 1; i <= ne; i++)
+                {
+                    const Element & el = mesh.VolumeElement(i);
+                    outfile << i 
+                            << " " << el.PNum(1) 
+                            << " " << el.PNum(2) 
+                            << " " << el.PNum(3) 
+                            << " " << el.PNum(4) << endl;
+                }
+            }
+            else
+            {
+                outfile << "$ELEMENT TYPE = TET10  ESET = ALLTET" << endl;
+                for (i = 1; i <= ne; i++)
+                {
+                    const Element & el = mesh.VolumeElement(i);
+                    outfile << i 
+                            << " " << el.PNum(1) 
+                            << " " << el.PNum(5) 
+                            << " " << el.PNum(2) 
+                            << " " << el.PNum(8) 
+                            << " " << el.PNum(3) 
+                            << " " << el.PNum(6) << endl << "& "
+                            << " " << el.PNum(7) 
+                            << " " << el.PNum(9) 
+                            << " " << el.PNum(10) 
+                            << " " << el.PNum(4) << endl;
+                }
+            }
+            
+            outfile << endl << endl;
+            
+            
+            outfile << "$SURFACE GEO  SURFID = 1  SFSET = ALLSUR" << endl;
+            for (i = 1; i <= nse; i++)
+            {
+                const Element2d & el = mesh.SurfaceElement(i);
+                if (el.GetNP() == 3)
+                    outfile << "STRIA3"
+                            << " " << el.PNum(1) 
+                            << " " << el.PNum(2) 
+                            << " " << el.PNum(3) << endl;
+            }    
+            
+            for (i = 1; i <= nse; i++)
+            {
+                const Element2d & el = mesh.SurfaceElement(i);
+                if (el.GetNP() == 4)
+                    outfile << "SQUAD4"
+                            << " " << el.PNum(1) 
+                            << " " << el.PNum(2) 
+                            << " " << el.PNum(3) 
+                            << " " << el.PNum(4) << endl;
+            }      
+            
+            for (i = 1; i <= nse; i++)
+            {
+                const Element2d & el = mesh.SurfaceElement(i);
+                if (el.GetNP() == 6)
+                    outfile << "STRIA6"
+                            << " " << el.PNum(1) 
+                            << " " << el.PNum(4) 
+                            << " " << el.PNum(2) 
+                            << " " << el.PNum(5) 
+                            << " " << el.PNum(3) 
+                            << " " << el.PNum(6) << endl;
+            }      
+        }
+        
+        
+        outfile << endl << endl;
+        
+        outfile << "$COOR  NSET = ALLNODES" << endl;
+        
+        outfile.precision(6);
+        outfile.setf (ios::fixed, ios::floatfield);
+        outfile.setf (ios::showpoint);
+        
+        for (i = 1; i <= np; i++)
+        {
+            outfile << i << " ";
+            outfile << mesh.Point(i)(0) << " ";
+            outfile << mesh.Point(i)(1) << " ";
+            outfile << mesh.Point(i)(2) << "\n";
+        }
+    }
+    ////////////////////////////////////////////////////////////////////////////////// 
+    // \brief Writes PERMAS configuration header into export file
+    //        Returns >0 in case of errors
+    // \par string &strComp  : Reference to component description
+    // \par string &strComp  : Reference to situation description
+    ////////////////////////////////////////////////////////////////////////////////// 
+    int addComponent(string &strComp, string &strSitu, ofstream &out)
+    {
+        if (strComp.size() > 12 || strSitu > 12) 
+            return 1;
+
+        if (0 == strComp.size()) 
+            strComp = "KOMPO1";
+        
+        if (0 == strSitu.size())
+            strSitu = "SIT1";
+
+        // Writing description header of configuration
+        out << "$ENTER COMPONENT  NAME = " << strComp << "  DOFTYPE = DISP MATH" << endl << endl;
+        out << "   $SITUATION  NAME = " << strSitu << endl;
+        out << "   $END SITUATION" << endl << endl;
+        out << "   $STRUCTURE" << endl;
+        
+        return 0;
+    }
+    
+}
diff --git a/contrib/Netgen/libsrc/interface/writetecplot.cpp b/contrib/Netgen/libsrc/interface/writetecplot.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..6f6063747a28c416034ab21a92596108670789fa
--- /dev/null
+++ b/contrib/Netgen/libsrc/interface/writetecplot.cpp
@@ -0,0 +1,127 @@
+//
+//
+// TECPLOT file by Jawor Georgiew
+//
+#include <mystdlib.h>
+
+#include <myadt.hpp>
+#include <linalg.hpp>
+#include <csg.hpp>
+#include <meshing.hpp>
+
+
+
+namespace netgen
+{
+#include "writeuser.hpp"
+
+void WriteTecPlotFormat (const Mesh & mesh,
+			 const CSGeometry & geom,
+			 const string & filename)
+{
+  INDEX i;
+  int j, k, e, z;
+  Vec<3> n;
+  
+  INDEX np = mesh.GetNP();
+  INDEX ne = mesh.GetNE();
+  INDEX nse = mesh.GetNSE();
+  
+  ARRAY<int> sn(np);
+  ofstream outfile(filename.c_str());
+  
+  outfile << "TITLE=\" " << filename << "\"" << endl;
+
+  // fill hashtable
+
+  INDEX_3_HASHTABLE<int> face2volelement(ne);
+
+  for (i = 1; i <= ne; i++)
+    {
+      const Element & el = mesh.VolumeElement(i);
+      INDEX_3 i3;
+      int l;
+      for (j = 1; j <= 4; j++)   // loop over faces of tet
+	{
+	  l = 0;
+	  for (k = 1; k <= 4; k++)
+	    if (k != j)
+	      {
+		l++;
+		i3.I(l) = el.PNum(k);
+	      }
+	  i3.Sort();
+	  face2volelement.Set (i3, i);
+	}
+    }
+      
+      
+  for (j = 1; j <= geom.GetNSurf(); j++)       /* Flaeche Nummer j */
+    {
+      for (i = 1; i <= np; i++)
+	sn.Elem(i) = 0;
+
+      e = 0;
+       
+      for (i = 1; i <= nse; i++)
+	{
+	  const Element2d & el = mesh.SurfaceElement(i);
+	  if (j ==  mesh.GetFaceDescriptor (el.GetIndex ()).SurfNr())
+	    {
+	      for (k = 1; k <= 3; k++)
+		sn.Elem(el.PNum(k)) = 1;
+	      e++;                     /* e= Anzahl der neuen Elemente */
+	    }
+	}
+
+      z = 0;
+      for (i = 1; i <= np; i++)
+	if (sn.Elem(i) == 1)
+	  sn.Elem(i) = ++z;
+
+      outfile << "ZONE T=\" Surface " << j << " \", N=" << z
+	      << ", E=" << e << ", ET=TRIANGLE, F=FEPOINT" << endl;
+
+      for (i = 1; i <= np; i++)
+	if (sn.Elem(i) != 0)
+	  {
+	    n = geom.GetSurface(j) -> GetNormalVector ( mesh.Point(i) );
+		
+	    outfile << mesh.Point(i)(0) << " " /* Knoten Koordinaten */
+		    << mesh.Point(i)(1) << " "
+		    << mesh.Point(i)(2) << " "
+		    << n(0) << " "
+		    << n(1) << " "
+		    << n(2) << " "
+		    << i     << endl;
+	  }
+	  
+
+      for (i = 1; i <= nse; i++)
+	{
+	  const Element2d & el = mesh.SurfaceElement(i);
+	  if (j ==  mesh.GetFaceDescriptor(el.GetIndex ()).SurfNr())
+	    /* FlaechenKnoten (3) */
+	    outfile << sn.Get(el.PNum(1)) << " " 
+		    << sn.Get(el.PNum(2)) << " "
+		    << sn.Get(el.PNum(3)) << endl;
+	      
+	  /// Hier soll noch die Ausgabe der Nummer des angrenzenden
+	      /// Vol.elements erfolgen !
+
+	      for (k = 1; k <= nse; k++)
+		{
+		  const Element2d & sel = mesh.SurfaceElement(k);
+		  INDEX_3 i3;
+		  for (j = 1; j <= 3; j++)
+		    i3.I(j) = sel.PNum(j);
+		  i3.Sort();
+		  
+		  //int elind = face2volelement.Get(i3);
+		}
+	}
+    }
+}
+
+
+}
diff --git a/contrib/Netgen/libsrc/interface/writetet.cpp b/contrib/Netgen/libsrc/interface/writetet.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..581cc0a3feb5220e3356ca12a932fe5212a3b815
--- /dev/null
+++ b/contrib/Netgen/libsrc/interface/writetet.cpp
@@ -0,0 +1,1096 @@
+
+#include <mystdlib.h>
+
+#include <myadt.hpp>
+#include <linalg.hpp>
+#include <csg.hpp>
+#include <acisgeom.hpp>
+#include <meshing.hpp>
+
+namespace netgen
+{
+
+#include "writeuser.hpp"
+  
+  
+  void WriteTETFormat (const Mesh & mesh,
+		       const string & filename)//, const string& problemType )
+  {
+    string problemType = "";
+    if(!mesh.PureTetMesh())
+      throw NgException("Can only export pure tet mesh in this format");
+
+    cout << "starting .tet export to file " << filename << endl;
+
+
+    ARRAY<int> point_ids,edge_ids,face_ids;
+    ARRAY<int> elnum(mesh.GetNE());
+    elnum = -1;
+
+    
+    ARRAY<int> userdata_int;
+    ARRAY<double> userdata_double;
+    ARRAY<int> ports;
+
+    ARRAY<int> uid_to_group_3D, uid_to_group_2D, uid_to_group_1D, uid_to_group_0D;
+
+    int pos_int = 0;
+    int pos_double = 0;
+    
+    bool haveuserdata = 
+      (mesh.GetUserData("TETmesh:double",userdata_double) &&
+       mesh.GetUserData("TETmesh:int",userdata_int) && 
+       mesh.GetUserData("TETmesh:ports",ports) &&
+       mesh.GetUserData("TETmesh:point_id",point_ids,PointIndex::BASE) &&
+       mesh.GetUserData("TETmesh:uid_to_group_3D",uid_to_group_3D) &&
+       mesh.GetUserData("TETmesh:uid_to_group_2D",uid_to_group_2D) &&
+       mesh.GetUserData("TETmesh:uid_to_group_1D",uid_to_group_1D) &&
+       mesh.GetUserData("TETmesh:uid_to_group_0D",uid_to_group_0D));
+
+
+    int version,subversion;
+
+    if(haveuserdata)
+      {
+	version = int(userdata_double[0]);
+	subversion = int(10*(userdata_double[0] - version));
+	pos_double++;
+      }
+    else
+      {
+	version = 2;
+	subversion = 0;
+      }
+
+    
+    if(version >= 2)
+      {
+	// test if ids are disjunct, if not version 2.0 not possible
+	int maxbc(-1),mindomain(-1);
+	
+	for(ElementIndex i=0; i<mesh.GetNE(); i++)
+	  if(i==0 || mesh[i].GetIndex() < mindomain)
+	    mindomain = mesh[i].GetIndex();
+	for(int i=1; i<=mesh.GetNFD(); i++)
+	  if(i==1 || mesh.GetFaceDescriptor(i).BCProperty() > maxbc)
+	    maxbc = mesh.GetFaceDescriptor(i).BCProperty();
+	
+	if(maxbc >= mindomain)
+	  {
+	    cout << "WARNING: writing version " << version << "." << subversion << " tetfile not possible, ";
+	    version = 1; subversion = 1;
+	    cout << "using version " << version << "." << subversion << endl;
+	  }
+      }
+
+
+
+    int startsize = point_ids.Size();
+    point_ids.SetSize(mesh.GetNP()+1);
+    for(int i=startsize; i<point_ids.Size(); i++)
+      point_ids[i] = -1;
+
+
+    for(int i=0; i<PointIndex::BASE; i++)
+      point_ids[i] = -1;
+
+
+    INDEX_2_CLOSED_HASHTABLE<int> edgenumbers(6*mesh.GetNE()+3*mesh.GetNSE());;
+    INDEX_3_CLOSED_HASHTABLE<int> facenumbers(4*mesh.GetNE()+mesh.GetNSE());
+
+    ARRAY<INDEX_2> edge2node;
+    ARRAY<INDEX_3> face2edge;
+    ARRAY<INDEX_4> element2face;
+
+    int numelems(0),numfaces(0),numedges(0),numnodes(0);
+
+    for(SegmentIndex si = 0; si < mesh.GetNSeg(); si++)
+      {
+	const Segment & seg = mesh[si];
+	INDEX_2 i2(seg.p1,seg.p2);
+	i2.Sort();
+	if(edgenumbers.Used(i2))
+	  continue;
+
+	numedges++;
+	edgenumbers.Set(i2,numedges);
+	edge2node.Append(i2);
+
+	edge_ids.Append(seg.edgenr);
+
+	if(point_ids[seg.p1] == -1)
+	  point_ids[seg.p1] = (version >= 2) ? seg.edgenr : 0;
+	if(point_ids[seg.p2] == -1)
+	  point_ids[seg.p2] = (version >= 2) ? seg.edgenr : 0;
+      }
+
+    for(SurfaceElementIndex si = 0; si < mesh.GetNSE(); si++)
+      {
+	if(mesh[si].IsDeleted())
+	  continue;
+
+	const Element2d & elem = mesh[si];
+
+	numfaces++;
+	INDEX_3 i3(elem[0], elem[1], elem[2]);
+
+	int min = i3[0];
+	int minpos = 0;
+	for(int j=1; j<3; j++)
+	  if(i3[j] < min)
+	    {
+	      min = i3[j]; minpos = j;
+	    }
+	if(minpos == 1)
+	  {
+	    int aux = i3[0]; i3[0] = i3[1]; i3[1] = i3[2]; i3[2] = aux;
+	  }
+	else if(minpos == 2)
+	  {
+	    int aux = i3[0]; i3[0] = i3[2]; i3[2] = i3[1]; i3[1] = aux;
+	  }
+	facenumbers.Set(i3,numfaces);
+
+	int bc = mesh.GetFaceDescriptor(elem.GetIndex()).BCProperty();
+	face_ids.Append(bc);
+
+	for(int j=0; j<3; j++)
+	  if(point_ids[elem[j]] == -1)
+	    point_ids[elem[j]] = (version >= 2) ? bc : 0;
+
+	INDEX_2 i2a,i2b;
+	INDEX_3 f_to_n;
+	for(int j=0; j<3; j++)
+	  {
+	    i2a = INDEX_2(i3[j],i3[(j+1)%3]);
+	    i2b[0] = i2a[1]; i2b[1] = i2a[0];
+	    if(edgenumbers.Used(i2a))
+	      f_to_n[j] = edgenumbers.Get(i2a);
+	    else if(edgenumbers.Used(i2b))
+	      f_to_n[j] = -edgenumbers.Get(i2b);
+	    else
+	      {
+		numedges++;
+		edgenumbers.Set(i2a,numedges);
+		edge2node.Append(i2a);
+		f_to_n[j] = numedges;
+		if(version >= 2)
+		  edge_ids.Append(bc);
+		else
+		  edge_ids.Append(0);
+	      }
+	  }
+	face2edge.Append(f_to_n);
+      }
+    
+    for(ElementIndex ei = 0; ei < mesh.GetNE(); ei++)
+      {
+	const Element & el = mesh[ei];
+
+	if(el.IsDeleted())
+	  continue;
+
+	numelems++;
+	elnum[ei] = numelems;
+
+	static int tetfaces[4][3] =
+	  { { 0, 2, 1 },
+	    { 0, 1, 3 },
+	    { 1, 2, 3 },
+	    { 2, 0, 3 } };
+	
+	for(int j=0; j<4; j++)
+	  if(point_ids[el[j]] == -1)
+	    point_ids[el[j]] = (version >= 2) ? el.GetIndex() : 0;
+
+	INDEX_4 e_to_f;
+
+	for(int i = 0; i < 4; i++)
+	  {
+	    INDEX_3 i3a(el[tetfaces[i][0]],el[tetfaces[i][1]],el[tetfaces[i][2]]);
+	    
+	    int min = i3a[0];
+	    int minpos = 0;
+	    for(int j=1; j<3; j++)
+	      if(i3a[j] < min)
+		{
+		  min = i3a[j]; minpos = j;
+		}
+	    if(minpos == 1)
+	      {
+		int aux = i3a[0]; i3a[0] = i3a[1]; i3a[1] = i3a[2]; i3a[2] = aux;
+	      }
+	    else if(minpos == 2)
+	      {
+		int aux = i3a[0]; i3a[0] = i3a[2]; i3a[2] = i3a[1]; i3a[1] = aux;
+	      }
+	    INDEX_3 i3b(i3a[0],i3a[2],i3a[1]);
+	    
+
+	    if(facenumbers.Used(i3a))
+	      e_to_f[i] = facenumbers.Get(i3a);
+	    else if(facenumbers.Used(i3b))
+	      e_to_f[i] = -facenumbers.Get(i3b);
+	    else
+	      {
+		numfaces++;
+		facenumbers.Set(i3a,numfaces);
+		e_to_f[i] = numfaces;
+		if(version >= 2)
+		  face_ids.Append(el.GetIndex());
+		else
+		  face_ids.Append(0);
+
+		INDEX_2 i2a,i2b;
+		INDEX_3 f_to_n;
+		for(int j=0; j<3; j++)
+		  {
+		    i2a = INDEX_2(i3a[j],i3a[(j+1)%3]);
+		    i2b[0] = i2a[1]; i2b[1] = i2a[0];
+		    if(edgenumbers.Used(i2a))
+		      f_to_n[j] = edgenumbers.Get(i2a);
+		    else if(edgenumbers.Used(i2b))
+		      f_to_n[j] = -edgenumbers.Get(i2b);
+		    else
+		      {
+			numedges++;
+			edgenumbers.Set(i2a,numedges);
+			edge2node.Append(i2a);
+			f_to_n[j] = numedges;
+			if(version >= 2)
+			  edge_ids.Append(el.GetIndex());
+			else
+			  edge_ids.Append(0);
+		      }
+		  }
+		face2edge.Append(f_to_n);	  
+	      }
+	  }
+	element2face.Append(e_to_f);
+      }
+
+
+
+
+    ofstream outfile(filename.c_str());
+
+    outfile.precision(16);
+
+    int unitcode;
+    double tolerance;
+    double dS1,dS2, alphaDeg;
+    double x3D,y3D,z3D;
+    int modelverts(0), modeledges(0), modelfaces(0), modelcells(0);
+
+    int numObj0D,numObj1D,numObj2D,numObj3D;
+    int numports = ports.Size();
+
+    ARRAY<int> nodenum(point_ids.Size()+1);
+
+    nodenum = -1;
+	    
+
+
+    numnodes = 0;
+    for(int i=0; i<point_ids.Size(); i++)
+      {
+	if(point_ids[i] != -1)
+	  {
+	    numnodes++;
+	    nodenum[i] = numnodes;
+	  }
+      }
+
+
+    if(haveuserdata)
+      {
+	unitcode = userdata_int[pos_int];
+	pos_int++;
+
+	tolerance = userdata_double[pos_double];
+	pos_double++;
+
+	dS1 = userdata_double[pos_double];
+	pos_double++;
+	dS2 = userdata_double[pos_double];
+	pos_double++;
+	alphaDeg = userdata_double[pos_double];
+	pos_double++;
+
+	x3D = userdata_double[pos_double];
+	pos_double++;
+	y3D = userdata_double[pos_double];
+	pos_double++;
+	z3D = userdata_double[pos_double];
+	pos_double++;
+
+	if(version == 2)
+	  {
+	    modelverts = userdata_int[pos_int];
+	    pos_int++;
+	    modeledges = userdata_int[pos_int];
+	    pos_int++;
+	    modelfaces = userdata_int[pos_int];
+	    pos_int++;
+	    modelcells = userdata_int[pos_int];
+	    pos_int++;
+	  }
+
+	numObj3D = userdata_int[pos_int];
+	pos_int++;
+	numObj2D = userdata_int[pos_int];
+	pos_int++;
+	numObj1D = userdata_int[pos_int];
+	pos_int++;
+	numObj0D = userdata_int[pos_int];
+	pos_int++;
+      }
+    else
+      {
+	unitcode = 3;
+
+	tolerance = 1e-5;
+
+	dS1 = dS2 = alphaDeg = 0;
+
+	x3D = y3D = z3D = 0;
+
+	modelverts = modeledges = modelfaces = modelcells = 0;
+	
+	numObj3D = numObj2D = numObj1D = numObj0D = 0;
+      }
+
+    string uidpid;
+    if(version == 1)
+      uidpid = "PID";
+    else if (version == 2)
+      uidpid = "UID";
+    
+
+    ARRAY< ARRAY<int,PointIndex::BASE>* > idmaps;
+    for(int i=1; i<=mesh.GetIdentifications().GetMaxNr(); i++)
+      {
+	if(mesh.GetIdentifications().GetType(i) == Identifications::PERIODIC)
+	  {
+	    idmaps.Append(new ARRAY<int,PointIndex::BASE>);
+	    mesh.GetIdentifications().GetMap(i,*idmaps.Last(),true);
+	  }
+      }
+
+    ARRAY<int> id_num,id_type;
+    ARRAY< ARRAY<int> *> id_groups;
+
+
+	// sst 2008-03-12: Write problem class...
+	{
+		std::string block;
+		block  = "// CST Tetrahedral ";
+		block += !problemType.empty() ? problemType : "High Frequency";
+		block += " Mesh, Version no.:\n";
+		
+		size_t size = block.size()-3;
+		block += "// ";
+		block.append( size, '^' );
+		block += "\n";
+
+		outfile
+			<< block
+			<< version << "." << subversion << "\n\n";
+	}
+
+	outfile 
+	    << "// User Units Code (1=CM 2=MM 3=M 4=MIC 5=NM 6=FT 7=IN 8=MIL):\n" \
+	    << "// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" \
+	    << unitcode << "\n\n"					\
+	    << "// Geometric coord \"zero\" tolerance threshold:\n" \
+	    << "// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" \
+	    << tolerance << "\n\n"				  \
+	    << "// Periodic UnitCell dS1 , dS2 , alphaDeg:\n" \
+	    << "// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" \
+	    << dS1 << " " << dS2 << " " << alphaDeg <<"\n\n"	\
+	    << "// Periodic UnitCell origin in global coords (x3D,y3D,z3D):\n" \
+	    << "// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" \
+	    << x3D << " " << y3D << " " << z3D << "\n" << endl;
+
+    if(version == 2)
+      {
+	outfile << "// Model entity count: Vertices, Edges, Faces, Cells:\n" \
+		<< "// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" \
+		<< modelverts << " " << modeledges << " " << modelfaces << " " << modelcells << endl << endl;
+      }
+
+
+    outfile << "// Topological mesh-entity counts (#elements,#faces,#edges,#nodes):\n" \
+	    << "// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n";
+    outfile << numelems << " " 
+	    << numfaces << " "
+	    << numedges << " " 
+	    << numnodes << endl << endl;
+
+    outfile << "// NodeID, X, Y, Z, Type (0=Reg 1=PMaster 2=PSlave 3=CPMaster 4=CPSlave), "<< uidpid <<":\n" \
+	    << "// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n";
+       
+
+
+    id_num.SetSize(mesh.GetNP()+1);
+    id_type.SetSize(mesh.GetNP()+1);
+    id_num = 0;
+    id_type = 0;
+
+    int n2,n4,n8;
+    n2 = n4 = n8 = 0;
+
+ 
+    for(int i=PointIndex::BASE; i<mesh.GetNP()+PointIndex::BASE; i++)
+      {
+	if(id_num[i] != 0)
+	  continue;
+
+	if(nodenum[i] == -1)
+	  continue;
+
+	ARRAY<int> group;
+	group.Append(i);
+	for(int j=0; j<idmaps.Size(); j++)
+	  {
+	    startsize = group.Size();
+	    for(int k=0; k<startsize; k++)
+	      {
+		int id = (*idmaps[j])[group[k]];
+		if(id != 0 && !group.Contains(id) && nodenum[id] != -1)
+		  {
+		    group.Append(id);
+		    id_num[id] = j+1+id_num[group[k]];
+		  }
+	      }
+	  }
+	if(group.Size() > 1)
+	  {
+	    id_groups.Append(new ARRAY<int>(group));
+	    if(group.Size() == 2)
+	      {
+		id_type[i] = 1;
+		id_type[group[1]] = 2;
+		n2++;
+	      }
+	    else if(group.Size() == 4)
+	      {
+		id_type[i] = 3;
+		for(int j=1; j<group.Size(); j++)
+		  id_type[group[j]] = 4;
+		n4++;
+	      }
+	    else if(group.Size() == 8)
+	      {
+		id_type[i] = 5;
+		for(int j=1; j<group.Size(); j++)
+		  id_type[group[j]] = 6;
+		n8++;
+	      }
+	    else
+	      cerr << "ERROR: Identification group size = " << group.Size() << endl;
+	  }
+	
+      }
+
+
+    for(PointIndex i=PointIndex::BASE; i<mesh.GetNP()+PointIndex::BASE; i++)
+      {
+	if(nodenum[i] == -1)
+	  continue;
+	outfile << nodenum[i] << " "
+		<< mesh[i](0) << " "
+		<< mesh[i](1) << " "
+		<< mesh[i](2) << " " << id_type[i] << " ";
+	if(i-PointIndex::BASE < point_ids.Size())
+	  outfile << point_ids[i];
+	else
+	  outfile << "0";
+	outfile << "\n";
+      }
+    outfile << endl;
+
+    outfile << "\n// Number of Periodic Master Nodes:\n" \
+	    << "// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" \
+	    << n2 << "\n"			       \
+	    << "\n" \
+	    << "// MasterNodeID, SlaveNodeID, TranslCode (1=dS1 2=dS2 3=dS1+dS2):\n" \
+	    << "// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n";
+    for(int i=0; i<id_groups.Size(); i++)
+      {
+	if(id_groups[i]->Size() != 2)
+	  continue;
+
+	for(int j=0; j<id_groups[i]->Size(); j++)
+	  outfile << nodenum[(*id_groups[i])[j]] << " ";
+	for(int j=1; j<id_groups[i]->Size(); j++)
+	  outfile << id_num[(*id_groups[i])[j]] << " ";
+	outfile << "\n";
+
+	delete id_groups[i];
+	id_groups[i] = NULL;
+      }
+    outfile << endl;
+	
+	
+    outfile << "// Number of Corner Periodic Master Nodes:\n"	      \
+	    << "// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" \
+	    << n4 << "\n"				      \
+	    << "\n" \
+	    << "// MasterNodeID, 3-SlaveNodeID's, 3-TranslCodes (1=dS1 2=dS2 3=dS1+dS2):\n" \
+	    << "// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n";
+
+
+    for(int i=0; i<id_groups.Size(); i++)
+      {
+	if(!id_groups[i] || id_groups[i]->Size() != 4)
+	  continue;
+
+	for(int j=0; j<id_groups[i]->Size(); j++)
+	  outfile << nodenum[(*id_groups[i])[j]] << " ";
+	for(int j=1; j<id_groups[i]->Size(); j++)
+	  {
+	    outfile << id_num[(*id_groups[i])[j]] << " ";
+	  }
+	outfile << "\n";
+
+	delete id_groups[i];
+	id_groups[i] = NULL;
+      }
+    outfile << endl;
+
+
+    outfile << "// Number of Cubic Periodic Master Nodes:\n"	     \
+	    << "// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" \
+	    << n8 << "\n"				     \
+	    << "\n" \
+	    << "// MasterNodeID, 7-SlaveNodeID's, TranslCodes:\n" \
+	    << "// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n";
+    for(int i=0; i<id_groups.Size(); i++)
+      {
+	if(!id_groups[i] || id_groups[i]->Size() != 8)
+	  continue;
+
+	for(int j=0; j<id_groups[i]->Size(); j++)
+	  outfile << nodenum[(*id_groups[i])[j]] << " ";
+	for(int j=1; j<id_groups[i]->Size(); j++)
+	  outfile << id_num[(*id_groups[i])[j]] << " ";
+	outfile << "\n";
+
+	delete id_groups[i];
+	id_groups[i] = NULL;
+      }
+    outfile << endl;
+
+    
+
+
+    outfile << "// EdgeID, NodeID0, NodeID1, Type (0=Reg 1=PMaster 2=PSlave 3=CPMaster 4=CPSlave), "<<uidpid<<":\n" \
+	    << "// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n";
+
+    
+      
+    ARRAY< ARRAY<int>* > vertex_to_edge(mesh.GetNP()+1);
+    for(int i=0; i<=mesh.GetNP(); i++)
+      vertex_to_edge[i] = new ARRAY<int>;
+
+    ARRAY< ARRAY<int,PointIndex::BASE>* > idmaps_edge(idmaps.Size());
+    for(int i=0; i<idmaps_edge.Size(); i++)
+      {
+	idmaps_edge[i] = new ARRAY<int,PointIndex::BASE>(numedges);
+	(*idmaps_edge[i]) = 0;
+      }
+
+    ARRAY<int> possible;
+    for(int i=0; i<edge2node.Size(); i++)
+      {
+	const INDEX_2 & v = edge2node[i];
+	for(int j=0; j<idmaps.Size(); j++)
+	  {
+	    INDEX_2 vid((*idmaps[j])[v[0]], (*idmaps[j])[v[1]]);
+	    if(vid[0] != 0 && vid[0] != v[0] && vid[1] != 0 && vid[1] != v[1])
+	      {
+		Intersection(*vertex_to_edge[vid[0]],*vertex_to_edge[vid[1]],possible);
+		if(possible.Size() == 1)
+		  {
+		    (*idmaps_edge[j])[possible[0]] = i+1;
+		    (*idmaps_edge[j])[i+1] = possible[0];
+		  }
+		else if(possible.Size() > 0)
+		  {
+		    cerr << "ERROR: too many possible edge identifications" << endl;
+		    (*testout) << "ERROR: too many possible edge identifications" << endl
+			       << "*vertex_to_edge["<<vid[0]<<"] " << *vertex_to_edge[vid[0]] << endl
+			       << "*vertex_to_edge["<<vid[1]<<"] " << *vertex_to_edge[vid[1]] << endl
+			       << "possible " << possible << endl;
+		  }
+	      }
+	  }
+	vertex_to_edge[v[0]]->Append(i+1);
+	vertex_to_edge[v[1]]->Append(i+1);
+      }
+
+
+    for(int i=0; i<vertex_to_edge.Size(); i++)
+      delete vertex_to_edge[i];
+
+
+    id_groups.SetSize(0);
+    id_num.SetSize(numedges+1);
+    id_num = 0;
+    id_type.SetSize(numedges+1);
+    id_type = 0;
+
+    n2 = n4 = n8 = 0;
+
+    for(int i=1; i<=edge2node.Size(); i++)
+      {
+	if(id_num[i] != 0)
+	  continue;
+
+
+	ARRAY<int> group;
+	group.Append(i);
+	for(int j=0; j<idmaps_edge.Size(); j++)
+	  {
+	    startsize = group.Size();
+	    for(int k=0; k<startsize; k++)
+	      {
+		int id = (*idmaps_edge[j])[group[k]];
+		if(id != 0 && !group.Contains(id))
+		  {
+		    group.Append(id);
+		    id_num[id] = j+1+id_num[group[k]];
+		  }
+	      }
+	  }
+	if(group.Size() > 1)
+	  {
+	    id_num[i] = 1;
+	    id_groups.Append(new ARRAY<int>(group));
+	    if(group.Size() == 2)
+	      {
+		id_type[i] = 1;
+		id_type[group[1]] = 2;
+		n2++;
+	      }
+	    else if(group.Size() == 4)
+	      {
+		id_type[i] = 3;
+		for(int j=1; j<group.Size(); j++)
+		  id_type[group[j]] = 4;
+		n4++;
+	      }
+	    else
+	      {
+		cerr << "ERROR: edge identification group size = " << group.Size() << endl;
+		(*testout) << "edge group " << group << endl;
+		for(int j=0; j<idmaps_edge.Size(); j++)
+		  {
+		    (*testout) << "edge id map " << j << endl << *idmaps_edge[j] << endl;
+		  }
+	      }
+	  }
+      }
+
+
+
+    for(int i=1; i<=edge2node.Size(); i++)
+      {
+	if(id_num[i] != 0)
+	  continue;
+
+
+	ARRAY<int> group;
+	group.Append(i);
+	for(int j=0; j<idmaps_edge.Size(); j++)
+	  {
+	    startsize = group.Size();
+	    for(int k=0; k<startsize; k++)
+	      {
+		int id = (*idmaps_edge[j])[group[k]];
+		if(id != 0 && !group.Contains(id))
+		  {
+		    group.Append(id);
+		    id_num[id] = j+1+id_num[group[k]];
+		  }
+	      }
+	  }
+	if(group.Size() > 1)
+	  {
+	    id_num[i] = 1;
+	    id_groups.Append(new ARRAY<int>(group));
+	    if(group.Size() == 2)
+	      {
+		id_type[i] = 1;
+		id_type[group[1]] = 2;
+		n2++;
+	      }
+	    else if(group.Size() == 4)
+	      {
+		id_type[i] = 3;
+		for(int j=1; j<group.Size(); j++)
+		  id_type[group[j]] = 4;
+		n4++;
+	      }
+	    else
+	      {
+		cerr << "ERROR: edge identification group size = " << group.Size() << endl;
+		(*testout) << "edge group " << group << endl;
+		for(int j=0; j<idmaps_edge.Size(); j++)
+		  {
+		    (*testout) << "edge id map " << j << endl << *idmaps_edge[j] << endl;
+		  }
+	      }
+	  }
+	
+      }
+
+    
+    for(int i=0; i<edge2node.Size(); i++)
+      outfile << i+1 << " " << nodenum[edge2node[i][0]] << " " << nodenum[edge2node[i][1]] 
+	      << " " << id_type[i+1] << " " << edge_ids[i] << "\n";
+
+    outfile << endl;
+
+    
+
+    outfile << "// Number of Periodic Master Edges:\n"\
+	    << "// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n"\
+	    << n2 << "\n"			      \
+	    << "\n"\
+	    << "// MasterEdgeID, SlaveEdgeID, TranslCode (1=dS1 2=dS2 3=dS1+dS2):\n"\
+	    << "// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n";
+    for(int i=0; i<id_groups.Size(); i++)
+      {
+	if(id_groups[i]->Size() != 2)
+	  continue;
+
+	for(int j=0; j<id_groups[i]->Size(); j++)
+	  outfile << (*id_groups[i])[j] << " ";
+	for(int j=1; j<id_groups[i]->Size(); j++)
+	  outfile << id_num[(*id_groups[i])[j]] << " ";
+	outfile << "\n";
+
+	delete id_groups[i];
+	id_groups[i] = NULL;
+      }
+    outfile << endl;
+
+    outfile << "// Number of Corner Periodic Master Edges:\n"		\
+	    << "// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n"\
+	    << n4 << "\n"				     \
+	    << "\n"\
+	    << "// MasterEdgeID, 3 SlaveEdgeID's, 3 TranslCode (1=dS1 2=dS2 3=dS1+dS2):\n"\
+	    << "// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n";
+    for(int i=0; i<id_groups.Size(); i++)
+      {
+	if(!id_groups[i] || id_groups[i]->Size() != 4)
+	  continue;
+
+	for(int j=0; j<id_groups[i]->Size(); j++)
+	  outfile << (*id_groups[i])[j] << " ";
+	for(int j=1; j<id_groups[i]->Size(); j++)
+	  outfile << id_num[(*id_groups[i])[j]] << " ";
+	outfile << "\n";
+
+	delete id_groups[i];
+	id_groups[i] = NULL;
+      }
+    outfile << endl;
+
+
+    outfile << "// FaceID, EdgeID0, EdgeID1, EdgeID2, FaceType (0=Reg 1=PMaster 2=PSlave), "<<uidpid<<":\n" \
+	    << "// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n";
+
+    
+    
+    ARRAY< ARRAY<int>* > edge_to_face(numedges+1);
+    for(int i=0; i<edge_to_face.Size(); i++)
+      edge_to_face[i] = new ARRAY<int>;
+
+    
+    for(int i=0; i<idmaps.Size(); i++)
+      {
+	idmaps[i]->SetSize(numfaces);
+	(*idmaps[i]) = 0;
+      }
+
+    
+    for(int i=0; i<face2edge.Size(); i++)
+      {
+	for(int j=0; j<idmaps_edge.Size(); j++)
+	  {
+	    int e1id,e2id,e3id;
+	    e1id = (*idmaps_edge[j])[abs(face2edge[i][0])];
+	    e2id = (*idmaps_edge[j])[abs(face2edge[i][1])];
+	    e3id = (*idmaps_edge[j])[abs(face2edge[i][2])];
+	    if(e1id != 0 && e1id != abs(face2edge[i][0]) &&
+	       e2id != 0 && e2id != abs(face2edge[i][1]) &&
+	       e3id != 0 && e3id != abs(face2edge[i][2]))
+	      {
+		Intersection(*edge_to_face[e1id],*edge_to_face[e2id],*edge_to_face[e3id],possible);
+		if(possible.Size() == 1)
+		  {
+		    (*idmaps[j])[possible[0]] = i+1;
+		    (*idmaps[j])[i+1] = possible[0];
+		  }
+		else if(possible.Size() > 0)
+		  cerr << "ERROR: too many possible face identifications" << endl;
+	      }
+	  }
+
+	edge_to_face[abs(face2edge[i][0])]->Append(i+1);
+	edge_to_face[abs(face2edge[i][1])]->Append(i+1);
+	edge_to_face[abs(face2edge[i][2])]->Append(i+1);
+      }
+
+    for(int i=0; i<edge_to_face.Size(); i++)
+      delete edge_to_face[i];
+
+
+    for(int i=0; i<idmaps_edge.Size(); i++)
+      delete idmaps_edge[i];
+
+    
+    id_groups.SetSize(0);
+    id_num.SetSize(numfaces+1);
+    id_num = 0;
+
+    n2 = n4 = n8 = 0;
+
+    for(int i=1; i<=numfaces; i++)
+      {
+	if(id_num[i] != 0)
+	  continue;
+
+	ARRAY<int> group;
+	group.Append(i);
+	for(int j=0; j<idmaps.Size(); j++)
+	  {
+	    startsize = group.Size();
+	    for(int k=0; k<startsize; k++)
+	      {
+		int id = (*idmaps[j])[group[k]];
+		if(id != 0 && !group.Contains(id))
+		  {
+		    group.Append(id);
+		    id_num[id] = j+1+id_num[group[k]];
+		  }
+	      }
+	  }
+	if(group.Size() > 1)
+	  {
+	    id_num[i] = -1;
+	    id_groups.Append(new ARRAY<int>(group));
+	    if(group.Size() == 2)
+	      n2++;
+	    else
+	      cerr << "ERROR: face identification group size = " << group.Size() << endl;
+	  }
+	
+      }
+
+
+    for(int i=0; i<idmaps.Size(); i++)
+      delete idmaps[i];
+
+
+
+
+    for(int i=0; i<face2edge.Size(); i++)
+      {	
+	outfile << i+1 << " ";
+	for(int j=0; j<3; j++)
+	  outfile << face2edge[i][j] << " ";
+
+	if(id_num[i+1] == 0)
+	  outfile << 0;
+	else if(id_num[i+1] == -1)
+	  outfile << 1;
+	else
+	  outfile << 2;
+
+	outfile << " " << face_ids[i] <<"\n";
+      }
+    outfile << endl;
+
+
+    outfile << "// Number of Periodic Master Faces:\n"\
+	    << "// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n"\
+	    << n2 << "\n"			      \
+	    << "\n"\
+	    << "// MasterFaceID, SlaveFaceID, TranslCode (1=dS1 2=dS2):\n"\
+	    << "// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n";
+    for(int i=0; i<id_groups.Size(); i++)
+      {
+	if(id_groups[i]->Size() != 2)
+	  continue;
+
+	for(int j=0; j<id_groups[i]->Size(); j++)
+	  outfile << (*id_groups[i])[j] << " ";
+	for(int j=1; j<id_groups[i]->Size(); j++)
+	  outfile << id_num[(*id_groups[i])[j]] << " ";
+	outfile << "\n";
+
+	delete id_groups[i];
+      }
+    outfile << endl;
+
+    
+
+
+    outfile << "// ElemID, FaceID0, FaceID1, FaceID2, FaceID3, "<<uidpid<<":\n" \
+	    << "// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n";
+
+    for(ElementIndex i=0; i<mesh.GetNE(); i++)
+      {
+	if(elnum[i] >= 0)
+	  {
+	    outfile << elnum[i] << " ";
+	    for(int j=0; j<4; j++)
+	      outfile << element2face[elnum[i]-1][j] << " ";
+
+	    outfile << mesh[i].GetIndex() << "\n";
+	  }
+      }
+    outfile << endl;
+
+    outfile << "// ElemID, NodeID0, NodeID1, NodeID2, NodeID3:\n" \
+	    << "// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n";
+
+    
+    for(ElementIndex i=0; i<mesh.GetNE(); i++)
+      {
+	if(elnum[i] >= 0)
+	  outfile << elnum[i] << " "
+		  << nodenum[mesh[i][1]] << " " << nodenum[mesh[i][0]] << " " << nodenum[mesh[i][2]] << " " << nodenum[mesh[i][3]] << "\n";
+      }
+    outfile << endl;
+    
+
+    
+
+    outfile << "// Physical Object counts (#Obj3D,#Obj2D,#Obj1D,#Obj0D):\n"
+	    << "// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n"
+	    << " "<< numObj3D << " " << numObj2D << " " << numObj1D << " " << numObj0D << "\n" \
+	    << "\n" \
+	    << "// Number of Ports (Ports are a subset of Object2D list):\n" \
+	    << "// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" \
+	    << numports << "\n"						\
+	    << endl;
+
+
+    ARRAY< ARRAY<int> * > groups;
+
+    int maxg = -1;
+    for(int i = 0; i<uid_to_group_3D.Size(); i++)
+      if(uid_to_group_3D[i] > maxg)
+	maxg = uid_to_group_3D[i];
+    for(int i = 0; i<uid_to_group_2D.Size(); i++)
+      if(uid_to_group_2D[i] > maxg)
+	maxg = uid_to_group_2D[i];
+    for(int i = 0; i<uid_to_group_1D.Size(); i++)
+      if(uid_to_group_1D[i] > maxg)
+	maxg = uid_to_group_1D[i];
+    for(int i = 0; i<uid_to_group_0D.Size(); i++)
+      if(uid_to_group_0D[i] > maxg)
+	maxg = uid_to_group_0D[i];
+
+    groups.SetSize(maxg+1);
+    for(int i=0; i<groups.Size(); i++)
+      groups[i] = new ARRAY<int>;
+
+    for(ElementIndex i=0; i<mesh.GetNE(); i++)
+      if(uid_to_group_3D[mesh[i].GetIndex()] >= 0)
+	groups[uid_to_group_3D[mesh[i].GetIndex()]]->Append(i+1);
+      
+    
+
+
+    outfile << "// Object3D GroupID, #Elems <immediately followed by> ElemID List:\n" \
+	    << "// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n";
+    for(int i=0; i<numObj3D; i++)
+      {
+	outfile << i << " " << groups[i]->Size() << "\n";
+	for(int j=0; j<groups[i]->Size(); j++)
+	  outfile << (*groups[i])[j] << "\n";
+      }
+
+    for(int i=0; i<groups.Size(); i++)
+      groups[i]->SetSize(0);
+
+    for(int i=0; i<face_ids.Size(); i++)
+      if(uid_to_group_2D[face_ids[i]] >= 0)
+	groups[uid_to_group_2D[face_ids[i]]]->Append(i+1);
+      
+
+    outfile << "// Object2D GroupID, #Faces <immediately followed by> FaceID List:\n" \
+	    << "// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n";
+    for(int i=0; i<numObj2D; i++)
+      {
+	outfile << i << " " << groups[i]->Size() << "\n";
+	for(int j=0; j<groups[i]->Size(); j++)
+	  {
+	    outfile << (*groups[i])[j];
+	    if(ports.Contains(face_ids[(*groups[i])[j]-1]))
+	      outfile << " P";
+	    outfile << "\n";
+	  }
+      }
+    outfile << endl;
+
+    
+    for(int i=0; i<groups.Size(); i++)
+      groups[i]->SetSize(0);
+
+    for(int i=0; i<edge_ids.Size(); i++)
+      if(uid_to_group_1D[edge_ids[i]] >= 0)
+	groups[uid_to_group_1D[edge_ids[i]]]->Append(i+1);
+
+
+
+    outfile << "// Object1D GroupID, #Edges <immediately followed by> EdgeID List:\n" \
+	    << "// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n";
+    for(int i=0; i<numObj1D; i++)
+      {
+	outfile << i << " " << groups[i]->Size() << "\n";
+	for(int j=0; j<groups[i]->Size(); j++)
+	  outfile << (*groups[i])[j] << "\n";
+      }
+    outfile << endl;
+
+    
+    for(int i=0; i<groups.Size(); i++)
+      groups[i]->SetSize(0);
+    for(PointIndex i=PointIndex::BASE; i<mesh.GetNP()+PointIndex::BASE; i++)
+      {
+	if(i-PointIndex::BASE < point_ids.Size())
+	  {
+	    if(uid_to_group_0D[point_ids[i]] >= 0)
+	      groups[uid_to_group_0D[point_ids[i]]]->Append(i+1-PointIndex::BASE);
+	  }
+	else
+	  groups[uid_to_group_0D[0]]->Append(i+1-PointIndex::BASE);
+      }
+
+
+    outfile << "// Object0D GroupID, #Nodes <immediately followed by> NodeID List:\n" \
+	    << "// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n";
+    for(int i=0; i<numObj0D; i++)
+      {
+	outfile << i << " " << groups[i]->Size() << "\n";
+	for(int j=0; j<groups[i]->Size(); j++)
+	  outfile << (*groups[i])[j] << "\n";
+      }
+    outfile << endl;
+
+    for(int i=0; i<groups.Size(); i++)
+      delete groups[i];
+
+
+    outfile.close();
+
+    cout << ".tet export done" << endl;
+  }
+}
diff --git a/contrib/Netgen/libsrc/interface/writetochnog.cpp b/contrib/Netgen/libsrc/interface/writetochnog.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..c9ec6e3ce9c6b2c6faae0b771f484a928eb0ce17
--- /dev/null
+++ b/contrib/Netgen/libsrc/interface/writetochnog.cpp
@@ -0,0 +1,108 @@
+//
+//  Write Tochnog file
+//
+//  by
+//
+//  Andreas Seltmann
+//  email:  A.Seltmann@lsw.uni-heidelberg.de
+//
+#include <mystdlib.h>
+
+#include <myadt.hpp>
+#include <linalg.hpp>
+#include <csg.hpp>
+#include <meshing.hpp>
+
+
+namespace netgen
+{
+#include "writeuser.hpp"
+
+
+void WriteTochnogFormat (const Mesh & mesh,
+			 const string & filename)
+{
+  cout << "\nWrite Tochnog Volume Mesh" << endl;
+
+  ofstream outfile (filename.c_str());
+
+  outfile << "(Nodes and Elements generated with NETGEN" << endl;
+  outfile << " " << filename << ")" << endl;
+
+  outfile.precision(8);
+
+  outfile << "(Nodes)" << endl;
+
+  int np = mesh.GetNP();
+  int ne = mesh.GetNE();
+  int i, j;
+
+  for (i = 1; i <= np; i++)
+    {
+      outfile << "node " << " " << i << " ";
+      outfile << mesh.Point(i)(0) << " ";
+      outfile << mesh.Point(i)(1) << " ";
+      outfile << mesh.Point(i)(2) << "\n";
+    }
+
+  int elemcnt = 0; //element counter
+  int finished = 0;
+  int indcnt = 1; //index counter
+
+  while (!finished)
+    {
+      int actcnt = 0;
+      const Element & el1 = mesh.VolumeElement(1);
+      int non = el1.GetNP();
+      if (non == 4)
+	{
+	  outfile << "(Elements, type=-tet4)" << endl;
+	} 
+      else
+	{
+	  cout << "unsupported Element type!!!" << endl;	  
+	}
+
+      for (i = 1; i <= ne; i++)
+	{
+	  const Element & el = mesh.VolumeElement(i);
+	      
+	  if (el.GetIndex() == indcnt)
+	    {
+	      actcnt++;
+	      if (el.GetNP() != non) 
+		{
+		  cout << "different element-types in a subdomain are not possible!!!" << endl;
+		  continue;
+		}
+		  
+	      elemcnt++;
+	      outfile << "element " << elemcnt << " -tet4 ";
+	      if (non == 4)
+		{
+		  outfile << el.PNum(1) << " ";
+		  outfile << el.PNum(2) << " ";
+		  outfile << el.PNum(4) << " ";
+		  outfile << el.PNum(3) << "\n";
+		}
+	      else
+		{
+		  cout << "unsupported Element type!!!" << endl;
+		  for (j = 1; j <= el.GetNP(); j++)
+		    {
+		      outfile << el.PNum(j);
+		      if (j != el.GetNP()) outfile << ", ";
+		    }
+		  outfile << "\n";
+		}
+	    }
+	}	  
+      indcnt++;
+      if (elemcnt == ne) {finished = 1; cout << "all elements found by Index!" << endl;}
+      if (actcnt == 0) {finished = 1;}
+    }
+
+  cout << "done" << endl;
+}
+
+}
diff --git a/contrib/Netgen/libsrc/interface/writeuser.cpp b/contrib/Netgen/libsrc/interface/writeuser.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..92b76520dcbe9d0a8819f2ef7f5ecb754bff6ae4
--- /dev/null
+++ b/contrib/Netgen/libsrc/interface/writeuser.cpp
@@ -0,0 +1,910 @@
+//
+//  Write user dependent output file
+//
+
+#include <mystdlib.h>
+
+#include <myadt.hpp>
+#include <linalg.hpp>
+#include <csg.hpp>
+#include <geometry2d.hpp>
+#include <meshing.hpp>
+
+namespace netgen
+{
+#include "writeuser.hpp"
+
+
+void RegisterUserFormats (ARRAY<const char*> & names)
+{
+  const char *types[] =
+    {
+      "Neutral Format",
+      "Surface Mesh Format" ,
+      "DIFFPACK Format",
+      "TecPlot Format",     
+      "Tochnog Format",
+      "Abaqus Format",
+      "Fluent Format",
+      "Permas Format",
+      "FEAP Format",
+      "Elmer Format",
+      "STL Format",
+      "VRML Format",
+      "Gmsh Format",
+      "JCMwave Format",
+      "TET Format",
+      //      { "Chemnitz Format" },
+      0
+    };
+
+  for (int i = 0; types[i]; i++)
+    names.Append (types[i]);
+}
+
+
+
+bool WriteUserFormat (const string & format,
+		      const Mesh & mesh,
+		      const CSGeometry & geom, 
+		      const string & filename)
+{
+  PrintMessage (1, "Export mesh to file ", filename, 
+		", format is ", format);
+
+  if (format == "Neutral Format")
+    WriteNeutralFormat (mesh, geom, filename);
+
+  else if (format == "Surface Mesh Format")
+    WriteSurfaceFormat (mesh, filename);
+
+  else if (format == "DIFFPACK Format")
+    WriteDiffPackFormat (mesh, geom, filename);
+
+  else if (format == "Tochnog Format")
+    WriteTochnogFormat (mesh, filename);
+
+  else if (format == "TecPlot Format")
+    cerr << "ERROR: TecPlot format currently out of order" << endl;
+      // WriteTecPlotFormat (mesh, geom, filename);
+
+  else if (format == "Abaqus Format")
+    WriteAbaqusFormat (mesh, filename);
+
+  else if (format == "Fluent Format")
+    WriteFluentFormat (mesh, filename);
+
+  else if (format == "Permas Format")
+    WritePermasFormat (mesh, filename);
+
+  else if (format == "FEAP Format")
+    WriteFEAPFormat (mesh, filename);
+
+  else if (format == "Elmer Format")
+    WriteElmerFormat (mesh, filename);
+
+  else if (format == "STL Format")
+    WriteSTLFormat (mesh, filename);
+
+  else if (format == "VRML Format")
+    WriteVRMLFormat (mesh, 1, filename);
+
+  else if (format == "Fepp Format")
+    WriteFEPPFormat (mesh, geom, filename);
+
+  else if (format ==  "EdgeElement Format")
+    WriteEdgeElementFormat (mesh, geom, filename);
+
+  else if (format == "Chemnitz Format")
+    WriteUserChemnitz (mesh, filename);
+
+  else if (format == "Gmsh Format")
+    WriteGmshFormat (mesh, geom, filename);
+ 
+  else if (format == "JCMwave Format")
+    WriteJCMFormat (mesh, geom, filename);
+
+#ifdef OLIVER
+  else if (format == "TET Format")
+    WriteTETFormat( mesh, filename);//, "High Frequency" );
+#endif
+
+  else 
+    {
+      return 1;
+    }
+
+  return 0;
+}
+
+
+
+
+/*
+ *  Neutral mesh format
+ *  points, elements, surface elements
+ */
+
+void WriteNeutralFormat (const Mesh & mesh,
+			 const CSGeometry & geom,
+			 const string & filename)
+{
+  cout << "write neutral, new" << endl;
+  int np = mesh.GetNP();
+  int ne = mesh.GetNE();
+  int nse = mesh.GetNSE();
+  int nseg = mesh.GetNSeg();
+  int i, j;
+  
+  int inverttets = mparam.inverttets;
+  int invertsurf = mparam.inverttrigs;
+
+  ofstream outfile (filename.c_str());
+
+  outfile.precision(6);
+  outfile.setf (ios::fixed, ios::floatfield);
+  outfile.setf (ios::showpoint);
+  
+  outfile << np << "\n";
+  
+  for (i = 1; i <= np; i++)
+    {
+      const Point3d & p = mesh.Point(i);
+      
+      outfile.width(10);
+      outfile << p.X() << " ";
+      outfile.width(9);
+      outfile << p.Y() << " ";
+      if (mesh.GetDimension() == 3)
+	{
+	  outfile.width(9);
+	  outfile << p.Z();
+	  }
+      outfile << "\n";
+    }
+
+  if (mesh.GetDimension() == 3)
+    {
+      outfile << ne << "\n";
+      for (i = 1; i <= ne; i++)
+	{
+	  Element el = mesh.VolumeElement(i);
+	  if (inverttets)
+	    el.Invert();
+	  outfile.width(4);
+	  outfile << el.GetIndex() << "  ";
+	  for (j = 1; j <= el.GetNP(); j++)
+	    {
+	      outfile << " ";
+	      outfile.width(8);
+	      outfile << el.PNum(j);
+	    }
+	  outfile << "\n";
+	}
+    }
+
+  outfile << nse << "\n";
+  for (i = 1; i <= nse; i++)
+    {
+      Element2d el = mesh.SurfaceElement(i);
+      if (invertsurf)
+	el.Invert();
+      outfile.width(4);
+      outfile << mesh.GetFaceDescriptor (el.GetIndex()).BCProperty() << "    ";
+      for (j = 1; j <= el.GetNP(); j++)
+	{
+	  outfile << " ";
+	  outfile.width(8);
+	  outfile << el.PNum(j);
+	}
+      outfile << "\n";
+    }
+
+
+  if (mesh.GetDimension() == 2)
+    {
+      outfile << nseg << "\n";
+      for (i = 1; i <= nseg; i++)
+	{
+	  const Segment & seg = mesh.LineSegment(i);
+	  outfile.width(4);
+	  outfile << seg.si << "    ";
+
+	  outfile << " ";
+	  outfile.width(8);
+	  outfile << seg.p1;
+	  outfile << " ";
+	  outfile.width(8);
+	  outfile << seg.p2;
+
+	  outfile << "\n";
+	}
+    }
+}
+
+
+
+
+
+
+
+
+
+void WriteSurfaceFormat (const Mesh & mesh,
+			 const string & filename)
+{
+  // surface mesh
+  int i, j;
+  
+  cout << "Write Surface Mesh" << endl;
+  
+  ofstream outfile (filename.c_str());
+  
+  outfile << "surfacemesh" << endl;
+  
+  outfile << mesh.GetNP() << endl;
+  for (i = 1; i <= mesh.GetNP(); i++)
+    {
+      for (j = 0; j < 3; j++)
+	{
+	  outfile.width(10);
+	  outfile << mesh.Point(i)(j) << " ";
+	}
+      outfile << endl;
+    }
+  outfile << mesh.GetNSE() << endl;
+  for (i = 1; i <= mesh.GetNSE(); i++)
+    {
+      for (j = 1; j <= 3; j++)
+	{
+	  outfile.width(8);
+	  outfile << mesh.SurfaceElement(i).PNum(j);
+	}
+      outfile << endl;
+    }
+}
+
+
+
+
+
+/*
+ *  save surface mesh as STL file
+ */
+
+void WriteSTLFormat (const Mesh & mesh,
+		     const string & filename)
+{
+  cout << "\nWrite STL Surface Mesh" << endl;
+  
+  ofstream outfile (filename.c_str());
+  
+  int i;
+  
+  outfile.precision(10);
+  
+  outfile << "solid" << endl;
+  
+  for (i = 1; i <= mesh.GetNSE(); i++)
+    {
+      outfile << "facet normal ";
+      const Point3d& p1 = mesh.Point(mesh.SurfaceElement(i).PNum(1));
+      const Point3d& p2 = mesh.Point(mesh.SurfaceElement(i).PNum(2));
+      const Point3d& p3 = mesh.Point(mesh.SurfaceElement(i).PNum(3));
+      
+      Vec3d normal = Cross(p2-p1,p3-p1);
+      if (normal.Length() != 0)
+	{
+	  normal /= (normal.Length());		  
+	}
+      
+      outfile << normal.X() << " " << normal.Y() << " " << normal.Z() << "\n";
+      outfile << "outer loop\n";
+      
+      outfile << "vertex " << p1.X() << " " << p1.Y() << " " << p1.Z() << "\n";
+      outfile << "vertex " << p2.X() << " " << p2.Y() << " " << p2.Z() << "\n";
+      outfile << "vertex " << p3.X() << " " << p3.Y() << " " << p3.Z() << "\n";
+      
+      outfile << "endloop\n";
+      outfile << "endfacet\n"; 
+    }
+  outfile << "endsolid" << endl;
+}
+
+
+
+
+
+/*
+ *
+ *  write surface mesh as VRML file
+ *
+ */
+
+void WriteVRMLFormat (const Mesh & mesh,
+		      bool faces,
+		      const string & filename)
+{
+
+  if (faces)
+
+    {
+      // Output in VRML, IndexedFaceSet is used 
+      // Bartosz Sawicki <sawickib@ee.pw.edu.pl>
+
+      int np = mesh.GetNP();
+      int nse = mesh.GetNSE();
+      int i, j;
+
+      ofstream outfile (filename.c_str());
+
+      outfile.precision(6);
+      outfile.setf (ios::fixed, ios::floatfield);
+      outfile.setf (ios::showpoint);
+
+      outfile << "#VRML V2.0 utf8 \n"
+	         "Background {\n"
+		 "    skyColor [1 1 1]\n"
+     		 "    groundColor [1 1 1]\n"
+		 "}\n"
+		 "Group{ children [\n"
+		 "Shape{ \n"
+		 "appearance Appearance { material Material { }} \n"
+                 "geometry IndexedFaceSet { \n"
+                 "coord Coordinate { point [ \n";  
+	        
+
+      for (i = 1; i <= np; i++)
+        {
+          const Point3d & p = mesh.Point(i);
+          outfile.width(10);
+          outfile << p.X() << " ";
+          outfile << p.Y() << " ";
+          outfile << p.Z() << " \n";
+	}
+
+      outfile << "  ] } \n"
+                 "coordIndex [ \n";               
+	
+      for (i = 1; i <= nse; i++)
+	{
+	  const Element2d & el = mesh.SurfaceElement(i);
+      
+	  for (j = 1; j <= 3; j++)
+	    {
+	      outfile.width(8);
+	      outfile << el.PNum(j)-1;
+	    }
+	  outfile << " -1 \n";
+	}
+      
+      outfile << "  ] \n";
+
+      //define number and RGB definitions of colors
+      outfile << "color Color { color [1 0 0, 0 1 0, 0 0 1, 1 1 0]} \n"
+                 "colorIndex [\n";
+      
+      for (i = 1; i <= nse; i++)
+	{
+	  outfile << mesh.GetFaceDescriptor(mesh.SurfaceElement(i).GetIndex ()).BCProperty();      
+          outfile << endl;
+	}
+      
+      outfile << " ] \n"
+                 "colorPerVertex FALSE \n"
+                 "creaseAngle 0 \n"
+		 "solid FALSE \n"
+                 "ccw FALSE \n"
+		 "convex TRUE \n"
+                 "} } # end of Shape\n"
+		 "] }\n";
+                         
+    } /* end of VRMLFACES */
+
+
+  else
+
+    {
+        // Output in VRML, IndexedLineSet is used
+	// Bartosz Sawicki <sawickib@ee.pw.edu.pl>
+
+      int np = mesh.GetNP();
+      int nse = mesh.GetNSE();
+      int i, j;
+
+      ofstream outfile (filename.c_str());
+
+      outfile.precision(6);
+      outfile.setf (ios::fixed, ios::floatfield);
+      outfile.setf (ios::showpoint);
+
+      outfile << "#VRML V2.0 utf8 \n"
+	         "Background {\n"
+		 "    skyColor [1 1 1]\n"
+     		 "    groundColor [1 1 1]\n"
+		 "}\n"
+		 "Group{ children [\n"
+	         "Shape{ \n"
+		 "appearance Appearance { material Material { }} \n"
+                 "geometry IndexedLineSet { \n"
+                 "coord Coordinate { point [ \n";  
+	        
+
+      for (i = 1; i <= np; i++)
+        {
+          const Point3d & p = mesh.Point(i);
+          outfile.width(10);
+          outfile << p.X() << " ";
+          outfile << p.Y() << " ";
+          outfile << p.Z() << " \n";
+	}
+
+      outfile << "  ] } \n"
+                 "coordIndex [ \n";               
+	
+      for (i = 1; i <= nse; i++)
+	{
+	  const Element2d & el = mesh.SurfaceElement(i);
+      
+	  for (j = 1; j <= 3; j++)
+	    {
+	      outfile.width(8);
+	      outfile << el.PNum(j)-1;
+	    }
+	  outfile.width(8);  
+	  outfile << el.PNum(1)-1; 
+	  outfile << " -1 \n";
+	}
+      
+      outfile << "  ] \n";
+
+/* Uncomment if you want color mesh    
+      outfile << "color Color { color [1 1 1, 0 1 0, 0 0 1, 1 1 0]} \n"
+                 "colorIndex [\n";
+      
+      for (i = 1; i <= nse; i++)
+	{
+	  outfile << mesh.GetFaceDescriptor(mesh.SurfaceElement(i).GetIndex ()).BCProperty();      
+          outfile << endl;
+	}
+      
+      outfile << " ] \n"
+*/ 
+      outfile << "colorPerVertex FALSE \n"
+                 "} } #end of Shape\n"
+		 "] } \n";
+                         
+    }
+
+}
+
+
+
+
+
+
+/*
+ * FEPP .. a finite element package developed at University Linz, Austria
+ */
+void WriteFEPPFormat (const Mesh & mesh,
+		      const CSGeometry & geom,
+		      const string & filename)
+{
+  
+  ofstream outfile (filename.c_str());
+
+  if (mesh.GetDimension() == 3)
+
+    {
+
+      // output for FEPP
+      
+      int np = mesh.GetNP();
+      int ne = mesh.GetNE();
+      int nse = mesh.GetNSE();
+      int ns = mesh.GetNFD();
+      int i, j;
+
+      outfile.precision(5);
+      outfile.setf (ios::fixed, ios::floatfield);
+      outfile.setf (ios::showpoint);
+      
+      outfile << "volumemesh4" << endl;
+      outfile << nse << endl;
+      for (i = 1; i <= nse; i++)
+	{
+	  const Element2d & el = mesh.SurfaceElement(i);
+
+	  //	  int facenr = mesh.facedecoding.Get(el.GetIndex()).surfnr;
+	  outfile.width(4);
+	  outfile << el.GetIndex() << " ";
+	  outfile.width(4);
+	  //	  outfile << mesh.GetFaceDescriptor(el.GetIndex()).BCProperty() << " ";
+	  outfile << mesh.GetFaceDescriptor(el.GetIndex()).BCProperty() << " ";
+	  outfile.width(4);
+	  outfile << el.GetNP() << "    ";
+	  for (j = 1; j <= el.GetNP(); j++)
+	    {
+	      outfile.width(8);
+	      outfile << el.PNum(j);
+	    }
+	  outfile << "\n";
+	}
+
+
+      outfile << ne << "\n";
+      for (i = 1; i <= ne; i++)
+	{
+	  const Element & el = mesh.VolumeElement(i);
+	  outfile.width(4);
+	  outfile << el.GetIndex() << " ";
+	  outfile.width(4);
+	  outfile << el.GetNP() << " ";
+	  for (j = 1; j <= el.GetNP(); j++)
+	    {
+	      outfile.width(8);
+	      outfile << el.PNum(j);
+	    }
+	  outfile << "\n";
+	}
+
+      outfile << np << "\n";
+      for (i = 1; i <= np; i++)
+	{
+	  const Point3d & p = mesh.Point(i);
+
+	  outfile.width(10);
+	  outfile << p.X() << " ";
+	  outfile.width(9);
+	  outfile << p.Y() << " ";
+	  outfile.width(9);
+	  outfile << p.Z() << "\n";
+	}
+
+      /*      
+      if (typ == WRITE_FEPPML)
+	{
+	  int nbn =  mesh.mlbetweennodes.Size();
+	  outfile << nbn << "\n";
+	  for (i = 1; i <= nbn; i++)
+	    outfile << mesh.mlbetweennodes.Get(i).I1() << " "
+		    << mesh.mlbetweennodes.Get(i).I2() << "\n";
+	  
+
+	  //	  int ncon = mesh.connectedtonode.Size();
+	  //	  outfile << ncon << "\n";
+	  //	  for (i = 1; i <= ncon; i++)
+	  //	    outfile << i << " " << mesh.connectedtonode.Get(i) << endl;
+	}
+      */
+
+
+      // write CSG surfaces
+      if (&geom && geom.GetNSurf() >= ns)
+	{
+	  outfile << ns << endl;
+	  for (i = 1; i <= ns; i++)
+	    geom.GetSurface(mesh.GetFaceDescriptor(i).SurfNr())->Print(outfile);
+	}
+      else 
+	outfile << "0" << endl;
+    }
+
+  
+  else
+    
+    { // 2D fepp format
+      
+      ;
+      /*
+      extern SplineGeometry2d * geometry2d;
+      if (geometry2d)
+	Save2DMesh (mesh, &geometry2d->GetSplines(), outfile);
+      else
+	Save2DMesh (mesh, 0, outfile);
+      */
+    }
+}
+
+
+
+
+
+
+/*
+ *  Edge element mesh format
+ *  points, elements, edges
+ */
+
+void WriteEdgeElementFormat (const Mesh & mesh,
+			     const CSGeometry & geom,
+			     const string & filename)
+{
+  cout << "write edge element format" << endl;
+
+  const MeshTopology * top = &mesh.GetTopology();
+  int npoints = mesh.GetNP();
+  int nelements = mesh.GetNE();
+  int nsurfelem = mesh.GetNSE();
+  int nedges = top->GetNEdges();
+  int i, j;
+  
+  int inverttets = mparam.inverttets;
+  int invertsurf = mparam.inverttrigs;
+  ARRAY<int> edges;
+
+  ofstream outfile (filename.c_str());
+
+  outfile.precision(6);
+  outfile.setf (ios::fixed, ios::floatfield);
+  outfile.setf (ios::showpoint);
+
+
+  // vertices with coordinates  
+  outfile << npoints << "\n";
+  for (i = 1; i <= npoints; i++)
+    {
+      const Point3d & p = mesh.Point(i);
+      
+      outfile.width(10);
+      outfile << p.X() << " ";
+      outfile.width(9);
+      outfile << p.Y() << " ";
+      outfile.width(9);
+      outfile << p.Z() << "\n";
+    }
+
+  // element - edge - list
+  outfile << nelements << " " << nedges << "\n";
+  for (i = 1; i <= nelements; i++)
+    {
+      Element el = mesh.VolumeElement(i);
+      if (inverttets)
+      	el.Invert();
+      outfile.width(4);
+      outfile << el.GetIndex() << "  ";
+      outfile.width(8);
+      outfile << el.GetNP();
+      for (j = 1; j <= el.GetNP(); j++)
+	{
+	  outfile << " ";
+	  outfile.width(8);
+	  outfile << el.PNum(j);
+	}
+
+      top->GetElementEdges(i,edges);
+      outfile << endl << "      ";
+      outfile.width(8);
+      outfile << edges.Size();
+      for (j=1; j <= edges.Size(); j++)
+	{
+	  outfile << " ";
+	  outfile.width(8);
+	  outfile << edges[j-1];
+	}
+      outfile << "\n";
+
+      // orientation:
+      top->GetElementEdgeOrientations(i,edges);
+      outfile << "              ";
+      for (j=1; j <= edges.Size(); j++)
+	{
+	  outfile << " ";
+	  outfile.width(8);
+	  outfile << edges[j-1];
+	}
+      outfile << "\n";
+    }
+
+  // surface element - edge - list (with boundary conditions)
+  outfile << nsurfelem << "\n";
+  for (i = 1; i <= nsurfelem; i++)
+    {
+      Element2d el = mesh.SurfaceElement(i);
+      if (invertsurf)
+	el.Invert();
+      outfile.width(4);
+      outfile << mesh.GetFaceDescriptor (el.GetIndex()).BCProperty() << "  ";
+      outfile.width(8);
+      outfile << el.GetNP();
+      for (j = 1; j <= el.GetNP(); j++)
+	{
+	  outfile << " ";
+	  outfile.width(8);
+	  outfile << el.PNum(j);
+	}
+
+      top->GetSurfaceElementEdges(i,edges);
+      outfile << endl << "      ";
+      outfile.width(8);
+      outfile << edges.Size();
+      for (j=1; j <= edges.Size(); j++)
+	{
+	  outfile << " ";
+	  outfile.width(8);
+	  outfile << edges[j-1];
+	}
+      outfile << "\n";
+    }
+
+
+  int v1, v2;
+  // edge - vertex - list
+  outfile << nedges << "\n";
+  for (i=1; i <= nedges; i++)
+    {
+      top->GetEdgeVertices(i,v1,v2);
+      outfile.width(4);
+      outfile << v1;
+      outfile << " ";
+      outfile.width(8);
+      outfile << v2 << endl;
+    }
+}
+
+
+
+
+
+
+
+
+
+#ifdef OLDSTYLE_WRITE
+
+
+void WriteFile (int typ,
+		const Mesh & mesh,
+		const CSGeometry & geom,
+		const char * filename,
+		const char * geomfile,
+		double h)
+{
+
+  
+  int inverttets = mparam.inverttets;
+  int invertsurf = mparam.inverttrigs;
+
+
+
+
+
+
+
+
+  if (typ == WRITE_EDGEELEMENT)
+    {
+      // write edge element file
+      // Peter Harscher, ETHZ
+
+      cout << "Write Edge-Element Format" << endl;
+
+      ofstream outfile (filename);
+
+      int i, j;
+      int ned;
+
+      // hash table representing edges;
+      INDEX_2_HASHTABLE<int> edgeht(mesh.GetNP());
+
+      // list of edges
+      ARRAY<INDEX_2> edgelist;
+
+      // edge (point) on boundary ?
+      BitArray bedge, bpoint(mesh.GetNP());
+      
+      static int eledges[6][2] = { { 1, 2 } , { 1, 3 } , { 1, 4 },
+				   { 2, 3 } , { 2, 4 } , { 3, 4 } };
+
+      // fill hashtable   (point1, point2)  ---->  edgenr
+      for (i = 1; i <= mesh.GetNE(); i++)
+	{
+	  const Element & el = mesh.VolumeElement (i);
+	  INDEX_2 edge;
+	  for (j = 1; j <= 6; j++)
+	    {
+	      edge.I1() = el.PNum (eledges[j-1][0]);
+	      edge.I2() = el.PNum (eledges[j-1][1]);
+	      edge.Sort();
+
+	      if (!edgeht.Used (edge))
+		{
+		  edgelist.Append (edge);
+		  edgeht.Set (edge, edgelist.Size());
+		}
+	    }
+	}
+
+      
+      // set bedges, bpoints
+      bedge.SetSize (edgelist.Size());
+      bedge.Clear();
+      bpoint.Clear();
+
+      for (i = 1; i <= mesh.GetNSE(); i++)
+	{
+	  const Element2d & sel = mesh.SurfaceElement(i);
+	  for (j = 1; j <= 3; j++)
+	    {
+	      bpoint.Set (sel.PNum(j));
+
+	      INDEX_2 edge;
+	      edge.I1() = sel.PNum(j);
+	      edge.I2() = sel.PNum(j%3+1);
+	      edge.Sort();
+
+	      bedge.Set (edgeht.Get (edge));
+	    }
+	}
+
+
+
+      outfile << mesh.GetNE() << endl;
+      // write element ---> point
+      for (i = 1; i <= mesh.GetNE(); i++)
+	{
+	  const Element & el = mesh.VolumeElement(i);
+	  
+	  outfile.width(8);
+	  outfile << i;
+	  for (j = 1; j <= 4; j++)
+	    {
+	      outfile.width(8);
+	      outfile << el.PNum(j);
+	    }
+	  outfile << endl;
+	}
+
+      // write element ---> edge
+      for (i = 1; i <= mesh.GetNE(); i++)
+	{
+	  const Element & el = mesh.VolumeElement (i);
+	  INDEX_2 edge;
+	  for (j = 1; j <= 6; j++)
+	    {
+	      edge.I1() = el.PNum (eledges[j-1][0]);
+	      edge.I2() = el.PNum (eledges[j-1][1]);
+	      edge.Sort();
+
+	      outfile.width(8);
+	      outfile << edgeht.Get (edge);
+	    }
+	  outfile << endl;
+	}
+
+      // write points
+      outfile << mesh.GetNP() << endl;
+      outfile.precision (6);
+      for (i = 1; i <= mesh.GetNP(); i++)
+	{
+	  const Point3d & p = mesh.Point(i);
+	  
+	  for (j = 1; j <= 3; j++)
+	    {
+	      outfile.width(8);
+	      outfile << p.X(j);
+	    }
+	  outfile << "       "
+		  << (bpoint.Test(i) ? "1" : 0) << endl;
+	}
+
+      // write edges
+      outfile << edgelist.Size() << endl;
+      for (i = 1; i <= edgelist.Size(); i++)
+	{
+	  outfile.width(8);
+	  outfile << edgelist.Get(i).I1();
+	  outfile.width(8);
+	  outfile << edgelist.Get(i).I2();
+	  outfile << "       "
+		  << (bedge.Test(i) ? "1" : "0") << endl;
+	}
+    }
+
+
+
+
+}
+#endif
+}
+
diff --git a/contrib/Netgen/libsrc/interface/writeuser.hpp b/contrib/Netgen/libsrc/interface/writeuser.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..61dd5aa27f1ff0e89488ce503850adc81b5cc358
--- /dev/null
+++ b/contrib/Netgen/libsrc/interface/writeuser.hpp
@@ -0,0 +1,140 @@
+#ifndef WRITEUSER
+#define WRITEUSER
+
+/**************************************************************************/
+/* File:    writeuser.hh                                                  */
+/* Authors: many                                                          */
+/* Date:    10. Dec. 97                                                   */
+/**************************************************************************/
+
+
+extern 
+void WriteFile (int typ,
+		const Mesh & mesh,
+		const CSGeometry & geom,
+		const char * filename,
+		const char * geomfile = NULL,
+		double h = 0);
+
+
+
+extern 
+void ReadFile (Mesh & mesh,
+	       const string & filename);
+
+extern 
+void ImportSolution (const char * filename);
+
+
+
+
+
+
+
+extern
+void WriteNeutralFormat (const Mesh & mesh,
+			 const CSGeometry & geom,
+			 const string & filename);
+
+extern
+void WriteSurfaceFormat (const Mesh & mesh,
+			 const string & filename);
+
+extern
+void WriteSTLFormat (const Mesh & mesh,
+		     const string & filename);
+
+extern
+void WriteVRMLFormat (const Mesh & mesh,
+		      bool faces,
+		      const string & filename);
+
+extern
+void WriteFEPPFormat (const Mesh & mesh,
+		      const CSGeometry & geom,
+		      const string & filename);
+
+extern
+void WriteGmshFormat (const Mesh & mesh,
+                         const CSGeometry & geom,
+                         const string & filename);
+
+extern
+void WriteUserChemnitz (const Mesh & mesh,
+			const string & filename);
+
+extern
+void WriteJCMFormat (const Mesh & mesh,
+                     const CSGeometry & geom,
+                     const string & filename);
+
+
+extern 
+void WriteDiffPackFormat (const Mesh & mesh,
+			  const CSGeometry & geom,
+			  const string & filename);
+
+extern
+void WriteTochnogFormat (const Mesh & mesh,
+			 const string & filename);
+
+extern
+void WriteTecPlotFormat (const Mesh & mesh,
+			 const CSGeometry & geom,
+			 const string & filename);
+
+extern
+void WriteAbaqusFormat (const Mesh & mesh,
+			const string & filename);
+
+extern
+void WriteFluentFormat (const Mesh & mesh,
+			const string & filename);
+
+extern
+void WritePermasFormat (const Mesh & mesh,
+			const string & filename);
+
+extern
+void WriteFEAPFormat (const Mesh & mesh,
+		      const string & filename);
+
+extern
+void WriteElmerFormat (const Mesh & mesh,
+		       const string & filename);
+
+
+extern
+void WriteEdgeElementFormat (const Mesh & mesh,
+			     const CSGeometry & geom,
+			     const string & filename);
+
+
+
+#ifdef OLIVER
+extern
+void WriteTETFormat (const Mesh & mesh,
+		     const string & filename);
+
+#endif
+
+extern void ReadTETFormat (Mesh & mesh,
+                      const string & filename);
+
+
+void WriteDolfinFormat (const Mesh & mesh,
+			const string & filename);
+
+
+extern void RegisterUserFormats (ARRAY<const char*> & names);
+
+extern bool WriteUserFormat (const string & format,
+			     const Mesh & mesh,
+			     const CSGeometry & geom, 
+			     const string & filename);
+
+
+
+
+#endif
+
diff --git a/contrib/Netgen/libsrc/interface/wuchemnitz.cpp b/contrib/Netgen/libsrc/interface/wuchemnitz.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..147d0d4d06b2e9badab48195942a4b9e904eb832
--- /dev/null
+++ b/contrib/Netgen/libsrc/interface/wuchemnitz.cpp
@@ -0,0 +1,313 @@
+// Write Chemnitz file format
+
+
+#include <mystdlib.h>
+
+#include <myadt.hpp>
+
+#include <linalg.hpp>
+#include <csg.hpp>
+#include <meshing.hpp>
+
+namespace netgen
+{
+
+class POINT3D
+  {
+  public:
+  POINT3D () { };
+  double x, y, z;
+  };
+
+class VOLELEMENT
+  {
+  public:
+  VOLELEMENT () {};
+  int domnr, p1, p2, p3, p4;
+  int faces[4];
+  };
+  
+class SURFELEMENT
+  {
+  public:
+  SURFELEMENT () { };
+  int snr, p1, p2, p3;
+  };
+  
+
+class FACE
+  {
+  public:
+  FACE () { };
+  int p1, p2, p3;
+  int edges[3];
+  };
+
+class EDGE
+  {
+  public:
+  EDGE () { };
+  int p1, p2;
+  };
+
+static ARRAY<POINT3D> points;
+static ARRAY<VOLELEMENT> volelements;
+static ARRAY<SURFELEMENT> surfelements;
+
+static ARRAY<FACE> faces;
+static ARRAY<EDGE> edges;
+
+
+void ReadFile (char * filename)
+  {
+  int i, n;
+  ifstream infile(filename);
+  char reco[100];
+  
+  
+  infile >> reco;  // file format recognition
+  
+  infile >> n;   // number of surface elements
+  cout << n << " Surface elements" << endl;
+  
+  for (i = 1; i <= n; i++)
+    {
+    SURFELEMENT sel;
+    infile >> sel.snr >> sel.p1 >> sel.p2 >> sel.p3;
+    surfelements.Append (sel);
+    }
+    
+  infile >> n;   // number of volume elements
+  cout << n << " Volume elements" << endl;
+  
+  for (i = 1; i <= n; i++)
+    {
+    VOLELEMENT el;
+    infile >> el.p1 >> el.p2 >> el.p3 >> el.p4;
+    volelements.Append (el);
+    }
+    
+  infile >> n;   // number of points 
+  cout << n << " Points" << endl;
+  
+  for (i = 1; i <= n; i++)
+    {
+    POINT3D p;
+    infile >> p.x >> p.y >> p.z;
+    points.Append (p);
+    }
+  }
+  
+  
+
+void ReadFileMesh (const Mesh & mesh)
+{
+  int i, n;
+  
+  n = mesh.GetNSE();   // number of surface elements
+  cout << n << " Surface elements" << endl;
+  
+  for (i = 1; i <= n; i++)
+    {
+      SURFELEMENT sel;
+      const Element2d & el = mesh.SurfaceElement(i);
+      sel.snr = el.GetIndex();
+      sel.p1 = el.PNum(1);
+      sel.p2 = el.PNum(2);
+      sel.p3 = el.PNum(3);
+      surfelements.Append (sel);
+    }
+    
+  n = mesh.GetNE();   // number of volume elements
+  cout << n << " Volume elements" << endl;
+  
+  for (i = 1; i <= n; i++)
+    {
+      VOLELEMENT el;
+      const Element & nel = mesh.VolumeElement(i);
+      el.p1 = nel.PNum(1);
+      el.p2 = nel.PNum(2);
+      el.p3 = nel.PNum(3);
+      el.p4 = nel.PNum(4);
+      //      infile >> el.p1 >> el.p2 >> el.p3 >> el.p4;
+      volelements.Append (el);
+    }
+    
+  n = mesh.GetNP();   // number of points 
+  cout << n << " Points" << endl;
+  
+  for (i = 1; i <= n; i++)
+    {
+      POINT3D p;
+      Point3d mp = mesh.Point(i);
+      p.x = mp.X();
+      p.y = mp.Y();
+      p.z = mp.Z();
+      //      infile >> p.x >> p.y >> p.z;
+      points.Append (p);
+    }
+  }
+  
+
+
+
+void Convert ()
+  {
+  int i, j, facei, edgei;
+  INDEX_3 i3;
+  INDEX_2 i2;
+
+  INDEX_3_HASHTABLE<int> faceindex(volelements.Size()/5 + 1);
+  INDEX_2_HASHTABLE<int> edgeindex(volelements.Size()/5 + 1);
+  
+  for (i = 1; i <= volelements.Size(); i++)
+    {
+    for (j = 1; j <= 4; j++)
+      {
+      switch (j)
+        {
+        case 1:
+          i3.I1() = volelements.Get(i).p2;
+          i3.I2() = volelements.Get(i).p3;
+          i3.I3() = volelements.Get(i).p4;
+          break;
+        case 2:
+          i3.I1() = volelements.Get(i).p1;
+          i3.I2() = volelements.Get(i).p3;
+          i3.I3() = volelements.Get(i).p4;
+          break;
+         case 3:
+          i3.I1() = volelements.Get(i).p1;
+          i3.I2() = volelements.Get(i).p2;
+          i3.I3() = volelements.Get(i).p4;
+          break;
+         case 4:
+          i3.I1() = volelements.Get(i).p1;
+          i3.I2() = volelements.Get(i).p2;
+          i3.I3() = volelements.Get(i).p3;
+          break;
+		 default:
+			 i3.I1()=i3.I2()=i3.I3()=0;
+        }
+      i3.Sort();
+      if (faceindex.Used (i3)) 
+        facei = faceindex.Get(i3);
+      else
+        {
+        FACE fa;
+        fa.p1 = i3.I1();
+        fa.p2 = i3.I2();
+        fa.p3 = i3.I3();
+        facei = faces.Append (fa);
+        faceindex.Set (i3, facei);
+        } 
+        
+      volelements.Elem(i).faces[j-1] = facei;  
+      }    
+    
+    } 
+ 
+
+  for (i = 1; i <= faces.Size(); i++)
+    {
+    for (j = 1; j <= 3; j++)
+      {
+      switch (j)
+        {
+        case 1:
+          i2.I1() = faces.Get(i).p2;
+          i2.I2() = faces.Get(i).p3;
+          break;
+        case 2:
+          i2.I1() = faces.Get(i).p1;
+          i2.I2() = faces.Get(i).p3;
+          break;
+         case 3:
+          i2.I1() = faces.Get(i).p1;
+          i2.I2() = faces.Get(i).p2;
+          break;
+		 default:
+			 i2.I1()=i2.I2()=0;
+        }
+      if (i2.I1() > i2.I2()) swap (i2.I1(), i2.I2());
+      if (edgeindex.Used (i2)) 
+        edgei = edgeindex.Get(i2);
+      else
+        {
+        EDGE ed;
+        ed.p1 = i2.I1();
+        ed.p2 = i2.I2();
+        edgei = edges.Append (ed);
+        edgeindex.Set (i2, edgei);
+        } 
+        
+      faces.Elem(i).edges[j-1] = edgei;  
+      }    
+    
+    }  
+ 
+  }  
+  
+  
+void WriteFile (ostream & outfile)
+  {
+  int i;
+  
+  outfile 
+  	<< "#VERSION: 1.0" << endl
+  	<< "#PROGRAM: NETGEN" << endl
+  	<< "#EQN_TYPE: POISSON" << endl
+  	<< "#DIMENSION: 3D" << endl
+  	<< "#DEG_OF_FREE: 1" << endl
+  	<< "#DESCRIPTION: I don't know" << endl
+  	<< "##RENUM: not done" << endl
+  	<< "#USER: Kleinzen" << endl
+  	<< "DATE: 10.06.1996" << endl;
+  
+  outfile << "#HEADER:   8" << endl
+  	<< points.Size() << "  " << edges.Size() << "  " 
+  	<< faces.Size() << "  " << volelements.Size() << "  0  0  0  0" << endl;
+  
+  outfile << "#VERTEX:   " << points.Size() << endl;
+  for (i = 1; i <= points.Size(); i++)
+    outfile << "  " << i << "  " << points.Get(i).x << "  " << points.Get(i).y 
+    	<< "  " << points.Get(i).z << endl;
+    	
+  outfile << "#EDGE:  " << edges.Size() << endl;
+  for (i = 1; i <= edges.Size(); i++)
+    outfile << "  " << i << "  1  " 
+    	<< edges.Get(i).p1 << "  " 
+    	<< edges.Get(i).p2 
+    	<< "  0" << endl;
+    
+  outfile << "#FACE:  " << faces.Size() << endl;  
+  for (i = 1; i <= faces.Size(); i++)
+    outfile << "  " << i << "  1  3  " 
+    	<< faces.Get(i).edges[0] << "  " 
+    	<< faces.Get(i).edges[1] << "  " 
+    	<< faces.Get(i).edges[2] << endl;
+    	
+  outfile << "#SOLID:  " << volelements.Size() << endl;
+  for (i = 1; i <= volelements.Size(); i++)
+    outfile << "  " << i << "  1  4  " 
+    	<< volelements.Get(i).faces[0] << "  "
+    	<< volelements.Get(i).faces[1] << "  "
+    	<< volelements.Get(i).faces[2] << "  "
+    	<< volelements.Get(i).faces[3] << endl;
+    	
+  outfile << "#END_OF_DATA" << endl;
+  }
+    
+
+void WriteUserChemnitz (const Mesh & mesh,
+			const string & filename)
+{
+  ofstream outfile (filename.c_str());
+
+  ReadFileMesh (mesh);
+  Convert ();
+  
+  WriteFile (outfile);
+  cout << "Wrote Chemnitz standard file" << endl;
+}
+}
diff --git a/contrib/Netgen/libsrc/linalg/Makefile b/contrib/Netgen/libsrc/linalg/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..1fac5fdd0607be1783487e61166151265494fa69
--- /dev/null
+++ b/contrib/Netgen/libsrc/linalg/Makefile
@@ -0,0 +1,13 @@
+#
+# Makefile for linear algebra library
+#
+src = densemat.cpp polynomial.cpp
+#
+lib = la
+libpath = libsrc/linalg
+#
+#
+include ../makefile.inc
+#
+
+
diff --git a/contrib/Netgen/libsrc/linalg/densemat.cpp b/contrib/Netgen/libsrc/linalg/densemat.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..762792f5c523031c9efd250b5ae545cc598280e3
--- /dev/null
+++ b/contrib/Netgen/libsrc/linalg/densemat.cpp
@@ -0,0 +1,1444 @@
+#include <mystdlib.h>
+
+#include <linalg.hpp>
+
+
+namespace netgen
+{
+  DenseMatrix :: DenseMatrix () 
+  {
+    data = NULL;
+    height = 0;
+    width = 0;
+  }
+
+  DenseMatrix :: DenseMatrix (int h, int w)
+  {
+    if (!w) w = h;
+    width = w;
+    height = h;
+    if (h*w)
+      data = new double[h*w];
+    else 
+      data = 0;
+
+    for (int i = 0 ; i < (h * w); i++)
+      data[i] = 0;
+  }
+
+  /*
+  DenseMatrix :: DenseMatrix (int h, int w, const double * d) 
+    : BaseMatrix (h, w)
+  {
+  int size = h * w;  
+  int i;
+  
+  if (size)
+    {
+      data = new double[size]; 
+      for (i = 0; i < size; i++)
+	data[i] = d[i];
+    }
+  else
+    data = NULL;
+  }    
+  */
+
+  DenseMatrix :: DenseMatrix (const DenseMatrix & m2)
+  {
+    data = NULL; height = width = 0;
+    SetSize (m2.Height(), m2.Width());
+    memcpy (data, m2.data, sizeof(double) * Height() * Width());
+  }
+
+  DenseMatrix :: ~DenseMatrix ()
+  {
+    delete [] data;
+  }
+  
+  
+  void DenseMatrix :: SetSize (int h, int w)
+  {
+    if (!w) w = h;
+    if (height == h && width == w)
+      return;
+          
+    height = h;
+    width = w;
+    
+    delete[] data;
+    
+    if (h*w)  
+      data = new double[h*w];
+    else
+      data = NULL;
+  }
+
+
+  /*
+DenseMatrix & DenseMatrix :: operator= (const BaseMatrix & m2)
+  {
+  int i, j;
+
+  SetSize (m2.Height(), m2.Width());
+
+  if (data)
+    for (i = 1; i <= Height(); i++)
+      for (j = 1; j <= Width(); j++)
+        Set (i, j, m2(i, j));
+  else
+    (*myerr) << "DenseMatrix::Operator=: Matrix not allocated" << endl;
+
+  return *this;
+  }
+  */
+
+
+  DenseMatrix & DenseMatrix :: operator= (const DenseMatrix & m2)
+  {
+    SetSize (m2.Height(), m2.Width());
+    
+    if (data) memcpy (data, m2.data, sizeof(double) * m2.Height() * m2.Width());
+    return *this;
+  }
+
+
+  DenseMatrix & DenseMatrix :: operator+= (const DenseMatrix & m2)
+  {
+    int i;
+    double * p, * q;
+    
+    if (Height() != m2.Height() || Width() != m2.Width())
+    {
+      (*myerr) << "DenseMatrix::Operator+=: Sizes don't fit" << endl;
+      return *this;
+    }
+    
+    if (data)
+      {
+	p = data;
+	q = m2.data;
+	for (i = Width() * Height(); i > 0; i--)
+      {
+      *p += *q;
+      p++;
+      q++;
+      }
+    }
+  else
+    (*myerr) << "DenseMatrix::Operator+=: Matrix not allocated" << endl;
+
+  return *this;
+  }
+
+
+DenseMatrix & DenseMatrix :: operator-= (const DenseMatrix & m2)
+  {
+  int i;
+  double * p, * q;
+
+  if (Height() != m2.Height() || Width() != m2.Width())
+    {
+    (*myerr) << "DenseMatrix::Operator-=: Sizes don't fit" << endl;
+    return *this;
+    }
+
+  if (data)
+    {
+    p = data;
+    q = m2.data;
+    for (i = Width() * Height(); i > 0; i--)
+      {
+      *p -= *q;
+      p++;
+      q++;
+      }
+    }
+  else
+    (*myerr) << "DenseMatrix::Operator-=: Matrix not allocated" << endl;
+
+  return *this;
+  }
+
+
+
+
+  /*
+double & DenseMatrix :: operator() (int i, int j)
+{
+  if (i >= 1 && j >= 1 && i <= height && j <= width)
+    return Elem(i,j);
+  else (*myerr) << "DenseMatrix: index (" << i << "," << j << ") out of range (1.."
+		<< height << ",1.." << width << ")\n";
+  static double dummy = 0;
+  return dummy;
+}
+
+  double DenseMatrix :: operator() (int i, int j) const
+  {
+    if (i >= 1 && j >= 1 && i <= height && j <= width)
+      return Get(i,j);
+    else (*myerr) << "DenseMatrix: index (" << i << "," << j << ") out of range (1.."
+            << height << ",1.." << width << ")\n";
+
+    static double dummy = 0;
+    return dummy;
+  }
+  */
+
+DenseMatrix & DenseMatrix :: operator= (double v)
+  {
+  int i;
+  double * p = data;
+
+  if (data)
+    for (i = width*height; i > 0; i--, p++)
+      *p = v;
+
+  return *this;
+  }
+
+
+
+DenseMatrix & DenseMatrix :: operator*= (double v)
+  {
+  int i;
+  double * p = data;
+
+  if (data)
+    for (i = width*height; i > 0; i--, p++)
+      *p *= v;
+
+  return *this;
+  }
+
+
+double DenseMatrix :: Det () const
+  {
+  if (width != height)
+    {
+    (*myerr) << "DenseMatrix :: Det: width != height" << endl;
+    return 0;
+    }
+
+  switch (width)
+    {
+    case 1: return Get(1, 1);
+    case 2: return Get(1) * Get(4) - Get(2) * Get(3);
+
+    case 3: return Get(1) * Get(5) * Get(9)
+                 + Get(2) * Get(6) * Get(7)
+                 + Get(3) * Get(4) * Get(8)
+                 - Get(1) * Get(6) * Get(8)
+                 - Get(2) * Get(4) * Get(9)
+                 - Get(3) * Get(5) * Get(7);
+    default:
+      {
+      (*myerr) << "Matrix :: Det:  general size not implemented (size=" << width << ")" << endl;
+      return 0;
+      }
+    }
+  }
+
+
+void CalcInverse (const DenseMatrix & m1, DenseMatrix & m2)
+  {
+    //  int i, j, k, n;
+  double det;
+  //  DenseMatrix m1 = hm1;
+
+  if (m1.width != m1.height)
+    {
+    (*myerr) << "CalcInverse: matrix not symmetric" << endl;
+    return;
+    }
+  if (m1.width != m2.width || m1.height != m2.height)
+    {
+    (*myerr) << "CalcInverse: dim(m2) != dim(m1)" << endl;
+    return;
+    }
+
+
+  if (m1.Width() <= 3)
+    {
+    det = m1.Det();
+    if (det == 0)
+      {
+      (*myerr) << "CalcInverse: Matrix singular" << endl;
+      return;
+      }
+
+    det = 1e0 / det;
+    switch (m1.width)
+      {
+      case 1:
+        {
+        m2.Set(1, 1, det);
+        return;
+        }
+      case 2:
+        {
+        m2.Set(1, 1, det * m1.Get(4));
+        m2.Set(2, 2, det * m1.Get(1));  
+        m2.Set(1, 2, - det * m1.Get(2));
+        m2.Set(2, 1, - det * m1.Get(3));
+        return;
+        }
+      case 3:
+        {
+        m2.Set(1, 1,  det * (m1.Get(5) * m1.Get(9) - m1.Get(6) * m1.Get(8)));
+        m2.Set(2, 1, -det * (m1.Get(4) * m1.Get(9) - m1.Get(6) * m1.Get(7)));
+        m2.Set(3, 1,  det * (m1.Get(4) * m1.Get(8) - m1.Get(5) * m1.Get(7)));
+
+        m2.Set(1, 2, -det * (m1.Get(2) * m1.Get(9) - m1.Get(3) * m1.Get(8)));
+        m2.Set(2, 2,  det * (m1.Get(1) * m1.Get(9) - m1.Get(3) * m1.Get(7)));
+        m2.Set(3, 2, -det * (m1.Get(1) * m1.Get(8) - m1.Get(2) * m1.Get(7)));
+
+        m2.Set(1, 3,  det * (m1.Get(2) * m1.Get(6) - m1.Get(3) * m1.Get(5)));
+        m2.Set(2, 3, -det * (m1.Get(1) * m1.Get(6) - m1.Get(3) * m1.Get(4)));
+        m2.Set(3, 3,  det * (m1.Get(1) * m1.Get(5) - m1.Get(2) * m1.Get(4)));
+        return;
+        }
+      }
+    }
+    
+  else
+    {
+      int i, j, k, n;
+      n = m1.Height();
+      
+
+#ifdef CHOL
+      int dots = (n > 200);
+
+      // Cholesky
+      
+      double x;
+      Vector p(n);
+
+      m2 = m1;
+      /*
+      m2.SetSymmetric();
+      if (!m2.Symmetric())
+	cerr << "m should be symmetric for Cholesky" << endl;
+      */
+
+      for (i = 1; i <= n; i++)
+	for (j = 1; j < i; j++)
+	  m2.Elem(j, i) = m2.Get(i, j);
+      
+      for (i = 1; i <= n; i++)
+	{
+	  if (dots && i % 10 == 0)
+	    (*mycout) << "." << flush;
+
+	  for (j = i; j <= n; j++)
+	    {
+	      x = m2.Get(i, j);
+
+	      const double * pik = &m2.Get(i, 1);
+	      const double * pjk = &m2.Get(j, 1);
+
+	      for (k = i-2; k >= 0; --k, ++pik, ++pjk)
+		x -= (*pik) * (*pjk);
+		  
+	      // for (k = i-1; k >= 1; --k)
+	      //   x -= m2.Get(j, k) * m2.Get(i, k);
+
+	      if (i == j)
+		{
+		  if (x <= 0)
+		    {
+		      cerr << "Matrix indefinite 1" << endl;
+		      return;
+		    }
+		  
+		  p.Elem(i) = 1 / sqrt(x);
+		}
+	      else
+		{
+		  m2.Elem(j, i) = x * p.Get(i);
+		}
+	    }
+	}
+
+      for (i = 1; i <= n; i++)
+	m2.Elem(i, i) = 1 / p.Get(i);
+
+      // check: A = L L^t
+
+//       for (i = 1; i <= n; i++)
+// 	for (j = 1; j <= n; j++)
+// 	  {
+// 	    x = 0;
+// 	    for (k = 1; k <= i && k <= j; k++)
+// 	      x += m2.Get(i, k) * m2.Get(j, k);
+// 	    (*testout) << "err " << i << "," << j << " = " << (m1.Get(i, j) - x) << endl;
+// 	  }
+
+
+      
+      // calc L^{-1}, store upper triangle
+      
+      //      DenseMatrix hm(n);
+      //      hm = m2;
+
+      for (i = 1; i <= n; i++)
+	{
+	  if (dots && i % 10 == 0)
+	    (*mycout) << "+" << flush;
+
+	  for (j = i; j <= n; j++)
+	    {
+	      x = 0;
+	      if (j == i) x = 1;
+
+	      const double * pjk = &m2.Get(j, i);
+	      const double * pik = &m2.Get(i, i);
+	      for (k = i; k < j; k++, ++pjk, ++pik)
+		x -= *pik * *pjk;
+
+	      //  for (k = i; k < j; k++)
+	      //  x -= m2.Get(j, k) * m2.Get(i, k);
+
+	      m2.Elem(i, j) = x / m2.Get(j, j);
+	    }
+	}
+      
+//      (*testout) << "check L^-1" << endl;
+//      for (i = 1; i <= n; i++)
+// 	for (j = 1; j <= n; j++)
+// 	  {
+// 	    x = 0;
+// 	    for (k = j; k <= i; k++)
+// 	      x += hm.Get(i, k) * m2.Get(j, k);
+// 	    (*testout) << "i, j = " << i << "," << j << " x = " << x << endl;
+// 	  }
+
+
+      // calc A^-1 = L^-T * L^-1
+
+      for (i = 1; i <= n; i++)
+	{
+	  if (dots && i % 10 == 0)
+	    (*mycout) << "-" << flush;
+
+	  for (j = 1; j <= i; j++)
+	    {
+	      x = 0;
+	      k = i;
+	      if (j > i) k = j;
+
+	      const double * pik = &m2.Get(i, k);
+	      const double * pjk = &m2.Get(j, k);
+
+	      for ( ; k <= n; ++k, ++pik, ++pjk)
+		x += *pik * *pjk;
+	      // for (  ; k <= n; k++)
+	      //   x += m2.Get(i, k) * m2.Get(j, k);
+	      
+	      m2.Elem(i, j) = x;
+	    }
+	}
+	  
+      for (i = 1; i <= n; i++)
+	for (j = 1; j < i; j++)
+	  m2.Elem(j, i) = m2.Get(i, j);
+      
+      if (dots) (*mycout) << endl;
+#endif
+
+
+
+      // Gauss - Jordan - algorithm
+      
+      int r, hi;
+      double max, hr;
+      
+
+      ARRAY<int> p(n);   // pivot-permutation
+      Vector hv(n);
+    
+      
+      m2 = m1;
+
+      /*      
+      if (m2.Symmetric())
+	for (i = 1; i <= n; i++)
+	  for (j = 1; j < i; j++)
+	    m2.Elem(j, i) = m2.Get(i, j);
+      */
+      
+    // Algorithm of Stoer, Einf. i. d. Num. Math, S 145
+      
+      for (j = 1; j <= n; j++)
+	p.Set(j, j);
+      
+      for (j = 1; j <= n; j++)
+	{
+	  // pivot search
+	  
+	  max = fabs(m2.Get(j, j));
+	  r = j;
+	  
+	  for (i = j+1; i <= n ;i++)
+	    if (fabs (m2.Get(i, j)) > max)
+	      {
+		r = i;
+		max = fabs (m2.Get(i, j));
+	      }
+	  
+	  if (max < 1e-20)
+	    {
+	      cerr << "Inverse matrix: matrix singular" << endl;
+	      return;
+	    }
+	  
+	  r = j;
+	  
+	  // exchange rows
+	  if (r > j)
+	    {
+	      for (k = 1; k <= n; k++)
+		{
+		  hr = m2.Get(j, k);
+		  m2.Elem(j, k) = m2.Get(r, k);
+		  m2.Elem(r, k) = hr;
+		}
+	      hi = p.Get(j);
+	      p.Elem(j) = p.Get(r);
+	      p.Elem(r) = hi;
+	    }
+	  
+	  
+	  // transformation
+	  
+	  hr = 1 / m2.Get(j, j);
+	  for (i = 1; i <= n; i++)
+	    m2.Elem(i, j) *= hr;
+	  m2.Elem(j, j) = hr;
+	  
+	  for (k = 1; k <= n; k++)
+	    if (k != j)
+	      {
+		for (i = 1; i <= n; i++)
+		  if (i != j)
+		    m2.Elem(i, k) -= m2.Elem(i, j) * m2.Elem(j, k);
+		m2.Elem(j, k) *= -hr;
+	      }
+	}
+      
+      // col exchange
+      
+      for (i = 1; i <= n; i++)
+	{
+	  for (k = 1; k <= n; k++)
+	    hv.Elem(p.Get(k)) = m2.Get(i, k);
+	  for (k = 1; k <= n; k++)
+	    m2.Elem(i, k) = hv.Get(k);
+	}
+
+
+
+    /*
+    if (m1.Symmetric())
+      for (i = 1; i <= n; i++)
+	for (j = 1; j < i; j++)
+	  m1.Elem(j, i) = m1.Get(i, j);
+
+    m2 = 0;
+    
+    for (i = 1; i <= n; i++)
+      m2.Elem(i, i) = 1;
+      
+    for (i = 1; i <= n; i++)
+      {
+	//	(*mycout) << '.' << flush;
+      q = m1.Get(i, i);
+      for (k = 1; k <= n; k++)
+        {
+        m1.Elem(i, k) /= q;
+        m2.Elem(i, k) /= q;
+        }
+        
+      for (j = i+1; j <= n; j++)
+        {
+        q = m1.Elem(j, i);
+
+	double * m1pi = &m1.Elem(i, i);
+	double * m1pj = &m1.Elem(j, i);
+
+	for (k = n; k >= i; --k, ++m1pi, ++m1pj)
+	    *m1pj -= q * (*m1pi);
+
+	double * m2pi = &m2.Elem(i, 1);
+	double * m2pj = &m2.Elem(j, 1);
+
+	for (k = i; k > 0; --k, ++m2pi, ++m2pj)
+	    *m2pj -= q * (*m2pi);
+
+	    //        for (k = 1; k <= n; k++)  
+	    //          {
+	    //          m1.Elem(j, k) -= q * m1.Elem(i, k);
+	    //          m2.Elem(j, k) -= q * m2.Elem(i, k);
+	    //          }
+	  
+        }
+      }  
+            
+    for (i = n; i >= 1; i--)
+      {
+	//	(*mycout) << "+" << flush;
+	for (j = 1; j < i; j++)
+	  {
+	    q = m1.Elem(j, i);
+
+	    double * m2pi = &m2.Elem(i, 1);
+	    double * m2pj = &m2.Elem(j, 1);
+
+	    for (k = n; k > 0; --k, ++m2pi, ++m2pj)
+	      *m2pj -= q * (*m2pi);	    
+
+	    
+	    //	    for (k = 1; k <= n; k++)
+	    //	      {
+	    //		m1.Elem(j, k) -= q * m1.Elem(i, k);
+	    //		m2.Elem(j, k) -= q * m2.Elem(i, k);
+	    //	      }    
+	  }         
+      }
+
+    if (m2.Symmetric())
+      {
+	for (i = 1; i <= n; i++)
+	  for (j = 1; j < i; j++)
+	    m2.Elem(i, j) = m2.Elem(j, i);
+      }
+*/
+    }
+  }
+
+
+void CalcAAt (const DenseMatrix & a, DenseMatrix & m2)
+  {
+  int n1 = a.Height();
+  int n2 = a.Width();
+  int i, j, k;
+  double sum;
+  const double *p, *q, *p0;
+
+  if (m2.Height() != n1 || m2.Width() != n1)
+    {
+    (*myerr) << "CalcAAt: sizes don't fit" << endl;
+    return;
+    }
+
+  for (i = 1; i <= n1; i++)
+    {
+    sum = 0;
+    p = &a.ConstElem(i, 1);
+    for (k = 1; k <= n2; k++)
+      {
+      sum += *p * *p;
+      p++;
+      }
+    m2.Set(i, i, sum);
+
+    p0 = &a.ConstElem(i, 1);
+    q = a.data;
+    for (j = 1; j < i; j++)
+      {
+      sum = 0;
+      p = p0;
+
+      for (k = 1; k <= n2; k++)
+        {
+        sum += *p * *q;
+        p++;
+        q++;
+        }
+      m2.Set(i, j, sum);
+      m2.Set(j, i, sum);
+      }
+    }
+  }
+
+
+
+#ifdef ABC
+BaseMatrix * DenseMatrix :: InverseMatrix (const BitArray * /* inner */) const
+{
+  if (Height() != Width())
+    {
+      (*myerr) << "BaseMatrix::InverseMatrix(): Matrix not symmetric" << endl;
+      return new DenseMatrix(1);
+    }
+  else
+    {
+      if (Symmetric())
+	{	
+	  (*mycout) << "Invmat not available" << endl;
+	  BaseMatrix * invmat = NULL;
+	  return invmat;
+	}
+
+      DenseMatrix * invmat = new DenseMatrix (Height());
+
+      CalcInverse (*this, *invmat);
+      return invmat;
+    }
+}
+#endif
+
+
+
+void CalcAtA (const DenseMatrix & a, DenseMatrix & m2)
+  {
+  int n1 = a.Height();
+  int n2 = a.Width();
+  int i, j, k;
+  double sum;
+
+  if (m2.Height() != n2 || m2.Width() != n2)
+    {
+    (*myerr) << "CalcAtA: sizes don't fit" << endl;
+    return;
+    }
+
+  for (i = 1; i <= n2; i++)
+    for (j = 1; j <= n2; j++)
+      {
+      sum = 0;
+      for (k = 1; k <= n1; k++)
+        sum += a.Get(k, i) * a.Get(k, j);
+      m2.Elem(i, j) = sum;
+      }
+  }
+
+
+
+
+
+
+void CalcABt (const DenseMatrix & a, const DenseMatrix & b, DenseMatrix & m2)
+  {
+  int n1 = a.Height();
+  int n2 = a.Width();
+  int n3 = b.Height();
+  int i, j, k;
+  double sum;
+
+  if (m2.Height() != n1 || m2.Width() != n3 || b.Width() != n2)
+    {
+    (*myerr) << "CalcABt: sizes don't fit" << endl;
+    return;
+    }
+
+  double * pm2 = &m2.Elem(1, 1);
+  const double * pa1 = &a.Get(1, 1);
+
+  for (i = 1; i <= n1; i++)
+    {
+      const double * pb = &b.Get(1, 1);
+      for (j = 1; j <= n3; j++)
+	{
+	  sum = 0;
+	  const double * pa = pa1;
+	  
+	  for (k = 1; k <= n2; k++)
+	    {
+	      sum += *pa * *pb;
+	      pa++; pb++;
+	    }
+	  
+	  *pm2 = sum;
+	  pm2++;
+	}
+      pa1 += n2;
+    }
+  }
+
+
+void CalcAtB (const DenseMatrix & a, const DenseMatrix & b, DenseMatrix & m2)
+  {
+  int n1 = a.Height();
+  int n2 = a.Width();
+  int n3 = b.Width();
+  int i, j, k;
+
+  if (m2.Height() != n2 || m2.Width() != n3 || b.Height() != n1)
+    {
+    (*myerr) << "CalcAtB: sizes don't fit" << endl;
+    return;
+    }
+
+  for (i = 1; i <= n2 * n3; i++)
+    m2.data[i-1] = 0;
+
+  for (i = 1; i <= n1; i++)
+    for (j = 1; j <= n2; j++)
+      {
+	const double va = a.Get(i, j);
+	double * pm2 = &m2.Elem(j, 1);
+	const double * pb = &b.Get(i, 1);
+
+	for (k = 1; k <= n3; ++k, ++pm2, ++pb)
+	  *pm2 += va * *pb;
+	//	for (k = 1; k <= n3; k++)
+	//	  m2.Elem(j, k) += va * b.Get(i, k);
+      }
+  /*
+  for (i = 1; i <= n2; i++)
+    for (j = 1; j <= n3; j++)
+      {
+	sum = 0;
+	for (k = 1; k <= n1; k++)
+	  sum += a.Get(k, i) * b.Get(k, j);
+	m2.Elem(i, j) = sum;
+      }
+      */
+  }
+
+
+
+
+
+
+
+DenseMatrix operator* (const DenseMatrix & m1, const DenseMatrix & m2)
+  {
+  DenseMatrix temp (m1.Height(), m2.Width());
+
+  if (m1.Width() != m2.Height())
+    {
+    (*myerr) << "DenseMatrix :: operator*: Matrix Size does not fit" << endl;
+    }
+  else if (temp.Height() != m1.Height())
+    {
+    (*myerr) << "DenseMatrix :: operator*: temp not allocated" << endl;
+    }
+  else
+    {
+    Mult (m1, m2, temp);
+    }
+  return temp;
+  }
+
+
+void Mult (const DenseMatrix & m1, const DenseMatrix & m2, DenseMatrix & m3)
+  {
+  double sum;
+  double *p1, *p1s, *p1sn, *p1snn, *p2, *p2s, *p2sn, *p3;
+
+  if (m1.Width() != m2.Height() || m1.Height() != m3.Height() ||
+       m2.Width() != m3.Width() )
+    {
+    (*myerr) << "DenseMatrix :: Mult: Matrix Size does not fit" << endl;
+    (*myerr) << "m1: " << m1.Height() << " x " << m1.Width() << endl;
+    (*myerr) << "m2: " << m2.Height() << " x " << m2.Width() << endl;
+    (*myerr) << "m3: " << m3.Height() << " x " << m3.Width() << endl;
+    return;
+    }
+  /*
+  else if (m1.Symmetric() || m2.Symmetric() || m3.Symmetric())
+    {
+    (*myerr) << "DenseMatrix :: Mult: not implemented for symmetric matrices" << endl;
+    return;
+    }
+  */
+  else
+    {
+      //      int i, j, k;
+      int n1 = m1.Height();
+      int n2 = m2.Width();
+      int n3 = m1.Width();
+
+      /*
+      for (i = n1 * n2-1; i >= 0; --i)
+	m3.data[i] = 0;
+
+      const double * pm1 = &m1.Get(1, 1);
+      for (i = 1; i <= n1; i++)
+	{
+	  const double * pm2 = &m2.Get(1, 1);
+	  double * pm3i = &m3.Elem(i, 1);
+
+	  for (j = 1; j <= n3; j++)
+	    {
+	      const double vm1 = *pm1;
+	      ++pm1;
+	      //	      const double vm1 = m1.Get(i, j);
+	      double * pm3 = pm3i;
+	      //	      const double * pm2 = &m2.Get(j, 1);
+
+	      for (k = 0; k < n2; k++)
+		{
+		  *pm3 += vm1 * *pm2;
+		  ++pm2;
+		  ++pm3;
+		}
+
+	    //	    for (k = 1; k <= n2; k++)
+	    //	      m3.Elem(i, k) += m1.Get(i, j) * m2.Get(j, k);
+	    }
+	}
+	*/
+
+      /*
+      for (i = 1; i <= n1; i++)
+	for (j = 1; j <= n2; j++)
+	  {
+	    sum = 0;
+	    for (k = 1; k <= n3; k++)
+	      sum += m1.Get(i, k) * m2.Get(k, j);
+	    m3.Set(i, j, sum);
+	  }
+	  */
+
+
+      /*
+      for (i = 1; i <= n1; i++)
+	{
+	  const double pm1i = &m1.Get(i, 1);
+	  const double pm2j = &m2.Get(1, 1);
+
+	  for (j = 1; j <= n2; j++)
+	    {
+	      double sum = 0;
+	      const double * pm1 = pm1i;
+	      const double * pm2 = pm2j;
+	      pm2j++;
+
+	      for (k = 1; k <= n3; k++)
+		{
+		  sum += *pm1 * *pm2;
+		  ++pm1;
+		  pm2 += n2;
+		}
+	      
+	      m3.Set (i, j, sum);
+	    }
+	}
+	*/
+
+
+      p3 = m3.data;
+      p1s = m1.data;
+      p2sn = m2.data + n2;
+      p1snn = p1s + n1 * n3;
+
+      while (p1s != p1snn)
+	{
+	  p1sn = p1s + n3;
+	  p2s = m2.data;
+	  
+	  while (p2s != p2sn)
+	    {
+	      sum = 0;
+	      p1 = p1s;
+	      p2 = p2s;
+	      p2s++;
+
+	      while (p1 != p1sn)
+		{
+		  sum += *p1 * *p2;
+		  p1++;
+		  p2 += n2;
+		}
+	      *p3++ = sum;
+	    }
+	  p1s = p1sn;
+	}
+    }
+  }  
+
+
+
+DenseMatrix operator+ (const DenseMatrix & m1, const DenseMatrix & m2)
+  {
+  DenseMatrix temp (m1.Height(), m1.Width());
+  int i, j;
+
+  if (m1.Width() != m2.Width() || m1.Height() != m2.Height())
+    {
+    (*myerr) << "BaseMatrix :: operator+: Matrix Size does not fit" << endl;
+    }
+  else if (temp.Height() != m1.Height())
+    {
+    (*myerr) << "BaseMatrix :: operator+: temp not allocated" << endl;
+    }
+  else
+    {
+    for (i = 1; i <= m1.Height(); i++)
+      for (j = 1; j <= m1.Width(); j++)
+        {
+        temp.Set(i, j, m1.Get(i, j) + m2.Get(i, j));
+        }
+    }
+  return temp;
+  }
+
+
+
+
+void Transpose (const DenseMatrix & m1, DenseMatrix & m2)
+{
+  int w = m1.Width();
+  int h = m1.Height();
+  int i, j;
+
+  m2.SetSize (w, h);
+
+  double * pm2 = &m2.Elem(1, 1);
+  for (j = 1; j <= w; j++)
+    {
+      const double * pm1 = &m1.Get(1, j);
+      for (i = 1; i <= h; i++)
+	{
+	  *pm2 = *pm1;
+	  pm2 ++;
+	  pm1 += w;
+	}
+    }
+}
+
+
+/*
+void DenseMatrix :: Mult (const Vector & v, Vector & prod) const
+  {
+  double sum, val;
+  const double * mp, * sp;
+  double * dp;
+  // const Vector & v = bv.CastToVector();
+  // Vector & prod = bprod.CastToVector();
+  
+
+  int n = Height();
+  int m = Width();
+
+  if (prod.Size() != n)
+    prod.SetSize (n);
+
+#ifdef DEVELOP
+  if (!n) 
+    {
+      cout << "DenseMatrix::Mult  mheight = 0" << endl;
+    }
+  if (!m) 
+    {
+      cout << "DenseMatrix::Mult mwidth = 0" << endl;
+    }
+
+  if (m != v.Size())
+    {
+    (*myerr) << "\nMatrix and Vector don't fit" << endl;
+    }
+  else if (Height() != prod.Size())
+    {
+    (*myerr) << "Base_Matrix::operator*(Vector): prod vector not ok" << endl;
+    }
+  else
+#endif
+    {
+      if (Symmetric())
+	{
+	  int i, j;
+
+
+	  for (i = 1; i <= n; i++)
+	    {
+	      sp = &v.Get(1);
+	      dp = &prod.Elem(1);
+	      mp = &Get(i, 1);
+
+	      val = v.Get(i);
+	      sum = Get(i, i) * val;
+
+	      for (j = 1; j < i; ++j, ++mp, ++sp, ++dp)
+		{
+		  sum += *mp * *sp;
+		  *dp += val * *mp;
+		}
+
+	      prod.Elem(i) = sum;
+	    }
+	}
+      else
+	{
+	  mp = data;
+	  dp = &prod.Elem(1);
+	  for (int i = 1; i <= n; i++)
+	    {
+	      sum = 0;
+	      sp = &v.Get(1);
+	      
+	      for (int j = 1; j <= m; j++)
+		{
+		  //        sum += Get(i,j) * v.Get(j);
+		  sum += *mp * *sp;
+		  mp++;
+		  sp++;
+		}
+	      
+	      //      prod.Set (i, sum);
+	      *dp = sum;
+	      dp++;
+	    }
+	}
+    }
+  }
+*/
+
+void DenseMatrix :: MultTrans (const Vector & v, Vector & prod) const
+{
+  // const Vector & v = (const Vector&)bv; // .CastToVector();
+  // Vector & prod = (Vector & )bprod;     // .CastToVector();
+
+  /*
+  if (Height() != v.Size())
+    {
+    (*myerr) << "\nMatrix and Vector don't fit" << endl;
+    }
+  else if (Width() != prod.Size())
+    {
+    (*myerr) << "Base_Matrix::operator*(Vector): prod vector not ok" << endl;
+    }
+  else
+  */
+    {
+      int i, j;
+      int w = Width(), h = Height();
+      if (prod.Size() != w)
+	prod.SetSize (w);
+
+      const double * pmat = &Get(1, 1);
+      const double * pv = &v.Get(1);
+
+      prod = 0;
+
+      for (i = 1; i <= h; i++)
+	{
+	  double val = *pv;
+	  ++pv;
+
+	  double * pprod = &prod.Elem(1);
+
+	  for (j = w-1; j >= 0; --j, ++pmat, ++pprod)
+	    {
+	      *pprod += val * *pmat;
+	    }
+	}
+	
+      /*
+      double sum;
+
+      for (i = 1; i <= Width(); i++)
+	{
+	  sum = 0;
+	  
+	  for (int j = 1; j <= Height(); j++)
+	    sum += Get(j, i) * v.Get(j);
+	  
+	  prod.Set (i, sum);
+	}
+      */
+    }
+  }
+
+
+void DenseMatrix :: Residuum (const Vector & x, const Vector & b,
+      Vector & res) const
+  {
+  double sum;
+  //   const Vector & x = bx.CastToVector();
+  //  const Vector & b = bb.CastToVector();
+  //  Vector & res = bres.CastToVector();
+
+  res.SetSize (Height());
+
+  if (Width() != x.Size() || Height() != b.Size())
+    {
+    (*myerr) << "\nMatrix and Vector don't fit" << endl;
+    }
+  else if (Height() != res.Size())
+    {
+    (*myerr) << "Base_Matrix::operator*(Vector): prod vector not ok" << endl;
+    }
+  else
+    {
+      int i, j;
+      int h = Height(); 
+      int w = Width();
+      const double * mp = &Get(1, 1);
+
+      for (i = 1; i <= h; i++)
+	{
+	  sum = b.Get(i);
+	  const double * xp = &x.Get(1);
+
+	  for (j = 1; j <= w; ++j, ++mp, ++xp)
+	    sum -= *mp * *xp;
+	  
+	  res.Elem(i) = sum;
+	}
+    }
+  }
+
+#ifdef ABC
+double DenseMatrix :: EvaluateBilinearform (const Vector & hx) const
+  {
+  double sum = 0, hsum;
+  // const Vector & hx = x.CastToVector();
+  int i, j;
+
+  if (Width() != hx.Size() || Height() != hx.Size())
+    {
+    (*myerr) << "Matrix::EvaluateBilinearForm: sizes don't fit" << endl;
+    }
+  else
+    {
+    for (i = 1; i <= Height(); i++)
+      {
+      hsum = 0;
+      for (j = 1; j <= Height(); j++)
+        {
+        hsum += Get(i, j) * hx.Get(j);
+        }
+      sum += hsum * hx.Get(i);
+      }
+    }
+
+//  testout << "sum = " << sum << endl;
+  return sum;
+  }
+
+
+void DenseMatrix :: MultElementMatrix (const ARRAY<int> & pnum, 
+      const Vector & hx, Vector & hy)
+  {
+  int i, j;
+  //  const Vector & hx = x.CastToVector();
+  //  Vector & hy = y.CastToVector();
+
+  if (Symmetric())
+    {
+    for (i = 1; i <= Height(); i++)
+      {
+      for (j = 1; j < i; j++)
+        {
+	hy.Elem(pnum.Get(i)) += Get(i, j) * hx.Get(pnum.Get(j));
+	hy.Elem(pnum.Get(j)) += Get(i, j) * hx.Get(pnum.Get(i));
+	}
+      hy.Elem(pnum.Get(j)) += Get(i, i) * hx.Get(pnum.Get(i));	
+      }
+    }
+  else
+    for (i = 1; i <= Height(); i++)
+      for (j = 1; j <= Width(); j++)
+	hy.Elem(pnum.Get(i)) += Get(i, j) * hx.Get(pnum.Get(j));
+    
+  }
+  
+void DenseMatrix :: MultTransElementMatrix (const ARRAY<int> & pnum, 
+      const Vector & hx, Vector & hy)
+  {
+  int i, j;
+  //  const Vector & hx = x.CastToVector();
+  //  Vector & hy = y.CastToVector();
+
+  if (Symmetric())
+    MultElementMatrix (pnum, hx, hy);
+  else
+    for (i = 1; i <= Height(); i++)
+      for (j = 1; j <= Width(); j++)
+	hy.Elem(pnum.Get(i)) += Get(j, i) * hx.Get(pnum.Get(j));
+  }
+#endif
+
+
+void DenseMatrix :: Solve (const Vector & v, Vector & sol) const
+{
+  DenseMatrix temp (*this);
+  temp.SolveDestroy (v, sol);
+}
+
+
+void DenseMatrix :: SolveDestroy (const Vector & v, Vector & sol)
+  {
+  double q;
+
+  if (Width() != Height())
+    {
+    (*myerr) << "SolveDestroy: Matrix not square";
+    return;
+    }
+  if (Width() != v.Size())
+    {
+    (*myerr) << "SolveDestroy: Matrix and Vector don't fit";
+    return;
+    }
+
+  sol = v;
+  if (Height() != sol.Size())
+    {
+    (*myerr) << "SolveDestroy: Solution Vector not ok";
+    return;
+    }
+
+
+  if (0 /* Symmetric() */)
+    {
+      
+      // Cholesky factorization
+
+      int i, j, k, n;
+      n = Height();
+      
+      // Cholesky
+      
+      double x;
+      Vector p(n);
+
+      for (i = 1; i <= n; i++)
+	for (j = 1; j < i; j++)
+	  Elem(j, i) = Get(i, j);
+      
+      for (i = 1; i <= n; i++)
+	{
+	  // (*mycout) << "." << flush;
+	  for (j = i; j <= n; j++)
+	    {
+	      x = Get(i, j);
+
+	      const double * pik = &Get(i, 1);
+	      const double * pjk = &Get(j, 1);
+
+	      for (k = i-2; k >= 0; --k, ++pik, ++pjk)
+		x -= (*pik) * (*pjk);
+		  
+	      // for (k = i-1; k >= 1; --k)
+	      //   x -= Get(j, k) * Get(i, k);
+
+	      if (i == j)
+		{
+		  if (x <= 0)
+		    {
+		      cerr << "Matrix indefinite" << endl;
+		      return;
+		    }
+		  
+		  p.Elem(i) = 1 / sqrt(x);
+		}
+	      else
+		{
+		  Elem(j, i) = x * p.Get(i);
+		}
+	    }
+	}
+
+      for (i = 1; i <= n; i++)
+        Elem(i, i) = 1 / p.Get(i);
+
+      // A = L L^t 
+      // L stored in left-lower triangle
+
+
+      sol = v;
+
+      // Solve L sol = sol
+
+      for (i = 1; i <= n; i++)
+	{
+	  double val = sol.Get(i);
+
+	  const double * pij = &Get(i, 1);
+	  const double * solj = &sol.Get(1);
+
+	  for (j = 1; j < i; j++, ++pij, ++solj)
+	    val -= *pij * *solj;
+	  //	  for (j = 1; j < i; j++)
+	  //	    val -= Get(i, j) * sol.Get(j);
+
+	  sol.Elem(i) = val / Get(i, i);
+	}
+
+      // Solve L^t sol = sol
+
+      for (i = n; i >= 1; i--)
+	{
+	  double val = sol.Get(i) / Get(i, i);
+	  sol.Elem(i) = val;
+
+	  double * solj = &sol.Elem(1);
+	  const double * pij = &Get(i, 1);
+
+	  for (j = 1; j < i; ++j, ++pij, ++solj)
+	    *solj -= val * *pij;
+	  //	  for (j = 1; j < i; j++)
+	  //	    sol.Elem(j) -= Get(i, j) * val;
+	}
+
+
+    }
+  else
+    {
+      //      (*mycout) << "gauss" << endl;
+      int i, j, k, n = Height();
+      for (i = 1; i <= n; i++)
+	{
+	  for (j = i+1; j <= n; j++)
+	    {
+	      q = Get(j,i) / Get(i,i);
+	      if (q)
+		{
+		  const double * pik = &Get(i, i+1);
+		  double * pjk = &Elem(j, i+1);
+
+		  for (k = i+1; k <= n; ++k, ++pik, ++pjk)
+		    *pjk -= q * *pik;
+		  
+		  //  for (k = i+1; k <= Height(); k++)
+		  //	Elem(j, k) -= q * Get(i,k);
+
+
+		  sol.Elem(j) -= q * sol.Get(i);
+		}
+	    }
+	}
+      
+      for (i = n; i >= 1; i--)
+	{
+	  q = sol.Get(i);
+	  for (j = i+1; j <= n; j++)
+	      q -= Get(i,j) * sol.Get(j);
+
+	  sol.Elem(i) = q / Get(i,i);
+	}
+    }
+  }
+
+
+/*
+BaseMatrix * DenseMatrix :: Copy () const
+  {
+  return new DenseMatrix (*this);
+  }
+*/
+
+
+
+
+ostream & operator<< (ostream & ost, const DenseMatrix & m)
+{
+  for (int i = 0; i < m.Height(); i++)
+    {
+      for (int j = 0; j < m.Width(); j++)
+	ost << m.Get(i+1,j+1) << " ";
+      ost << endl;
+    }
+  return ost;
+}
+
+
+
+}
diff --git a/contrib/Netgen/libsrc/linalg/densemat.hpp b/contrib/Netgen/libsrc/linalg/densemat.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..a63d5a875751b55fb97b008ef4e78230aec2b418
--- /dev/null
+++ b/contrib/Netgen/libsrc/linalg/densemat.hpp
@@ -0,0 +1,284 @@
+#ifndef FILE_DENSEMAT
+#define FILE_DENSEMAT
+
+/**************************************************************************/
+/* File:   densemat.hh                                                    */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   01. Oct. 94                                                    */
+/**************************************************************************/
+
+/** 
+    Data type dense matrix
+*/
+
+
+#include <assert.h>
+
+
+class DenseMatrix
+{
+protected:
+  int height;
+  int width;
+  double * data;
+
+public:
+  ///
+  DenseMatrix ();
+  ///
+  DenseMatrix (int h, int w = 0);
+  ///
+  DenseMatrix (const DenseMatrix & m2);
+  ///
+  ~DenseMatrix ();
+
+  ///
+  void SetSize (int h, int w = 0);
+
+  int Height() const { return height; }
+  int Width() const {return width; }
+
+  double & operator() (int i, int j) { return data[i*width+j]; }
+  double operator() (int i, int j) const { return data[i*width+j]; }
+  double & operator() (int i) { return data[i]; }
+  double operator() (int i) const { return data[i]; }
+
+  ///
+  DenseMatrix & operator= (const DenseMatrix & m2);
+  ///
+  DenseMatrix & operator+= (const DenseMatrix & m2);
+  ///
+  DenseMatrix & operator-= (const DenseMatrix & m2);
+
+  ///
+  DenseMatrix & operator= (double v);
+  ///
+  DenseMatrix & operator*= (double v);
+
+  ///
+  void Mult (const FlatVector & v, FlatVector & prod) const
+  {
+    double sum;
+    const double * mp, * sp;
+    double * dp;
+    
+#ifdef DEBUG
+    if (prod.Size() != height)
+      {
+	cerr << "Mult: wrong vector size " << endl;
+	assert (1);
+	// prod.SetSize (height);
+      }
+    
+
+    if (!height) 
+      {
+	cout << "DenseMatrix::Mult height = 0" << endl;
+      }
+    if (!width) 
+      {
+	cout << "DenseMatrix::Mult width = 0" << endl;
+      }
+    
+    if (width != v.Size())
+      {
+	(*myerr) << "\nMatrix and Vector don't fit" << endl;
+      }
+    else if (Height() != prod.Size())
+      {
+	(*myerr) << "Base_Matrix::operator*(Vector): prod vector not ok" << endl;
+      }
+    else
+#endif
+      {      
+	mp = data;
+	dp = &prod.Elem(1);
+	for (int i = 1; i <= height; i++)
+	  {
+	    sum = 0;
+	    sp = &v.Get(1);
+	    
+	    for (int j = 1; j <= width; j++)
+	      {
+		//        sum += Get(i,j) * v.Get(j);
+		sum += *mp * *sp;
+		mp++;
+		sp++;
+	      }
+	    
+	    *dp = sum;
+	    dp++;
+	  }
+      }
+  }
+
+  ///
+  void MultTrans (const Vector & v, Vector & prod) const;
+  ///
+  void Residuum (const Vector & x, const Vector & b, Vector & res) const;
+  ///
+  double Det () const;
+
+  ///
+  friend DenseMatrix operator* (const DenseMatrix & m1, const DenseMatrix & m2);
+  ///
+  friend DenseMatrix operator+ (const DenseMatrix & m1, const DenseMatrix & m2);
+
+  /// 
+  friend void Transpose (const DenseMatrix & m1, DenseMatrix & m2);
+  ///
+  friend void Mult (const DenseMatrix & m1, const DenseMatrix & m2, DenseMatrix & m3);
+  ///
+  friend void CalcInverse (const DenseMatrix & m1, DenseMatrix & m2);
+  ///
+  friend void CalcAAt (const DenseMatrix & a, DenseMatrix & m2);
+  ///
+  friend void CalcAtA (const DenseMatrix & a, DenseMatrix & m2);
+  ///
+  friend void CalcABt (const DenseMatrix & a, const DenseMatrix & b, DenseMatrix & m2);
+  ///
+  friend void CalcAtB (const DenseMatrix & a, const DenseMatrix & b, DenseMatrix & m2);
+  ///
+  void Solve (const Vector & b, Vector & x) const;
+  ///
+  void SolveDestroy (const Vector & b, Vector & x);
+  ///
+  const double & Get(int i, int j) const { return data[(i-1)*width+j-1]; }
+  ///
+  const double & Get(int i) const { return data[i-1]; }
+  ///
+  void Set(int i, int j, double v) { data[(i-1)*width+j-1] = v; }
+  ///
+  double & Elem(int i, int j) { return data[(i-1)*width+j-1]; }
+  ///
+  const double & ConstElem(int i, int j) const { return data[(i-1)*width+j-1]; }
+};
+
+
+extern ostream & operator<< (ostream & ost, const DenseMatrix & m);
+
+
+
+template <int WIDTH>
+class MatrixFixWidth
+{
+protected:
+  int height;
+  double * data;
+
+public:
+  ///
+  MatrixFixWidth () 
+  { height = 0; data = 0; }
+  ///
+  MatrixFixWidth (int h)
+  { height = h; data = new double[WIDTH*height]; }
+  ///
+  ~MatrixFixWidth ()
+  { delete [] data; }
+
+  void SetSize (int h)
+  {
+    if (h != height)
+      {
+	delete data;
+	height = h;
+	data = new double[WIDTH*height]; 
+      }
+  }
+
+  ///
+  int Height() const { return height; }
+
+  ///
+  int Width() const { return WIDTH; }
+
+  ///
+  MatrixFixWidth & operator= (double v)
+  {
+    for (int i = 0; i < height*WIDTH; i++)
+      data[i] = v; 
+    return *this;
+  }
+
+  ///
+  void Mult (const FlatVector & v, FlatVector & prod) const
+  {
+    double sum;
+    const double * mp, * sp;
+    double * dp;
+
+    /*    
+    if (prod.Size() != height)
+      {
+	cerr << "MatrixFixWidth::Mult: wrong vector size " << endl;
+	assert (1);
+      }
+    */    
+
+    mp = data;
+    dp = &prod[0];
+    for (int i = 0; i < height; i++)
+      {
+	sum = 0;
+	sp = &v[0];
+	
+	for (int j = 0; j < WIDTH; j++)
+	  {
+	    sum += *mp * *sp;
+	    mp++;
+	    sp++;
+	  }
+	    
+	*dp = sum;
+	dp++;
+      }
+  }
+
+  double & operator() (int i, int j)
+  { return data[i*WIDTH+j]; }
+
+  const double & operator() (int i, int j) const
+  { return data[i*WIDTH+j]; }
+
+
+  MatrixFixWidth & operator*= (double v)
+  {
+    if (data)
+      for (int i = 0; i < height*WIDTH; i++)
+        data[i] *= v;
+    return *this;
+  }
+
+
+
+  const double & Get(int i, int j) const { return data[(i-1)*WIDTH+j-1]; }
+  ///
+  const double & Get(int i) const { return data[i-1]; }
+  ///
+  void Set(int i, int j, double v) { data[(i-1)*WIDTH+j-1] = v; }
+  ///
+  double & Elem(int i, int j) { return data[(i-1)*WIDTH+j-1]; }
+  ///
+  const double & ConstElem(int i, int j) const { return data[(i-1)*WIDTH+j-1]; }
+};
+
+
+template <int WIDTH>
+extern ostream & operator<< (ostream & ost, const MatrixFixWidth<WIDTH> & m)
+{
+  for (int i = 0; i < m.Height(); i++)
+    {
+      for (int j = 0; j < m.Width(); j++)
+	ost << m.Get(i+1,j+1) << " ";
+      ost << endl;
+    }
+  return ost;
+};
+
+
+
+extern void CalcInverse (const DenseMatrix & m1, DenseMatrix & m2);
+
+
+#endif
diff --git a/contrib/Netgen/libsrc/linalg/linalg.hpp b/contrib/Netgen/libsrc/linalg/linalg.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..7be9b4adedc36945fd3ce917ae87352b0e8734cf
--- /dev/null
+++ b/contrib/Netgen/libsrc/linalg/linalg.hpp
@@ -0,0 +1,33 @@
+#ifndef FILE_LINALG
+#define FILE_LINALG
+
+/* *************************************************************************/
+/* File:   linalg.hpp                                                      */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   01. Oct. 94                                                    */
+/* *************************************************************************/
+
+/* 
+
+   Data types for basic linear algebra
+   more data types are found in linalgl.hpp
+   
+   The basic concepts include the data types 
+   
+    Vector
+    SparseMatrix
+    DenseMatrix
+
+*/
+
+
+#include "../include/myadt.hpp"
+namespace netgen
+{
+#include "vector.hpp"
+#include "densemat.hpp"
+#include "polynomial.hpp"
+}
+#endif
+
+
diff --git a/contrib/Netgen/libsrc/linalg/polynomial.cpp b/contrib/Netgen/libsrc/linalg/polynomial.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..f947e0a19124088c132db8acd5dc995174a22e62
--- /dev/null
+++ b/contrib/Netgen/libsrc/linalg/polynomial.cpp
@@ -0,0 +1,216 @@
+#include <mystdlib.h>
+#include <linalg.hpp>
+
+namespace netgen
+{
+
+QuadraticPolynomial1V :: 
+QuadraticPolynomial1V (double ac, double acx, double acxx)
+{
+  c = ac;
+  cx = acx;
+  cxx = acxx;
+}
+
+double QuadraticPolynomial1V :: 
+Value (double x)
+{
+  return c + cx * x + cxx * x * x;
+}
+
+double QuadraticPolynomial1V ::  MaxUnitInterval ()
+{
+  // inner max
+  if (cxx < 0 && cx > 0 && cx < -2 * cxx)
+    {
+      return c - 0.25 * cx * cx / cxx;
+    }
+
+  
+  if (cx + cxx > 0)   // right edge
+    return c + cx + cxx;
+
+  // left end
+  return c;
+}
+
+
+
+
+LinearPolynomial2V :: 
+LinearPolynomial2V (double ac, double acx, double acy)
+{
+  c = ac;
+  cx = acx;
+  cy = acy;
+};
+
+
+QuadraticPolynomial2V ::   
+QuadraticPolynomial2V ()
+{
+  ;
+}
+
+
+QuadraticPolynomial2V :: 
+QuadraticPolynomial2V (double ac, double acx, double acy,
+		       double acxx, double acxy, double acyy)
+{
+  c = ac;
+  cx = acx;
+  cy = acy;
+  cxx = acxx;
+  cxy = acxy;
+  cyy = acyy;
+}
+
+void QuadraticPolynomial2V :: 
+Square (const LinearPolynomial2V & lp)
+{
+  c = lp.c * lp.c;
+  cx = 2 * lp.c * lp.cx;
+  cy = 2 * lp.c * lp.cy;
+
+  cxx = lp.cx * lp.cx;
+  cxy = 2 * lp.cx * lp.cy;
+  cyy = lp.cy * lp.cy;
+}
+
+void QuadraticPolynomial2V :: 
+Add (double lam, const QuadraticPolynomial2V & qp2)
+{
+  c += lam * qp2.c;
+  cx += lam * qp2.cx;
+  cy += lam * qp2.cy;
+  cxx += lam * qp2.cxx;
+  cxy += lam * qp2.cxy;
+  cyy += lam * qp2.cyy;
+}
+
+double QuadraticPolynomial2V :: 
+Value (double x, double y)
+{
+  return c + cx * x + cy * y + cxx * x * x + cxy * x * y + cyy * y * y;
+}
+
+/*
+double QuadraticPolynomial2V :: 
+MinUnitSquare ()
+{
+  double x, y;
+  double minv = 1e8;
+  double val;
+  for (x = 0; x <= 1; x += 0.1)
+    for (y = 0; y <= 1; y += 0.1)
+      {
+	val = Value (x, y);
+	if (val < minv)
+	  minv = val;
+      }
+  return minv;
+};
+*/
+
+double QuadraticPolynomial2V :: 
+MaxUnitSquare ()
+{
+  // find critical point
+
+  double maxv = c;
+  double hv;
+
+  double det, x0, y0;
+  det = 4 * cxx * cyy - cxy * cxy;
+
+  if (det > 0)
+    {
+      // definite surface
+      
+      x0 = (-2 * cyy * cx + cxy * cy) / det;
+      y0 = (cxy * cx -2 * cxx * cy) / det;
+
+      if (x0 >= 0 && x0 <= 1 && y0 >= 0 && y0 <= 1)
+	{
+	  hv = Value (x0, y0);
+	  if (hv > maxv) maxv = hv;
+	}
+    }
+  
+  QuadraticPolynomial1V e1(c, cx, cxx);
+  QuadraticPolynomial1V e2(c, cy, cyy);
+  QuadraticPolynomial1V e3(c+cy+cyy, cx+cxy, cxx);
+  QuadraticPolynomial1V e4(c+cx+cxx, cy+cxy, cyy);
+  
+  hv = e1.MaxUnitInterval();
+  if (hv > maxv) maxv = hv;
+  hv = e2.MaxUnitInterval();
+  if (hv > maxv) maxv = hv;
+  hv = e3.MaxUnitInterval();
+  if (hv > maxv) maxv = hv;
+  hv = e4.MaxUnitInterval();
+  if (hv > maxv) maxv = hv;
+
+  return maxv;
+
+  //  (*testout) << "maxv = " << maxv << " =~= ";
+
+  /*
+  double x, y;
+  maxv = -1e8;
+  double val;
+  for (x = 0; x <= 1.01; x += 0.1)
+    for (y = 0; y <= 1.01; y += 0.1)
+      {
+	val = Value (x, y);
+	if (val > maxv)
+	  maxv = val;
+      }
+
+  //  (*testout) << maxv << endl;
+  return maxv;
+  */
+};
+
+
+
+
+double QuadraticPolynomial2V :: 
+MaxUnitTriangle ()
+{
+  // find critical point
+  
+  double maxv = c;
+  double hv;
+
+  double det, x0, y0;
+  det = 4 * cxx * cyy - cxy * cxy;
+
+  if (cxx < 0 && det > 0)
+    { 
+      // definite surface
+      
+      x0 = (-2 * cyy * cx + cxy * cy) / det;
+      y0 = (cxy * cx -2 * cxx * cy) / det;
+
+      if (x0 >= 0 && y0 >= 0 && x0+y0 <= 1)
+	{
+	  return Value (x0, y0);
+	}
+    }
+  
+  
+  QuadraticPolynomial1V e1(c, cx, cxx);
+  QuadraticPolynomial1V e2(c, cy, cyy);
+  QuadraticPolynomial1V e3(c+cy+cyy, cx-cy+cxy-2*cyy, cxx-cxy+cyy);
+  
+  hv = e1.MaxUnitInterval();
+  if (hv > maxv) maxv = hv;
+  hv = e2.MaxUnitInterval();
+  if (hv > maxv) maxv = hv;
+  hv = e3.MaxUnitInterval();
+  if (hv > maxv) maxv = hv;
+
+  return maxv;
+}
+}
diff --git a/contrib/Netgen/libsrc/linalg/polynomial.hpp b/contrib/Netgen/libsrc/linalg/polynomial.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..3108d4dd729172bd644052524aab62f3d150576f
--- /dev/null
+++ b/contrib/Netgen/libsrc/linalg/polynomial.hpp
@@ -0,0 +1,45 @@
+#ifndef FILE_POLYNOMIAL
+#define FILE_POLYNOMIAL
+
+/* *************************************************************************/
+/* File:   polynomial.hh                                                   */
+/* Author: Joachim Schoeberl                                               */
+/* Date:   25. Nov. 99                                                     */
+/* *************************************************************************/
+
+
+class QuadraticPolynomial1V 
+{
+  double c, cx, cxx;
+public:
+  QuadraticPolynomial1V (double ac, double acx, double acxx);
+  double Value (double x);
+  double MaxUnitInterval ();
+};
+
+class LinearPolynomial2V
+{
+  double c, cx, cy;
+public:
+  LinearPolynomial2V (double ac, double acx, double acy);
+  friend class QuadraticPolynomial2V;
+};
+
+
+class QuadraticPolynomial2V
+{
+  double c, cx, cy, cxx, cxy, cyy;
+public:
+  QuadraticPolynomial2V ();
+  QuadraticPolynomial2V (double ac, double acx, double acy,
+			 double acxx, double acxy, double acyy);
+  void Square (const LinearPolynomial2V & lp);
+  void Add (double lam, const QuadraticPolynomial2V & qp);
+
+  double Value (double x, double y);
+  //  double MinUnitSquare ();
+  double MaxUnitSquare ();
+  double MaxUnitTriangle ();
+};
+
+#endif
diff --git a/contrib/Netgen/libsrc/linalg/vector.cpp b/contrib/Netgen/libsrc/linalg/vector.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..b9dabda3669d6f4879de4999f3ef7d1317bcb45a
--- /dev/null
+++ b/contrib/Netgen/libsrc/linalg/vector.cpp
@@ -0,0 +1,786 @@
+#ifdef abc
+#include <mystdlib.h>
+#include <linalg.hpp>
+#include <algorithm>
+
+namespace netgen
+{
+
+double BaseVector :: shit = 0;
+
+// %FD Constructs a vector of length zero
+BaseVector :: BaseVector ()
+  {
+  length = 0;
+  }
+
+// %FD Constructs a vector of given length
+BaseVector :: BaseVector (
+    INDEX alength  // length of the vector
+    )
+  {
+  length = alength;
+  }
+
+// %FD Sets length of the vector, old vector will be destroyed
+void
+BaseVector :: SetLength (
+    INDEX alength        // new length of the vector
+    )
+  {
+  length = alength;
+  }
+
+// %FD Changes length of the vector, old values stay valid
+void
+BaseVector :: ChangeLength (
+    INDEX alength        // new length of the vector
+    )
+  {
+  length = alength;
+  }
+
+
+
+// %FD { Write a vector with the help of the '<<' operator onto a stream }
+ostream &    // stream for further use
+operator<< (
+    ostream & s,            // stream to write vector onto
+    const BaseVector & v   // vector to write
+    )
+  {
+  return v.Print (s);
+  }
+
+
+// %FD{ Divides every component of the vector by the scalar c.
+//      The function checks for division by zero }
+BaseVector &      // result vector
+BaseVector :: operator/= (
+    double c       // scalar to divide by
+    )
+  {
+  if (c)
+    return (*this) *= (1/c);
+  else
+    {
+    (*myerr) << "operator/=: division by zero" << endl;
+    return *this;
+    }
+  }
+
+
+// %FD Creates a copy of the object
+BaseVector *      // pointer to the new vector
+BaseVector :: Copy () const
+  {
+  cerr << "Base_vector::Copy called" << endl << flush;
+  return NULL;
+  }
+
+
+
+
+void BaseVector :: GetElementVector (const ARRAY<INDEX> & pnum,
+				 BaseVector & elvec) const
+{
+  int i;
+  for (i = 1; i <= pnum.Size(); i++)
+    elvec(i) = (*this)(pnum.Get(i));
+}
+
+void BaseVector :: SetElementVector (const ARRAY<INDEX> & pnum,
+				 const BaseVector & elvec)
+{
+  int i;
+  for (i = 1; i <= pnum.Size(); i++)
+    (*this)(pnum.Get(i)) = elvec(i);
+}
+
+
+void BaseVector :: AddElementVector (const ARRAY<INDEX> & pnum,
+				 const BaseVector & elvec)
+{
+  int i;
+  for (i = 1; i <= pnum.Size(); i++)
+    (*this)(pnum.Get(i)) += elvec(i);
+}
+
+
+
+
+
+
+
+
+
+
+
+TempVector :: ~TempVector ()
+  {
+  delete vec;
+  }
+
+TempVector BaseVector :: operator+ (const BaseVector & v2) const
+  {
+  return (*Copy()) += v2;
+  }
+
+TempVector BaseVector :: operator- (const BaseVector & v2) const
+  {
+  return (*Copy()) -= v2;
+  }
+
+TempVector BaseVector :: operator- () const
+  {
+  return (*Copy()) *= -1;
+  }
+
+
+TempVector operator* (const BaseVector & v1, double scal) 
+  {
+  return (*v1.Copy()) *= scal;
+  }
+
+TempVector operator/ (const BaseVector & v1, double scal) 
+  {
+  return (*v1.Copy()) /= scal;
+  }
+
+
+TempVector operator* (double scal, const BaseVector & v1)
+  {
+  return v1 * scal;
+  }
+
+
+
+
+
+BaseVector * TempVector :: Copy () const
+  {
+  return vec->Copy();
+  }
+
+
+
+
+
+
+
+
+
+
+double Vector :: shit = 0;
+
+class clVecpool
+{
+public:
+  ARRAY<double *> vecs;
+  ARRAY<INDEX> veclens;
+
+  ~clVecpool();
+};
+
+clVecpool :: ~clVecpool()
+{
+  int i;
+  for (i = 1; i <= vecs.Size(); i++)
+    delete vecs.Elem(i);
+}
+
+static clVecpool vecpool;
+
+
+
+static double * NewDouble (INDEX len)
+{
+  if (len < 10)
+    return new double[len];
+  else
+    {
+      int i;
+      for (i = 1; i <= vecpool.veclens.Size(); i++)
+	if (vecpool.veclens.Get(i) == len)
+	  {
+	    double * hvec = vecpool.vecs.Get(i);
+	    vecpool.vecs.DeleteElement(i);
+	    vecpool.veclens.DeleteElement(i);
+	    return hvec;
+	  }
+
+      return new double[len];
+    }
+}
+
+static void DeleteDouble (INDEX len, double * dp)
+{
+  if (len < 10)
+    delete [] dp;
+  else
+    {
+      vecpool.vecs.Append (dp);
+      vecpool.veclens.Append (len);
+    }
+}
+
+
+
+Vector :: Vector () : BaseVector()
+  {
+  data = NULL;
+  }
+
+Vector :: Vector (INDEX alength) : BaseVector (alength)
+  {
+  if (length)
+    {
+      //    data = new double[length];
+      data = NewDouble (length);
+
+    if (!data)
+      {
+      length = 0;
+      (*myerr) << "Vector not allocated" << endl;
+      }
+    }
+  else
+    data = NULL;
+  }
+
+
+Vector :: Vector (const Vector & v2)
+  {
+  length = v2.length;
+
+  if (length)
+    {
+      //    data = new double[length];
+      data = NewDouble (length);
+
+    if (data)
+      {
+      memcpy (data, v2.data, length * sizeof (double));
+      }
+    else
+      {
+      length = 0;
+      (*myerr) << "Vector::Vector : Vector not allocated" << endl;
+      }
+    }
+  else
+    data = NULL;
+  }
+
+
+Vector :: ~Vector ()
+{
+  //  veclenfile << "~Vector delete: " << length << endl;
+  if (data) 
+    {
+      DeleteDouble (length, data);
+      //      delete [] data;
+    }
+
+}
+
+void Vector :: SetLength (INDEX alength)
+  {
+  if (length == alength) return;
+
+  if (data) 
+    {
+      DeleteDouble (length, data);
+      //      delete [] data;
+    }
+  data = NULL;
+  length = alength;
+
+  if (length == 0) return;
+  //  data = new double[length];
+  data = NewDouble (length);
+
+  if (!data)
+    {
+    length = 0;
+    (*myerr) << "Vector::SetLength: Vector not allocated" << endl;
+    }
+  }
+
+void Vector :: ChangeLength (INDEX alength)
+{
+  (*mycout) << "Vector::ChangeLength called" << endl;
+  if (length == alength) return;
+  
+  if (alength == 0)
+    {
+      //    delete [] data;
+      DeleteDouble (length, data);
+      length = 0;
+      return;
+    }
+  
+  double * olddata = data;
+
+  data = NewDouble (alength);
+  //  data = new double[alength];
+  if (!data)
+    {
+    length = 0;
+    (*myerr) << "Vector::SetLength: Vector not allocated" << endl;
+    delete [] olddata;
+    }
+
+  memcpy (data, olddata, min2(alength, length));
+
+  delete [] olddata;
+  length = alength;
+  }
+
+/// NEW RM
+void Vector::SetBlockLength (INDEX /* blength */)
+{
+  MyError("BaseVector::SetBlockLength was called for a Vector");
+}
+
+
+double & Vector :: operator() (INDEX i)
+  {
+  if (i >= 1 && i <= length) return Elem(i);
+  else (*myerr) << "\nindex " << i << " out of range ("
+                                << 1 << "," << Length() << ")\n";
+  return shit;
+  }
+
+double Vector :: operator() (INDEX i) const
+  {
+  if (i >= 1 && i <= length) return Get(i);
+  else (*myerr) << "\nindex " << i << " out of range ("
+                                << 1 << "," << Length() << ")\n" << flush;
+  return shit;
+  }
+
+
+
+double Vector :: SupNorm () const
+  {
+  double sup = 0;
+
+  for (INDEX i = 1; i <= Length(); i++)
+    if (fabs (Get(i)) > sup)
+      sup = fabs(Get(i));
+
+  return sup;
+  }
+
+double Vector :: L2Norm () const
+  {
+  double sum = 0;
+
+  for (INDEX i = 1; i <= Length(); i++)
+    sum += Get(i) * Get(i);
+
+  return sqrt (sum);
+  }
+
+double Vector :: L1Norm () const
+  {
+  double sum = 0;
+
+  for (INDEX i = 1; i <= Length(); i++)
+    sum += fabs (Get(i));
+
+  return sum;
+  }
+
+double Vector :: Max () const
+  {
+  if (!Length()) return 0;
+  double m = Get(1);
+  for (INDEX i = 2; i <= Length(); i++)
+    if (Get(i) > m) m = Get(i);
+  return m;
+  }
+
+double Vector :: Min () const
+  {
+  if (!Length()) return 0;
+  double m = Get(1);
+  for (INDEX i = 2; i <= Length(); i++)
+    if (Get(i) < m) m = Get(i);
+  return m;
+  }
+
+
+/*
+ostream & operator<<(ostream & s, const Vector & v)
+  {
+  int w = s.width();
+  if (v.Length())
+    {
+    s.width(0);
+    s << '(';
+    for (INDEX i = 1; i < v.Length(); i++)
+      {
+      s.width(w);
+      s << v.Get(i) << ",";
+      if (i % 8 == 0) s << endl << ' ';
+      }
+    s.width(w);
+    s << v.Get(v.Length()) << ')';
+    }
+  else
+    s << "(Vector not allocated)";
+
+  return s;
+  }
+*/
+
+ostream & Vector :: Print (ostream & s) const
+  {
+  int w = s.width();
+  if (Length())
+    {
+    s.width(0);
+    s << '(';
+    for (INDEX i = 1; i < Length(); i++)
+      {
+      s.width(w);
+      s << Get(i) << ",";
+      if (i % 8 == 0) s << endl << ' ';
+      }
+    s.width(w);
+    s << Get(Length()) << ')';
+    }
+  else
+    s << "(Vector not allocated)";
+
+  return s;
+  }
+
+
+
+BaseVector & Vector :: operator+= (const BaseVector & v2)
+  {
+  const Vector & hv2 = v2.CastToVector();
+
+  if (Length() == hv2.Length())
+    for (INDEX i = 1; i <= Length(); i++)
+      Elem (i) += hv2.Get(i);
+  else
+    (*myerr) << "operator+= illegal dimension" << endl;
+  return *this;
+  }
+
+BaseVector & Vector :: operator-= (const BaseVector & v2)
+  {
+  const Vector & hv2 = v2.CastToVector();
+
+  if (Length() == hv2.Length())
+    for (INDEX i = 1; i <= Length(); i++)
+      Elem (i) -= hv2.Get(i);
+  else
+    (*myerr) << "operator-= illegal dimension" << endl;
+  return *this;
+  }
+
+BaseVector & Vector :: operator*= (double c)
+  {
+  for (INDEX i = 1; i <= Length(); i++)
+    Elem(i) *= c;
+  return *this;
+  }
+
+
+
+BaseVector & Vector :: Add (double scal, const BaseVector & v2)
+  {
+  const Vector & hv2 = v2.CastToVector();
+
+  if (Length() == hv2.Length())
+    {
+    double * p1 = data;
+    double * p2 = hv2.data;
+
+    for (INDEX i = Length(); i > 0; i--)
+      {
+      (*p1) += scal * (*p2);
+      p1++; p2++;
+      }
+    }
+  else
+    (*myerr) << "Vector::Add: illegal dimension" << endl;
+  return *this;
+  }
+
+BaseVector & Vector :: Add2 (double scal, const BaseVector & v2,
+                             double scal3, const BaseVector & v3)
+  {
+  const Vector & hv2 = v2.CastToVector();
+  const Vector & hv3 = v3.CastToVector();
+
+  if (Length() == hv2.Length())
+    {
+    double * p1 = data;
+    double * p2 = hv2.data;
+    double * p3 = hv3.data;
+
+    for (INDEX i = Length(); i > 0; i--)
+      {
+      (*p1) += (scal * (*p2) + scal3 * (*p3));
+      p1++; p2++; p3++;
+      }
+    }
+  else
+    (*myerr) << "Vector::Add: illegal dimension" << endl;
+  return *this;
+  }
+
+BaseVector & Vector :: Set (double scal, const BaseVector & v2)
+  {
+  const Vector & hv2 = v2.CastToVector();
+
+  if (Length() == hv2.Length())
+    {
+    double * p1 = data;
+    double * p2 = hv2.data;
+
+    for (INDEX i = Length(); i > 0; i--)
+      {
+      (*p1) = scal * (*p2);
+      p1++; p2++;
+      }
+    }
+  else
+    (*myerr) << "Vector::Set: illegal dimension" << endl;
+  return *this;
+  }
+
+
+BaseVector & Vector :: Set2 (double scal , const BaseVector & v2,
+      double scal3, const BaseVector & v3)
+{
+  const Vector & hv2 = v2.CastToVector();
+  const Vector & hv3 = v3.CastToVector();
+
+  if (Length() == hv2.Length() && Length() == hv3.Length())
+    {
+      double * p1 = data;
+      double * p2 = hv2.data;
+      double * p3 = hv3.data;
+      
+      for (INDEX i = Length(); i > 0; i--)
+	{
+	  (*p1) = scal * (*p2) + scal3 * (*p3);
+	  p1++; p2++; p3++;
+	}
+    }
+  else
+    (*myerr) << "Vector::Set: illegal dimension" << endl;
+  return *this;
+}
+
+
+void Vector :: GetPart (int startpos, BaseVector & v2) const
+{
+  Vector & hv2 = v2.CastToVector();
+
+  if (Length() >= startpos + v2.Length() - 1)
+    {
+      const double * p1 = &Get(startpos);
+      double * p2 = &hv2.Elem(1);
+      
+      memcpy (p2, p1, hv2.Length() * sizeof(double));
+    }
+  else
+    MyError ("Vector::GetPart: Vector to short");
+}
+
+
+// NEW RM
+void Vector :: SetPart (int startpos, const BaseVector & v2)
+{
+  const Vector & hv2 = v2.CastToVector();
+  INDEX i;
+  INDEX n = v2.Length();
+
+  if (Length() >= startpos + n - 1)
+    {
+      double * p1 = &Elem(startpos);
+      const double * p2 = &hv2.Get(1);
+
+      for (i = 1; i <= n; i++)
+	{
+	  (*p1) = (*p2);
+	  p1++;
+	  p2++;
+	}
+    }
+  else
+    MyError ("Vector::SetPart: Vector to short");
+}
+
+void Vector :: AddPart (int startpos, double val, const BaseVector & v2)
+{
+  const Vector & hv2 = v2.CastToVector();
+  INDEX i;
+  INDEX n = v2.Length();
+
+  if (Length() >= startpos + n - 1)
+    {
+      double * p1 = &Elem(startpos);
+      const double * p2 = &hv2.Get(1);
+
+      for (i = 1; i <= n; i++)
+	{
+	  (*p1) += val * (*p2);
+	  p1++;
+	  p2++;
+	}
+    }
+  else
+    MyError ("Vector::AddPart: Vector to short");
+}
+
+
+
+
+double Vector :: operator* (const BaseVector & v2) const
+  {
+  const Vector & hv2 = v2.CastToVector();
+
+  double sum = 0;
+  double * p1 = data;
+  double * p2 = hv2.data;
+
+  if (Length() == hv2.Length())
+    {
+    for (INDEX i = Length(); i > 0; i--)
+      {
+      sum += (*p1) * (*p2);
+      p1++; p2++;
+      }
+    }
+  else
+    (*myerr) << "Scalarproduct illegal dimension" << endl;
+  return sum;
+  }
+
+void Vector :: SetRandom ()
+  {
+  INDEX i;
+  for (i = 1; i <= Length(); i++)
+    Elem(i) = rand ();
+
+  double l2 = L2Norm();
+  if (l2 > 0)
+    (*this) /= l2;
+    //    Elem(i) = 1.0 / double(i);
+    //    Elem(i) = drand48();
+  }
+
+
+/*
+TempVector Vector :: operator- () const
+  {
+  Vector & sum = *(Vector*)Copy();
+
+  if (sum.Length () == Length())
+    {
+    for (INDEX i = 1; i <= Length(); i++)
+      sum.Set (i, Get(i));
+    }
+  else
+    (*myerr) << "operator+ (Vector, Vector): sum.Length() not ok" << endl;
+  return sum;
+  }
+*/
+
+BaseVector & Vector::operator= (const Vector & v2)
+  {
+  SetLength (v2.Length());
+
+  if (data == v2.data) return *this;
+  
+  if (v2.Length() == Length())
+    memcpy (data, v2.data, sizeof (double) * Length());
+  else
+    (*myerr) << "Vector::operator=: not allocated" << endl;
+
+  return *this;
+  }
+
+BaseVector & Vector::operator= (const BaseVector & v2)
+  {
+  const Vector & hv2 = v2.CastToVector();
+
+  SetLength (hv2.Length());
+
+  if (data == hv2.data) return *this;
+  
+  if (hv2.Length() == Length())
+    memcpy (data, hv2.data, sizeof (double) * Length());
+  else
+    (*myerr) << "Vector::operator=: not allocated" << endl;
+
+  return *this;
+  }
+
+
+BaseVector & Vector::operator= (double scal)
+  {
+  if (!Length()) (*myerr) << "Vector::operator= (double) : data not allocated"
+                      << endl;
+
+  for (INDEX i = 1; i <= Length(); i++)
+    Set (i, scal);
+
+  return *this;
+  }
+
+
+BaseVector * Vector :: Copy () const
+  {
+  return new Vector (*this);
+  }
+
+
+void Vector :: Swap (BaseVector & v2)
+  {
+  Vector & hv2 = v2.CastToVector();
+  swap (length, hv2.length);
+  swap (data, hv2.data);
+  }
+
+
+
+
+void Vector :: GetElementVector (const ARRAY<INDEX> & pnum,
+				 BaseVector & elvec) const
+{
+  int i;
+  Vector & helvec = elvec.CastToVector();
+  for (i = 1; i <= pnum.Size(); i++)
+    helvec.Elem(i) = Get(pnum.Get(i));
+}
+
+void Vector :: SetElementVector (const ARRAY<INDEX> & pnum,
+				 const BaseVector & elvec)
+{
+  int i;
+  const Vector & helvec = elvec.CastToVector();
+  for (i = 1; i <= pnum.Size(); i++)
+    Elem(pnum.Get(i)) = helvec.Get(i);
+}
+
+
+void Vector :: AddElementVector (const ARRAY<INDEX> & pnum,
+				 const BaseVector & elvec)
+{
+  int i;
+  const Vector & helvec = elvec.CastToVector();
+  for (i = 1; i <= pnum.Size(); i++)
+    Elem(pnum.Get(i)) += helvec.Get(i);
+}
+}
+#endif
diff --git a/contrib/Netgen/libsrc/linalg/vector.hpp b/contrib/Netgen/libsrc/linalg/vector.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..c6c2dcce30ad62a36abd84c5f81f8a2c65415891
--- /dev/null
+++ b/contrib/Netgen/libsrc/linalg/vector.hpp
@@ -0,0 +1,138 @@
+#ifndef FILE_VECTOR
+#define FILE_VECTOR
+
+/* *************************************************************************/
+/* File:   vector.hh                                                      */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   01. Oct. 94                                                    */
+/* *************************************************************************/
+
+
+class FlatVector
+{
+protected:
+  int s;
+  double *data;
+public:
+  FlatVector () { ; }
+  FlatVector (int as, double * adata)
+  { s = as; data = adata; }
+
+  int Size () const
+  { return s; }
+
+  FlatVector & operator= (const FlatVector & v) 
+  { memcpy (data, v.data, s*sizeof(double)); return *this; }
+
+  FlatVector & operator= (double scal) 
+  {
+    for (int i = 0; i < s; i++) data[i] = scal; 
+    return *this;
+  }
+
+  double & operator[] (int i) { return data[i]; }
+  const double & operator[] (int i) const { return data[i]; }
+  double & operator() (int i) { return data[i]; }
+  const double & operator() (int i) const { return data[i]; }
+
+  double & Elem (int i) { return data[i-1]; }
+  const double & Get (int i) const { return data[i-1]; }
+  void Set (int i, double val) { data[i-1] = val; }
+
+  FlatVector & operator*= (double scal)
+  {
+    for (int i = 0; i < s; i++) data[i] *= scal;
+    return *this;
+  }
+
+  FlatVector & Add (double scal, const FlatVector & v2)
+  {
+    for (int i = 0; i < s; i++) 
+      data[i] += scal * v2[i];
+    return *this;
+  }
+
+  FlatVector & Set (double scal, const FlatVector & v2)
+  {
+    for (int i = 0; i < s; i++) 
+      data[i] = scal * v2[i];
+    return *this;
+  }
+
+  FlatVector & Set2 (double scal1, const FlatVector & v1,
+		 double scal2, const FlatVector & v2)
+  {
+    for (int i = 0; i < s; i++) 
+      data[i] = scal1 * v1[i] + scal2 * v2[i];
+    return *this;
+  }
+  
+  double L2Norm() const
+  {
+    double sum = 0;
+    for (int i = 0; i < s; i++)
+      sum += data[i] * data[i];
+    return sqrt (sum);
+  }
+
+  friend double operator* (const FlatVector & v1, const FlatVector & v2);
+};
+
+
+
+class Vector : public FlatVector
+{
+
+public:
+  Vector () 
+  { s = 0; data = 0; }
+  Vector (int as)
+  { s = as; data = new double[s]; }
+  ~Vector ()
+  { delete [] data; }
+
+  Vector & operator= (const FlatVector & v) 
+  { memcpy (data, &v.Get(1), s*sizeof(double)); return *this; }
+
+  Vector & operator= (double scal) 
+  {
+    for (int i = 0; i < s; i++) data[i] = scal; 
+    return *this;
+  }
+
+  void SetSize (int as)
+  {
+    if (s != as)
+      {
+	s = as;
+	delete [] data;
+	data = new double [s];
+      }
+  }
+
+};
+
+
+inline double operator* (const FlatVector & v1, const FlatVector & v2)
+{
+  double sum = 0;
+  for (int i = 0; i < v1.s; i++)
+    sum += v1.data[i] * v2.data[i];
+  return sum;
+}
+
+
+
+
+inline ostream & operator<< (ostream & ost, const FlatVector & v)
+{
+  for (int i = 0; i < v.Size(); i++)
+    ost << " " << setw(7) << v[i];
+  return ost;
+}
+
+
+
+#endif
+
+
diff --git a/contrib/Netgen/libsrc/makefile.inc b/contrib/Netgen/libsrc/makefile.inc
new file mode 100644
index 0000000000000000000000000000000000000000..091210bc91fc8e56954fbeacda977965a39f3516
--- /dev/null
+++ b/contrib/Netgen/libsrc/makefile.inc
@@ -0,0 +1,19 @@
+# MODIFIED FOR GMSH - This replaces the original makefile.inc provided by Netgen
+
+include ../../../../variables
+
+INC = ${DASH}I../../../../Common ${DASH}I../include ${DASH}I../interface
+
+CFLAGS = ${OPTIM} ${FLAGS} ${INC} ${SYSINCLUDE} ${DASH}DNO_PARALLEL_THREADS
+
+OBJ = ${src:.cpp=${OBJEXT}}
+
+.SUFFIXES: ${OBJEXT} .cpp
+
+default: ${OBJ}
+
+.cpp${OBJEXT}:
+	${CXX} ${CFLAGS} ${DASH}c $<
+
+clean:
+	${RM} *.o *.obj
diff --git a/contrib/Netgen/libsrc/meshing/Makefile b/contrib/Netgen/libsrc/meshing/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..22c86ee98629764a6a5c347cbcfe0ea29f57d9f6
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/Makefile
@@ -0,0 +1,19 @@
+# MODIFIED FOR GMSH
+src =  meshclass.cpp adfront2.cpp adfront3.cpp geomsearch.cpp global.cpp \
+        meshtool.cpp \
+        netrule2.cpp netrule3.cpp parser2.cpp parser3.cpp ruler2.cpp ruler3.cpp \
+        meshtype.cpp improve2.cpp smoothing2.5.cpp smoothing2.cpp improve3.cpp smoothing3.cpp \
+	improve2gen.cpp meshing2.cpp meshing3.cpp  \
+	localh.cpp delaunay.cpp topology.cpp clusters.cpp \
+	tetrarls.cpp triarls.cpp quadrls.cpp meshfunc.cpp meshfunc2d.cpp \
+	refine.cpp bisect.cpp \
+	boundarylayer.cpp specials.cpp msghandler.cpp \
+	pyramidrls.cpp pyramid2rls.cpp prism2rls.cpp \
+	curvedelems.cpp curvedelems2.cpp curvedelems_new.cpp \
+	validate.cpp
+#
+lib = mesh
+libpath = libsrc/meshing
+#
+include ../makefile.inc
+#
diff --git a/contrib/Netgen/libsrc/meshing/adfront2.cpp b/contrib/Netgen/libsrc/meshing/adfront2.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..37a7c385f6be371098865058c3cd0c3aa3db6ac0
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/adfront2.cpp
@@ -0,0 +1,466 @@
+/*
+  Advancing front class for surfaces
+*/
+
+#include <mystdlib.h>
+#include "meshing.hpp"
+
+
+namespace netgen
+{
+  AdFront2::FrontPoint2 :: FrontPoint2 (const Point<3> & ap, PointIndex agi,
+					MultiPointGeomInfo * amgi, bool aonsurface)
+  {
+    p = ap;
+    globalindex = agi;
+    nlinetopoint = 0;
+    frontnr = INT_MAX-10;
+    onsurface = aonsurface;
+
+    if (amgi)
+      {
+	mgi = new MultiPointGeomInfo (*amgi);
+	for (int i = 1; i <= mgi->GetNPGI(); i++)
+	  if (mgi->GetPGI(i).trignum <= 0)
+	    cout << "Add FrontPoint2, illegal geominfo = " << mgi->GetPGI(i).trignum << endl;
+      }
+    else
+      mgi = NULL;
+  }
+
+
+  AdFront2 :: AdFront2 (const Box3d & aboundingbox)
+    : boundingbox(aboundingbox), 
+      linesearchtree(boundingbox.PMin(), boundingbox.PMax()),
+      pointsearchtree(boundingbox.PMin(), boundingbox.PMax()),
+      cpointsearchtree(boundingbox.PMin(), boundingbox.PMax())
+  {
+    nfl = 0;
+    allflines = 0;
+
+    minval = 0;
+    starti = lines.Begin();
+  }
+
+  AdFront2 :: ~AdFront2 ()
+  {
+    delete allflines;
+  }
+
+
+  void AdFront2 :: PrintOpenSegments (ostream & ost) const
+  {
+    if (nfl > 0)
+      {
+	ost << nfl << " open front segments left:" << endl;
+	for (int i = lines.Begin(); i < lines.End(); i++)
+	  if (lines[i].Valid())
+	    ost << i << ": " 
+                << GetGlobalIndex (lines[i].L().I1()) << "-"
+		<< GetGlobalIndex (lines[i].L().I2()) << endl;
+      }
+  }
+
+  /*
+  void AdFront2 :: GetPoints (ARRAY<Point<3> > & apoints) const
+  {
+    apoints.Append (points);
+    // for (int i = 0; i < points.Size(); i++)
+    // apoints.Append (points[i].P());
+  }
+  */
+
+
+
+  int AdFront2 :: AddPoint (const Point<3> & p, PointIndex globind, 
+                            MultiPointGeomInfo * mgi,
+                            bool pointonsurface)
+  {
+    // inserts at empty position or resizes array
+    int pi;
+
+    if (delpointl.Size() != 0)
+      {
+	pi = delpointl.Last();
+	delpointl.DeleteLast ();
+
+	points[pi] = FrontPoint2 (p, globind, mgi, pointonsurface);
+      }
+    else
+      {
+	pi = points.Append (FrontPoint2 (p, globind, mgi, pointonsurface)) - 1;
+      }
+
+    if (mgi)
+      cpointsearchtree.Insert (p, pi);
+
+    pointsearchtree.Insert (p, pi);
+
+    return pi;
+  }
+
+
+  int AdFront2 :: AddLine (int pi1, int pi2,
+                           const PointGeomInfo & gi1, const PointGeomInfo & gi2)
+  {
+    int minfn;
+    int li;
+
+    FrontPoint2 & p1 = points[pi1];
+    FrontPoint2 & p2 = points[pi2];
+
+
+    nfl++;
+
+    p1.AddLine();
+    p2.AddLine();
+
+    minfn = min2 (p1.FrontNr(), p2.FrontNr());
+    p1.DecFrontNr (minfn+1);
+    p2.DecFrontNr (minfn+1);
+
+    if (dellinel.Size() != 0)
+      {
+	li = dellinel.Last();
+	dellinel.DeleteLast ();
+	lines[li] = FrontLine (INDEX_2(pi1, pi2));
+      }
+    else
+      {
+	li = lines.Append(FrontLine (INDEX_2(pi1, pi2))) - 1;
+      }
+
+  
+    if (!gi1.trignum || !gi2.trignum)
+      {
+	cout << "ERROR: in AdFront::AddLine, illegal geominfo" << endl;
+      }
+  
+    lines[li].SetGeomInfo (gi1, gi2);
+
+    Box3d lbox;
+    lbox.SetPoint(p1.P());
+    lbox.AddPoint(p2.P());
+
+    linesearchtree.Insert (lbox.PMin(), lbox.PMax(), li);
+
+    if (allflines)
+      {
+	if (allflines->Used (INDEX_2 (GetGlobalIndex (pi1), 
+				      GetGlobalIndex (pi2))))
+	  {
+	    cerr << "ERROR Adfront2::AddLine: line exists" << endl;
+	    (*testout) << "ERROR Adfront2::AddLine: line exists" << endl;
+	  }
+
+	allflines->Set (INDEX_2 (GetGlobalIndex (pi1), 
+				 GetGlobalIndex (pi2)), 1);
+      }
+
+    return li;
+  }
+
+
+  void AdFront2 :: DeleteLine (int li)
+  {
+    int pi;
+
+    nfl--;
+
+    for (int i = 1; i <= 2; i++)
+      {
+	pi = lines[li].L().I(i);
+	points[pi].RemoveLine();
+
+	if (!points[pi].Valid())
+	  {
+	    delpointl.Append (pi);
+	    if (points[pi].mgi)
+	      {
+		cpointsearchtree.DeleteElement (pi);
+		delete points[pi].mgi;
+		points[pi].mgi = NULL;
+	      }
+
+            pointsearchtree.DeleteElement (pi);
+	  }
+      }
+
+    if (allflines)
+      {
+	allflines->Set (INDEX_2 (GetGlobalIndex (lines[li].L().I1()),
+				 GetGlobalIndex (lines[li].L().I2())), 2);
+      }
+
+    lines[li].Invalidate();
+    linesearchtree.DeleteElement (li);
+
+    dellinel.Append (li);
+  }
+
+
+  int AdFront2 :: ExistsLine (int pi1, int pi2)
+  {
+    if (!allflines)
+      return 0;
+    if (allflines->Used (INDEX_2(pi1, pi2)))
+      return allflines->Get (INDEX_2 (pi1, pi2));
+    else
+      return 0;
+  }
+
+
+  /*
+  void AdFront2 :: IncrementClass (int li)
+  {
+    lines[li].IncrementClass();
+  }
+
+
+  void AdFront2 :: ResetClass (int li)
+  {
+    lines[li].ResetClass();
+  }
+  */
+
+  int AdFront2 :: SelectBaseLine (Point<3>  & p1, Point<3>  & p2, 
+				  const PointGeomInfo *& geominfo1,
+				  const PointGeomInfo *& geominfo2,
+				  int & qualclass)
+  {
+    int baselineindex = -1; 
+
+    for (int i = starti; i < lines.End(); i++)
+      {
+	if (lines[i].Valid())
+	  {
+	    int hi = lines[i].LineClass() +
+	      points[lines[i].L().I1()].FrontNr() +
+	      points[lines[i].L().I2()].FrontNr();
+	  
+	    if (hi <= minval)
+	      {
+		minval = hi;
+		baselineindex = i;
+		break;
+	      }
+	  }
+      }
+  
+    if (baselineindex == -1)
+      {
+	minval = INT_MAX;
+	for (int i = lines.Begin(); i < lines.End(); i++)
+	  if (lines[i].Valid())
+	    {
+	      int hi = lines[i].LineClass() +
+		points[lines[i].L().I1()].FrontNr() +
+		points[lines[i].L().I2()].FrontNr();
+	    
+	      if (hi < minval)
+		{
+		  minval = hi;
+		  baselineindex = i;
+		}
+	    }
+      }
+    starti = baselineindex+1;
+
+    p1 = points[lines[baselineindex].L().I1()].P();
+    p2 = points[lines[baselineindex].L().I2()].P();
+    geominfo1 = &lines[baselineindex].GetGeomInfo(1);
+    geominfo2 = &lines[baselineindex].GetGeomInfo(2);
+
+    qualclass = lines[baselineindex].LineClass();
+
+    return baselineindex;
+  }
+
+
+
+
+  int AdFront2 :: GetLocals (int baselineindex,
+			     ARRAY<Point3d> & locpoints,
+			     ARRAY<MultiPointGeomInfo> & pgeominfo,
+			     ARRAY<INDEX_2> & loclines,   // local index
+			     ARRAY<INDEX> & pindex,
+			     ARRAY<INDEX> & lindex,
+			     double xh)
+  {
+    // baselineindex += 1-lines.Begin();
+
+    int pstind;
+    Point<3>  midp, p0;
+
+    pstind = lines[baselineindex].L().I1();
+    p0 = points[pstind].P();
+
+    loclines.Append(lines[baselineindex].L());
+    lindex.Append(baselineindex);  //  +1-lines.Begin());
+
+    static ARRAY<int> nearlines;
+    nearlines.SetSize(0);
+    static ARRAY<int> nearpoints;
+    nearpoints.SetSize(0);
+
+    linesearchtree.GetIntersecting (p0 - Vec3d(xh, xh, xh),
+				    p0 + Vec3d(xh, xh, xh),
+				    nearlines);
+
+    pointsearchtree.GetIntersecting (p0 - Vec3d(xh, xh, xh),
+                                     p0 + Vec3d(xh, xh, xh),
+                                     nearpoints);
+
+
+    for (int ii = 1; ii <= nearlines.Size(); ii++)
+      {
+	int i = nearlines.Get(ii);
+	if (lines[i].Valid() && i != baselineindex) //  + 1-lines.Begin())
+	  {
+            loclines.Append(lines[i].L());
+            lindex.Append(i);
+	  }
+      }
+
+    static ARRAY<int> invpindex;
+    invpindex.SetSize (points.Size()); 
+    // invpindex = -1;
+    for (int i = 0; i < nearpoints.Size(); i++)
+      invpindex[nearpoints[i]] = -1;
+
+    for (int i = 0; i < loclines.Size(); i++)
+      {
+	invpindex[loclines[i].I1()] = 0;
+	invpindex[loclines[i].I2()] = 0;
+      }
+
+
+    for (int i = 0; i < loclines.Size(); i++)
+      {
+	for (int j = 0; j < 2; j++)
+	  {
+	    int pi = loclines[i][j];
+	    if (invpindex[pi] == 0)
+	      {
+		pindex.Append (pi);
+		invpindex[pi] = pindex.Size();
+		loclines[i][j] = locpoints.Append (points[pi].P());
+	      }
+	    else
+	      loclines[i][j] = invpindex[pi];
+	  }
+      }
+
+
+    // double xh2 = xh*xh;
+    for (int ii = 0; ii < nearpoints.Size(); ii++)
+      {
+        int i = nearpoints[ii];
+	if (points[i].Valid() && 
+	    points[i].OnSurface() &&
+	    // Dist2 (points.Get(i).P(), p0) <= xh2 &&
+	    invpindex[i] <= 0)
+	  {
+	    invpindex[i] = locpoints.Append (points[i].P());
+	    pindex.Append(i);
+	  }
+      }
+    /*
+    double xh2 = xh*xh;
+    for (i = 1; i <= points.Size(); i++)
+      {
+	if (points.Get(i).Valid() && 
+	    points.Get(i).OnSurface() &&
+	    Dist2 (points.Get(i).P(), p0) <= xh2 &&
+	    invpindex.Get(i) <= 0)
+	  {
+	    invpindex.Elem(i) =
+	      locpoints.Append (points.Get(i).P());
+	    pindex.Append(i);
+	  }
+      }
+    */
+
+    pgeominfo.SetSize (locpoints.Size());
+    for (int i = 0; i < pgeominfo.Size(); i++)
+      pgeominfo[i].Init();
+
+
+    for (int i = 0; i < loclines.Size(); i++)
+      for (int j = 0; j < 2; j++)
+	{
+	  int lpi = loclines[i][j];
+	
+	  const PointGeomInfo & gi = 
+	    lines[lindex[i]].GetGeomInfo (j+1);
+	  pgeominfo.Elem(lpi).AddPointGeomInfo (gi);
+	
+	  /*
+	    if (pgeominfo.Elem(lpi).cnt == MULTIPOINTGEOMINFO_MAX)
+	    break;
+
+	    const PointGeomInfo & gi = 
+	    lines.Get(lindex.Get(i)).GetGeomInfo (j);
+	
+	    PointGeomInfo * pgi = pgeominfo.Elem(lpi).mgi;
+
+	    int found = 0;
+	    for (k = 0; k < pgeominfo.Elem(lpi).cnt; k++)
+	    if (pgi[k].trignum == gi.trignum)
+	    found = 1;
+
+	    if (!found)
+	    {
+	    pgi[pgeominfo.Elem(lpi).cnt] = gi;
+	    pgeominfo.Elem(lpi).cnt++;
+	    }
+	  */
+	}
+
+    for (int i = 0; i < locpoints.Size(); i++)
+      {
+	int pi = pindex[i];
+      
+	if (points[pi].mgi)
+	  for (int j = 1; j <= points[pi].mgi->GetNPGI(); j++)
+	    pgeominfo[i].AddPointGeomInfo (points[pi].mgi->GetPGI(j));
+      }
+   
+    if (loclines.Size() == 1)
+      {
+	cout << "loclines.Size = 1" << endl;
+	(*testout) << "loclines.size = 1" << endl
+		   << " h = " << xh << endl
+		   << " nearline.size = " << nearlines.Size() << endl
+		   << " p0 = " << p0 << endl;
+      }
+
+    return lines[baselineindex].LineClass();
+  }
+
+
+
+  void AdFront2 :: SetStartFront ()
+  {
+    for (int i = lines.Begin(); i < lines.End(); i++)
+      if (lines[i].Valid())
+	for (int j = 1; j <= 2; j++)
+	  points[lines[i].L().I(j)].DecFrontNr(0);
+  }
+
+
+  void AdFront2 :: Print (ostream & ost) const
+  {
+    ost << points.Size() << " Points: " << endl;
+    for (int i = points.Begin(); i < points.End(); i++)
+      if (points[i].Valid())
+	ost << i << "  " << points[i].P() << endl;
+
+    ost << nfl << " Lines: " << endl;
+    for (int i = lines.Begin(); i < lines.End(); i++)
+      if (lines[i].Valid())
+	ost << lines[i].L().I1() << " - " << lines[i].L().I2() << endl;
+
+    ost << flush;
+  }
+}
diff --git a/contrib/Netgen/libsrc/meshing/adfront2.hpp b/contrib/Netgen/libsrc/meshing/adfront2.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..4266d3332ecba37c2fc0d4d192f6826a1bd807ae
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/adfront2.hpp
@@ -0,0 +1,264 @@
+#ifndef FILE_ADFRONT2
+#define FILE_ADFRONT2
+
+/**************************************************************************/
+/* File:   adfront2.hpp                                                   */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   01. Okt. 95                                                    */
+/**************************************************************************/
+
+
+/**
+
+    Advancing front class for surfaces
+
+*/
+class AdFront2
+{
+
+  ///
+  class FrontPoint2
+  {
+    /// coordinates
+    Point<3> p;            
+    /// global node index
+    PointIndex globalindex;   
+    /// number of front lines connected to point 
+    int nlinetopoint;    
+    /// distance to original boundary
+    int frontnr;          
+
+    bool onsurface;
+
+  public:
+    ///
+    MultiPointGeomInfo * mgi;
+
+    ///
+    FrontPoint2 ()
+    {
+      globalindex = -1;
+      nlinetopoint = 0;
+      frontnr = INT_MAX-10;    // attention: overflow on calculating  INT_MAX + 1
+      mgi = NULL;
+      onsurface = true;
+    }
+
+    ///
+    FrontPoint2 (const Point<3> & ap, PointIndex agi,
+		 MultiPointGeomInfo * amgi, bool aonsurface = true);
+    ///
+    ~FrontPoint2 () { ; }
+
+    ///
+    const Point<3> & P () const { return p; }
+    ///
+    operator const Point<3> & () const { return p; }
+    ///
+    PointIndex GlobalIndex () const { return globalindex; }
+
+    ///
+    void AddLine () { nlinetopoint++; }
+    ///
+    void RemoveLine ()
+    {
+      nlinetopoint--;
+      if (nlinetopoint == 0)
+	nlinetopoint = -1;
+    }
+
+    ///
+    bool Valid () const
+    { return nlinetopoint >= 0; }
+
+    ///
+    bool OnSurface() const
+    { return onsurface; }
+
+    ///
+    void DecFrontNr (int afrontnr)
+    {
+      if (frontnr > afrontnr) frontnr = afrontnr;
+    }
+    
+    ///
+    int FrontNr () const { return frontnr; }
+  };
+
+  
+  ///
+  class FrontLine
+  {
+  private:
+    /// Point Indizes
+    INDEX_2 l;            
+    /// quality class 
+    int lineclass;      
+    /// geometry specific data
+    PointGeomInfo geominfo[2];
+  public:
+
+    FrontLine ()
+    {
+      lineclass = 1;
+    }
+
+    ///
+    FrontLine (const INDEX_2 & al)
+    {
+      l = al;
+      lineclass = 1;
+    }
+
+
+    ///
+    const INDEX_2 & L () const
+    {
+      return l;
+    }
+
+    ///
+    int LineClass() const
+    {
+      return lineclass;
+    }
+
+    ///
+    void IncrementClass ()
+    {
+      lineclass++;
+    }
+    ///
+    void ResetClass ()
+    {
+      lineclass = 1;
+    }
+
+    ///
+    bool Valid () const
+    {
+      return l.I1() != -1;
+    }
+    ///
+    void Invalidate ()
+    {
+      l.I1() = -1;
+      l.I2() = -1;
+      lineclass = 1000;
+    }
+
+    void SetGeomInfo (const PointGeomInfo & gi1, const PointGeomInfo & gi2)
+      {
+	geominfo[0] = gi1;
+	geominfo[1] = gi2;
+      }
+
+    const PointGeomInfo * GetGeomInfo () const
+    { return geominfo; }
+    
+    const PointGeomInfo & GetGeomInfo (int endp) const
+    { return geominfo[endp-1]; }
+
+    friend class AdFront2;
+  };
+
+
+
+  ///
+  ARRAY<FrontPoint2> points;  /// front points
+  ARRAY<FrontLine> lines;     /// front lines
+
+  Box3d boundingbox;
+  Box3dTree linesearchtree;       /// search tree for lines
+  Point3dTree pointsearchtree;    /// search tree for points
+  Point3dTree cpointsearchtree;   /// search tree for cone points (not used ???)
+
+  ARRAY<int> delpointl;     /// list of deleted front points
+  ARRAY<int> dellinel;      /// list of deleted front lines
+
+  int nfl;                  /// number of front lines;
+  INDEX_2_HASHTABLE<int> * allflines; /// all front lines ever have been
+
+
+  int minval;
+  int starti;
+
+public:
+  ///
+  //  AdFront2 ();
+  AdFront2 (const Box3d & aboundingbox);
+  ///
+  ~AdFront2 ();
+
+  ///
+  // void GetPoints (ARRAY<Point<3> > & apoints) const;
+  ///
+  void Print (ostream & ost) const;
+
+  ///
+  bool Empty () const
+  {
+    return nfl == 0;
+  }
+  ///
+  int GetNFL () const { return nfl; }
+  ///
+  int SelectBaseLine (Point<3> & p1, Point<3> & p2, 
+		      const PointGeomInfo *& geominfo1,
+		      const PointGeomInfo *& geominfo2,
+		      int & qualclass);
+
+  ///
+  int GetLocals (int baseline, 
+		 ARRAY<Point3d> & locpoints,
+		 ARRAY<MultiPointGeomInfo> & pgeominfo,
+                 ARRAY<INDEX_2> & loclines,   // local index
+                 ARRAY<int> & pindex,
+                 ARRAY<int> & lindex,
+                 double xh);
+
+  ///
+  void DeleteLine (int li);
+  ///
+  int AddPoint (const Point<3> & p, PointIndex globind, 
+                MultiPointGeomInfo * mgi = NULL,
+                bool pointonsurface = true);
+  ///
+  int AddLine (int pi1, int pi2, 
+               const PointGeomInfo & gi1, const PointGeomInfo & gi2);
+  ///
+  int ExistsLine (int gpi1, int gpi2);
+
+  ///
+  void IncrementClass (int li)
+  {
+    lines[li].IncrementClass();
+  }
+
+  ///
+  void ResetClass (int li)
+  {
+    lines[li].ResetClass();
+  }
+
+  ///
+  const PointGeomInfo & GetLineGeomInfo (int li, int lend) const
+    { return lines[li].GetGeomInfo (lend); }
+  ///
+
+  PointIndex GetGlobalIndex (int pi) const
+  {
+    return points[pi].GlobalIndex();
+  }
+  ///
+  void SetStartFront ();
+  ///
+  void PrintOpenSegments (ostream & ost) const;
+};
+
+
+
+#endif
+
+
+
diff --git a/contrib/Netgen/libsrc/meshing/adfront3.cpp b/contrib/Netgen/libsrc/meshing/adfront3.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..dfe2edc839881517939f5eddf73f0f985c831492
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/adfront3.cpp
@@ -0,0 +1,876 @@
+#include <mystdlib.h>
+#include "meshing.hpp"
+
+
+/* ********************** FrontPoint ********************** */
+
+namespace netgen
+{
+
+FrontPoint3 :: FrontPoint3 () 
+{ 
+  globalindex = -1;
+  nfacetopoint = 0; 
+  frontnr = 1000; 
+  cluster = 0;
+}
+
+
+FrontPoint3 :: FrontPoint3 (const Point<3> & ap, PointIndex agi)
+{ 
+  p = ap; 
+  globalindex = agi;
+  nfacetopoint = 0; 
+  frontnr = 1000; 
+  cluster = 0;
+}
+
+
+
+/* ********************** FrontFace ********************** */
+
+FrontFace :: FrontFace () 
+{ 
+  qualclass = 1; 
+  oldfront = 0; 
+  hashvalue = 0;
+  cluster = 0;
+}
+
+FrontFace :: FrontFace (const MiniElement2d & af)
+{ 
+  f = af; 
+  oldfront = 0; 
+  qualclass = 1; 
+  hashvalue = 0;
+}
+
+void FrontFace :: Invalidate ()
+{ 
+  f.Delete(); 
+  oldfront = 0; 
+  qualclass = 1000; 
+}
+
+
+
+
+/* ********************** AddFront ********************** */
+ 
+
+AdFront3 :: AdFront3 ()
+{
+  nff = 0;
+  nff4 = 0;
+  vol = 0;
+
+  hashon = 1;
+  hashcreated = 0;
+  if (hashon) 
+    hashtable.Init(&points, &faces);
+
+  facetree = NULL;
+  connectedpairs = NULL;
+
+  rebuildcounter = -1;
+  lasti = 0;
+  minval = -1;
+}
+
+
+AdFront3 :: ~AdFront3 ()
+{
+  delete facetree;
+  delete connectedpairs;
+}
+
+void AdFront3 :: GetPoints (ARRAY<Point<3> > & apoints) const
+{
+  for (PointIndex pi = PointIndex::BASE; 
+       pi < points.Size()+PointIndex::BASE; pi++)
+    
+    apoints.Append (points[pi].P());
+}
+
+
+PointIndex AdFront3 :: AddPoint (const Point<3> & p, PointIndex globind)
+{
+  if (delpointl.Size())
+    {
+      PointIndex pi = delpointl.Last();
+      delpointl.DeleteLast ();
+      
+      points[pi] = FrontPoint3 (p, globind);
+      return pi;
+    }
+  else
+    {
+      points.Append (FrontPoint3 (p, globind));
+      return points.Size()-1+PointIndex::BASE;
+    }
+}
+
+
+INDEX AdFront3 :: AddFace (const MiniElement2d & aface)
+{
+  int i, minfn;
+
+  nff++;
+
+  for (i = 0; i < aface.GetNP(); i++)
+    points[aface[i]].AddFace();
+
+  const Point3d & p1 = points[aface[0]].P();
+  const Point3d & p2 = points[aface[1]].P();
+  const Point3d & p3 = points[aface[2]].P();
+
+  vol += 1.0/6.0 * (p1.X() + p2.X() + p3.X()) *
+    ( (p2.Y() - p1.Y()) * (p3.Z() - p1.Z()) -
+      (p2.Z() - p1.Z()) * (p3.Y() - p1.Y()) );
+
+  if (aface.GetNP() == 4)
+    {
+      nff4++;
+      const Point3d & p4 = points[aface[3]].P();      
+      vol += 1.0/6.0 * (p1.X() + p3.X() + p4.X()) *
+	( (p3.Y() - p1.Y()) * (p4.Z() - p1.Z()) -
+	  (p3.Z() - p1.Z()) * (p4.Y() - p1.Y()) );
+    }
+
+
+  minfn = 1000;
+  for (i = 0; i < aface.GetNP(); i++)
+    {
+      int fpn = points[aface[i]].FrontNr();
+      if (i == 0 || fpn < minfn)
+	minfn = fpn;
+    }
+
+
+  int cluster = 0;
+  for (i = 1; i <= aface.GetNP(); i++)
+    {
+      if (points[aface.PNum(i)].cluster)
+	cluster = points[aface.PNum(i)].cluster;
+    }
+  for (i = 1; i <= aface.GetNP(); i++)
+    points[aface.PNum(i)].cluster = cluster;
+
+
+  for (i = 1; i <= aface.GetNP(); i++)
+    points[aface.PNum(i)].DecFrontNr (minfn+1);
+
+  int nfn = faces.Append(FrontFace (aface));
+  faces.Elem(nfn).cluster = cluster;
+
+  if (hashon && hashcreated) 
+    hashtable.AddElem(aface, nfn);
+
+  return nfn;
+}
+
+
+
+void AdFront3 :: DeleteFace (INDEX fi)
+{
+  nff--;
+
+  for (int i = 1; i <= faces.Get(fi).Face().GetNP(); i++)
+    {
+      PointIndex pi = faces.Get(fi).Face().PNum(i);
+      points[pi].RemoveFace();
+      if (!points[pi].Valid())
+	delpointl.Append (pi);
+    }
+
+  const MiniElement2d & face = faces.Get(fi).Face();
+  const Point3d & p1 = points[face.PNum(1)].P();
+  const Point3d & p2 = points[face.PNum(2)].P();
+  const Point3d & p3 = points[face.PNum(3)].P();
+
+  vol -= 1.0/6.0 * (p1.X() + p2.X() + p3.X()) *
+    ( (p2.Y() - p1.Y()) * (p3.Z() - p1.Z()) -
+      (p2.Z() - p1.Z()) * (p3.Y() - p1.Y()) );
+
+  if (face.GetNP() == 4)
+    {
+      const Point3d & p4 = points[face.PNum(4)].P();      
+      vol -= 1.0/6.0 * (p1.X() + p3.X() + p4.X()) *
+	( (p3.Y() - p1.Y()) * (p4.Z() - p1.Z()) -
+	  (p3.Z() - p1.Z()) * (p4.Y() - p1.Y()) );
+
+      nff4--;
+    }
+
+  faces.Elem(fi).Invalidate();
+}
+
+
+INDEX AdFront3 :: AddConnectedPair (const INDEX_2 & apair)
+{
+  if (!connectedpairs)
+    connectedpairs = new TABLE<int, PointIndex::BASE> (GetNP());
+
+  connectedpairs->Add (apair.I1(), apair.I2());
+  connectedpairs->Add (apair.I2(), apair.I1());
+
+  return 0;
+}
+
+
+void AdFront3 :: CreateTrees ()
+{
+  int i, j;
+  PointIndex pi;
+  Point3d pmin, pmax;
+
+  for (pi = PointIndex::BASE; 
+       pi < GetNP()+PointIndex::BASE; pi++)
+    {
+      const Point<3> & p = GetPoint(pi);
+      if (pi == PointIndex::BASE)
+	{
+	  pmin = p;
+	  pmax = p;
+	}
+      else
+	{
+	  pmin.SetToMin (p);
+	  pmax.SetToMax (p);
+	}
+    }
+
+  pmax = pmax + 0.5 * (pmax - pmin);
+  pmin = pmin + 0.5 * (pmin - pmax);
+
+  delete facetree;
+  facetree = new Box3dTree (pmin, pmax);
+  
+  for (i = 1; i <= GetNF(); i++)
+    {
+      const MiniElement2d & el = GetFace(i);
+      pmin = GetPoint (el[0]);
+      pmax = pmin;
+      for (j = 1; j < 3; j++)
+	{
+	  const Point<3> & p = GetPoint (el[j]);
+	  pmin.SetToMin (p);
+	  pmax.SetToMax (p);
+	}
+      pmax = pmax + 0.01 * (pmax - pmin);
+      pmin = pmin + 0.01 * (pmin - pmax);
+      //      (*testout) << "insert " << i << ": " << pmin << " - " << pmax << "\n";
+      facetree -> Insert (pmin, pmax, i);
+    }
+}
+
+
+void AdFront3 :: GetIntersectingFaces (const Point<3> & pmin, const Point<3> & pmax, 
+				       ARRAY<int> & ifaces) const
+{
+  facetree -> GetIntersecting (pmin, pmax, ifaces);
+}
+
+void AdFront3 :: GetFaceBoundingBox (int i, Box3d & box) const
+{
+  const FrontFace & face = faces.Get(i);
+  box.SetPoint (points[face.f[0]].p);
+  box.AddPoint (points[face.f[1]].p);
+  box.AddPoint (points[face.f[2]].p);
+}
+
+void AdFront3 :: RebuildInternalTables ()
+{
+  static int timer_a = NgProfiler::CreateTimer ("Adfront3::RebuildInternal A");
+  static int timer_b = NgProfiler::CreateTimer ("Adfront3::RebuildInternal B");
+  static int timer_c = NgProfiler::CreateTimer ("Adfront3::RebuildInternal C");
+  static int timer_d = NgProfiler::CreateTimer ("Adfront3::RebuildInternal D");
+
+
+  NgProfiler::StartTimer (timer_a);	  
+  int hi = 0;
+  for (int i = 1; i <= faces.Size(); i++)
+    if (faces.Get(i).Valid())
+      {
+	hi++;
+	if (hi < i)
+	  faces.Elem(hi) = faces.Get(i);
+      }
+  
+  faces.SetSize (nff);
+
+  int np = points.Size();
+
+  for (int i = PointIndex::BASE; 
+       i < np+PointIndex::BASE; i++)
+    points[i].cluster = i;
+  
+  NgProfiler::StopTimer (timer_a);	  
+  NgProfiler::StartTimer (timer_b);	  
+
+  int change;
+  do
+    {
+      change = 0;
+      for (int i = 1; i <= faces.Size(); i++)
+	{
+	  const MiniElement2d & el = faces.Get(i).Face();
+
+	  int mini = points[el.PNum(1)].cluster;
+	  int maxi = mini;
+	  
+	  for (int j = 2; j <= 3; j++)
+	    {
+	      int ci = points[el.PNum(j)].cluster;
+	      if (ci < mini) mini = ci;
+	      if (ci > maxi) maxi = ci;
+	    }
+
+	  if (mini < maxi)
+	    {
+	      change = 1;
+	      for (int j = 1; j <= 3; j++)
+		points[el.PNum(j)].cluster = mini;
+	    }
+	}
+    }
+  while (change);
+
+
+  NgProfiler::StopTimer (timer_b);	  
+  NgProfiler::StartTimer (timer_c);	  
+
+
+
+
+  BitArrayChar<PointIndex::BASE> usecl(np);
+  usecl.Clear();
+  for (int i = 1; i <= faces.Size(); i++)
+    {
+      usecl.Set (points[faces.Get(i).Face().PNum(1)].cluster);
+      faces.Elem(i).cluster =
+	points[faces.Get(i).Face().PNum(1)].cluster;
+    }
+  int cntcl = 0;
+  for (int i = PointIndex::BASE; 
+       i < np+PointIndex::BASE; i++)
+    if (usecl.Test(i))
+      cntcl++;
+
+  ARRAY<double, PointIndex::BASE> clvol (np);
+  clvol = 0.0;
+
+  for (int i = 1; i <= faces.Size(); i++)
+    {
+      const MiniElement2d & face = faces.Get(i).Face();
+
+      const Point3d p1 = points[face.PNum(1)].P();      
+      const Point3d p2 = points[face.PNum(2)].P();      
+      const Point3d p3 = points[face.PNum(3)].P();      
+      
+      double vi = 1.0/6.0 * (p1.X() + p2.X() + p3.X()) *
+	( (p2.Y() - p1.Y()) * (p3.Z() - p1.Z()) -
+	  (p2.Z() - p1.Z()) * (p3.Y() - p1.Y()) );
+      
+      if (face.GetNP() == 4)
+	{
+	  const Point3d p4 = points[face.PNum(4)].P();      
+	  vi += 1.0/6.0 * (p1.X() + p3.X() + p4.X()) *
+	    ( (p3.Y() - p1.Y()) * (p4.Z() - p1.Z()) -
+	      (p3.Z() - p1.Z()) * (p4.Y() - p1.Y()) );
+	}
+     
+      clvol[faces.Get(i).cluster] += vi;
+    }
+
+  NgProfiler::StopTimer (timer_c);	  
+  NgProfiler::StartTimer (timer_d);	  
+
+
+
+  int negvol = 0;
+  for (int i = PointIndex::BASE; 
+       i < clvol.Size()+PointIndex::BASE; i++)
+    {
+      if (clvol[i] < 0)
+	negvol = 1;
+    }
+
+  if (negvol)
+    {
+      for (int i = 1; i <= faces.Size(); i++)
+	faces.Elem(i).cluster = 1;
+      for (int i = PointIndex::BASE; 
+	   i < points.Size()+PointIndex::BASE; i++)
+	points[i].cluster = 1;
+    }
+
+  if (hashon) 
+    hashtable.Create();
+
+  NgProfiler::StopTimer (timer_d);	  
+}
+
+
+
+int AdFront3 :: SelectBaseElement ()
+{
+  int i, hi, fstind;
+
+  /*
+  static int minval = -1;
+  static int lasti = 0;
+  static int counter = 0;
+  */
+  if (rebuildcounter <= 0)
+    {
+      RebuildInternalTables();
+      rebuildcounter = nff / 10 + 1;
+      
+      lasti = 0;
+    }
+  rebuildcounter--;
+
+  /*
+  if (faces.Size() > 2 * nff)
+    {
+      // compress facelist
+
+      RebuildInternalTables ();
+      lasti = 0;
+    }
+    */
+  
+  fstind = 0;
+
+  for (i = lasti+1; i <= faces.Size() && !fstind; i++)
+    if (faces.Elem(i).Valid())
+      {
+	hi = faces.Get(i).QualClass() +
+	  points[faces.Get(i).Face().PNum(1)].FrontNr() +
+	  points[faces.Get(i).Face().PNum(2)].FrontNr() +
+	  points[faces.Get(i).Face().PNum(3)].FrontNr();
+	
+	if (hi <= minval)
+	  {
+	    minval = hi;
+	    fstind = i;
+	    lasti = fstind;
+	  }
+      }
+  
+  if (!fstind)
+    {
+      minval = INT_MAX;
+      for (i = 1; i <= faces.Size(); i++)
+	if (faces.Elem(i).Valid())
+	  {
+	    hi = faces.Get(i).QualClass() +
+	      points[faces.Get(i).Face().PNum(1)].FrontNr() +
+	      points[faces.Get(i).Face().PNum(2)].FrontNr() +
+	      points[faces.Get(i).Face().PNum(3)].FrontNr();
+	    
+	    if (hi <= minval)
+	      {
+		minval = hi;
+		fstind = i;
+		lasti = 0;
+	      }
+	  }
+    }
+
+
+  return fstind;
+}
+
+
+
+int AdFront3 :: GetLocals (int fstind,
+			   ARRAY<Point3d > & locpoints,
+			   ARRAY<MiniElement2d> & locfaces,   // local index
+			   ARRAY<PointIndex> & pindex,
+			   ARRAY<INDEX> & findex,
+			   INDEX_2_HASHTABLE<int> & getconnectedpairs,
+			   float xh,
+			   float relh,
+			   INDEX& facesplit)
+{
+  static int timer = NgProfiler::CreateTimer ("AdFront3::GetLocals");
+  NgProfiler::RegionTimer reg (timer);
+
+
+  if (hashon && faces.Size() < 500) { hashon=0; }
+  if (hashon && !hashcreated) 
+    {
+      hashtable.Create(); 
+      hashcreated=1;
+    }
+
+  INDEX i, j;
+  PointIndex pstind;
+  INDEX pi;
+  Point3d midp, p0;
+
+  static ARRAY<int, PointIndex::BASE> invpindex;
+  
+  static ARRAY<MiniElement2d> locfaces2;           //all local faces in radius xh
+  static ARRAY<int> locfaces3;           // all faces in outer radius relh
+  static ARRAY<INDEX> findex2;
+
+  locfaces2.SetSize(0);
+  locfaces3.SetSize(0);
+  findex2.SetSize(0);
+
+  int cluster = faces.Get(fstind).cluster;
+
+  pstind = faces.Get(fstind).Face().PNum(1);
+  p0 = points[pstind].P();
+  
+  locfaces2.Append(faces.Get(fstind).Face());
+  findex2.Append(fstind);
+
+
+  Box3d b1 (p0 - Vec3d(xh, xh, xh), p0 + Vec3d (xh, xh, xh));
+
+  if (hashon)
+    {
+      hashtable.GetLocals(locfaces2, findex2, fstind, p0, xh);
+    }
+  else
+    {
+      for (i = 1; i <= faces.Size(); i++)
+	{
+	  const MiniElement2d & face = faces.Get(i).Face();
+	  if (faces.Get(i).cluster == cluster && faces.Get(i).Valid() && i != fstind)
+	    {
+	      Box3d b2;
+	      b2.SetPoint (points[face[0]].P());
+	      b2.AddPoint (points[face[1]].P());
+	      b2.AddPoint (points[face[2]].P());
+
+	      if (b1.Intersect (b2))
+		{
+		  locfaces2.Append(faces.Get(i).Face());
+		  findex2.Append(i);
+		}
+	    }
+	}
+    }
+
+  //local faces for inner radius:
+  for (i = 1; i <= locfaces2.Size(); i++)
+    {
+      const MiniElement2d & face = locfaces2.Get(i);
+      const Point3d & p1 = points[face[0]].P();
+      const Point3d & p2 = points[face[1]].P();
+      const Point3d & p3 = points[face[2]].P();
+
+      midp = Center (p1, p2, p3);
+
+      if (Dist2 (midp, p0) <= relh * relh || i == 1)
+	{
+          locfaces.Append(locfaces2.Get(i));
+	  findex.Append(findex2.Get(i));
+	}
+      else
+	locfaces3.Append (i);
+    }
+  
+  facesplit=locfaces.Size();
+  
+  
+  //local faces for outer radius:
+  for (i = 1; i <= locfaces3.Size(); i++)
+    {
+      locfaces.Append (locfaces2.Get(locfaces3.Get(i)));
+      findex.Append (findex2.Get(locfaces3.Get(i)));
+    }
+
+
+  invpindex.SetSize (points.Size());
+  for (i = 1; i <= locfaces.Size(); i++)
+    for (j = 1; j <= locfaces.Get(i).GetNP(); j++)
+      {
+	pi = locfaces.Get(i).PNum(j);
+	invpindex[pi] = -1;
+      }
+
+  for (i = 1; i <= locfaces.Size(); i++)
+    {
+      for (j = 1; j <= locfaces.Get(i).GetNP(); j++)
+	{
+	  pi = locfaces.Get(i).PNum(j);
+	  if (invpindex[pi] == -1)
+	    {
+	      pindex.Append (pi);
+	      invpindex[pi] = pindex.Size();  // -1+PointIndex::BASE;
+	      locfaces.Elem(i).PNum(j) = locpoints.Append (points[pi].P());
+	    }
+	  else
+	    locfaces.Elem(i).PNum(j) = invpindex[pi];
+
+	}
+    }
+
+
+
+  if (connectedpairs)
+    {
+      for (i = 1; i <= locpoints.Size(); i++)
+	{
+	  int pind = pindex.Get(i);
+	  if (pind >= 1 && pind <= connectedpairs->Size ())
+	    {
+	      for (j = 1; j <= connectedpairs->EntrySize(pind); j++)
+		{
+		  int oi = connectedpairs->Get(pind, j);
+		  int other = invpindex.Get(oi);
+		  if (other >= 1 && other <= pindex.Size() && 
+		      pindex.Get(other) == oi)
+		    {
+		      // INDEX_2 coned(i, other);
+		      // coned.Sort();
+		      // (*testout) << "connected: " << locpoints.Get(i) << "-" << locpoints.Get(other) << endl;
+		      getconnectedpairs.Set (INDEX_2::Sort (i, other), 1);
+		    }
+		}
+	    }
+	}
+    }
+  
+
+  /*
+    // add isolated points
+  for (i = 1; i <= points.Size(); i++)
+    if (points.Elem(i).Valid() && Dist (points.Elem(i).P(), p0) <= xh)
+      {
+	if (!invpindex.Get(i))
+	  {
+	    locpoints.Append (points.Get(i).P());
+	    pindex.Append (i);
+	    invpindex.Elem(i) = pindex.Size();
+	  }
+      }
+      */
+  return faces.Get(fstind).QualClass();
+}
+
+
+// returns all points connected with fi
+void AdFront3 :: GetGroup (int fi,
+			   ARRAY<MeshPoint> & grouppoints,
+			   ARRAY<MiniElement2d> & groupelements,
+			   ARRAY<PointIndex> & pindex,
+			   ARRAY<INDEX> & findex) const
+{
+  static ARRAY<char> pingroup;
+  int i, j, changed;
+
+  pingroup.SetSize(points.Size());
+
+  pingroup = 0;
+  for (j = 1; j <= 3; j++)
+    pingroup.Elem (faces.Get(fi).Face().PNum(j)) = 1;
+
+  do
+    {
+      changed = 0;
+
+      for (i = 1; i <= faces.Size(); i++)
+	if (faces.Get(i).Valid())
+	  {
+	    const MiniElement2d & face = faces.Get(i).Face();
+
+	    int fused = 0;
+	    for (j = 1; j <= 3; j++)
+	      if (pingroup.Elem(face.PNum(j))) 
+		fused++;
+            
+	    if (fused >= 2)
+	      for (j = 1; j <= 3; j++)
+		if (!pingroup.Elem(face.PNum(j)))
+		  {
+		    pingroup.Elem(face.PNum(j)) = 1;
+		    changed = 1;
+		  }
+	  }
+
+    }
+  while (changed);
+
+
+  static ARRAY<int> invpindex;
+  invpindex.SetSize (points.Size());
+  
+
+  for (i = 1; i <= points.Size(); i++)
+    if (points.Get(i).Valid())
+      {
+	grouppoints.Append (points.Get(i).P());
+	pindex.Append (i);
+	invpindex.Elem(i) = pindex.Size();
+      }
+
+  for (i = 1; i <= faces.Size(); i++)
+    if (faces.Get(i).Valid())
+      {
+	int fused = 0;
+	for (j = 1; j <= 3; j++)
+	  if (pingroup.Get(faces.Get(i).Face().PNum(j)))
+	    fused++;
+
+	if (fused >= 2)
+	  {
+	    groupelements.Append (faces.Get(i).Face());
+	    findex.Append (i);
+	  }
+      }
+      
+  for (i = 1; i <= groupelements.Size(); i++)
+    for (j = 1; j <= 3; j++)
+      {
+	groupelements.Elem(i).PNum(j) =
+	  invpindex.Get(groupelements.Elem(i).PNum(j));
+      }
+
+  /*
+  for (i = 1; i <= groupelements.Size(); i++)
+    for (j = 1; j <= 3; j++)
+      for (k = 1; k <= grouppoints.Size(); k++)
+        if (pindex.Get(k) == groupelements.Get(i).PNum(j))
+          {
+	    groupelements.Elem(i).PNum(j) = k;
+	    break;
+          }
+  */          
+}
+
+
+void AdFront3 :: SetStartFront (int /* baseelnp */)
+{
+  INDEX i;
+  int j;
+
+  for (i = 1; i <= faces.Size(); i++)
+    if (faces.Get(i).Valid())
+      {
+	const MiniElement2d & face = faces.Get(i).Face();
+	for (j = 1; j <= 3; j++)
+	  points[face.PNum(j)].DecFrontNr(0);
+      }
+
+  /*
+  if (baseelnp)
+    {
+      for (i = 1; i <= faces.Size(); i++)
+	if (faces.Get(i).Valid() && faces.Get(i).Face().GetNP() != baseelnp)
+	  faces.Elem(i).qualclass = 1000;
+    }
+    */
+}
+
+
+bool AdFront3 :: Inside (const Point<3> & p) const
+{
+  int i, cnt;
+  Vec3d n, v1, v2;
+  DenseMatrix a(3), ainv(3);
+  Vector b(3), u(3);
+
+  // random numbers:
+  n.X() = 0.123871;
+  n.Y() = 0.15432;
+  n.Z() = -0.43989;
+
+  cnt = 0;
+  for (i = 1; i <= faces.Size(); i++)
+    if (faces.Get(i).Valid())
+      {
+	const Point<3> & p1 = points[faces.Get(i).Face().PNum(1)].P();
+	const Point<3> & p2 = points[faces.Get(i).Face().PNum(2)].P();
+	const Point<3> & p3 = points[faces.Get(i).Face().PNum(3)].P();
+
+	v1 = p2 - p1;
+	v2 = p3 - p1;
+
+	a.Elem(1, 1) = v1.X();
+	a.Elem(2, 1) = v1.Y();
+	a.Elem(3, 1) = v1.Z();
+	a.Elem(1, 2) = v2.X();
+	a.Elem(2, 2) = v2.Y();
+	a.Elem(3, 2) = v2.Z();
+	a.Elem(1, 3) = -n.X();
+	a.Elem(2, 3) = -n.Y();
+	a.Elem(3, 3) = -n.Z();
+
+	b.Elem(1) = p(0) - p1(0);
+	b.Elem(2) = p(1) - p1(1);
+	b.Elem(3) = p(2) - p1(2);
+
+	CalcInverse (a, ainv);
+	ainv.Mult (b, u);
+
+	if (u.Elem(1) >= 0 && u.Elem(2) >= 0 && u.Elem(1)+u.Elem(2) <= 1 &&
+	    u.Elem(3) > 0)
+	  {
+	    cnt++;
+	  }
+      }
+
+  return ((cnt % 2) != 0);
+}
+
+
+
+
+
+int AdFront3 :: SameSide (const Point<3> & lp1, const Point<3> & lp2,
+			  const ARRAY<int> * testfaces) const
+{
+  int i, ii, cnt;
+
+  const Point<3> *line[2];
+  line[0] = &lp1;
+  line[1] = &lp2;
+
+
+  cnt = 0;
+
+  Point3d pmin(lp1);
+  Point3d pmax(lp1);
+  pmin.SetToMin (lp2);
+  pmax.SetToMax (lp2);
+
+  static ARRAY<int> aprif;
+  aprif.SetSize(0);
+  
+  if (!testfaces)
+    facetree->GetIntersecting (pmin, pmax, aprif);
+  else
+    {
+      for (i = 1; i <= testfaces->Size(); i++)
+	aprif.Append (testfaces->Get(i));
+    }
+
+  //  (*testout) << "test ss, p1,p2 = " << lp1 << lp2 << ", inters = " << aprif.Size() << endl;
+  //  for (i = 1; i <= faces.Size(); i++)
+  for (ii = 1; ii <= aprif.Size(); ii++)
+    {
+      i = aprif.Get(ii);
+      
+      if (faces.Get(i).Valid())
+	{
+	  const Point<3> *tri[3];
+	  tri[0] = &points[faces.Get(i).Face().PNum(1)].P();
+	  tri[1] = &points[faces.Get(i).Face().PNum(2)].P();
+	  tri[2] = &points[faces.Get(i).Face().PNum(3)].P();
+	  	  
+	  if (IntersectTriangleLine (&tri[0], &line[0]))
+	    cnt++;
+	  
+	}
+    }
+
+  return ((cnt+1) % 2);
+}
+}
diff --git a/contrib/Netgen/libsrc/meshing/adfront3.hpp b/contrib/Netgen/libsrc/meshing/adfront3.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..40d6eabb99c391d046cde49f3e9a2f8623f3432d
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/adfront3.hpp
@@ -0,0 +1,319 @@
+#ifndef FILE_ADFRONT3
+#define FILE_ADFRONT3
+
+/**************************************************************************/
+/* File:   adfront3.hh                                                    */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   01. Okt. 95                                                    */
+/**************************************************************************/
+
+/*
+  Advancing front class for volume meshing
+*/
+
+
+
+/// Point in advancing front
+class FrontPoint3
+{
+  /// coordinates
+Point<3> p;           
+  /// global node index
+PointIndex globalindex;   
+  /// number of faces connected to point 
+int nfacetopoint;    
+  /// distance to original boundary
+int frontnr;
+  /// 
+int cluster;
+public:
+  ///
+  FrontPoint3 ();
+  ///
+  FrontPoint3 (const Point<3> & ap, PointIndex agi);
+  
+  ///
+  const Point<3> & P () const
+  { return p; }
+  ///
+  PointIndex GlobalIndex () const
+  { return globalindex; }
+  
+  ///
+  void AddFace ()
+  { nfacetopoint++; }
+
+  ///
+  void RemoveFace()
+  { 
+    nfacetopoint--;
+    if (nfacetopoint == 0) nfacetopoint = -1;
+  }
+  
+  ///
+  int Valid () const
+  { return nfacetopoint >= 0; }
+
+  ///
+  void DecFrontNr (int afrontnr)
+  {
+    if (frontnr > afrontnr) frontnr = afrontnr;
+  }
+  
+  ///
+  int FrontNr () const
+  { return frontnr; }
+
+  ///
+  friend class AdFront3;
+};
+
+
+
+class MiniElement2d
+{
+protected:
+  int np;
+  PointIndex pnum[4];
+  bool deleted;
+public:
+  MiniElement2d ()
+  { np = 3; deleted = 0; }
+  MiniElement2d (int anp)
+  { np = anp; deleted = 0; }
+
+  int GetNP() const { return np; }
+  PointIndex & operator[] (int i) { return pnum[i]; }
+  const PointIndex operator[] (int i) const { return pnum[i]; }
+
+  const PointIndex PNum (int i) const { return pnum[i-1]; }
+  PointIndex & PNum (int i) { return pnum[i-1]; }
+  const PointIndex PNumMod (int i) const { return pnum[(i-1)%np]; }
+
+  void Delete () { deleted = 1; pnum[0] = pnum[1] = pnum[2] = pnum[3] = PointIndex::BASE-1; }
+  bool IsDeleted () const { return deleted; }
+};
+
+
+inline ostream & operator<<(ostream  & s, const MiniElement2d & el)
+{
+  s << "np = " << el.GetNP();
+  for (int j = 0; j < el.GetNP(); j++)
+    s << " " << el[j];
+  return s;
+}
+
+
+
+
+/// Face in advancing front
+class FrontFace
+{
+private:
+  ///
+  MiniElement2d f;
+  ///
+  int qualclass;
+  ///
+  char oldfront;
+  ///
+  int hashvalue;
+  ///
+  int cluster;
+
+public:
+  ///
+  FrontFace ();
+  ///
+  FrontFace (const MiniElement2d & af);
+  ///
+  const MiniElement2d & Face () const
+  { return f; }
+  
+  ///
+  int QualClass () const
+  { return qualclass; }
+
+  ///
+  void IncrementQualClass ()
+  { qualclass++; }
+
+  ///
+  void ResetQualClass ()
+  {
+    if (qualclass > 1)
+      {
+	qualclass = 1;
+	oldfront = 0;
+      }
+  }
+  
+  ///
+  bool Valid () const
+  { return !f.IsDeleted(); }
+
+  ///
+  void Invalidate ();
+
+  ///
+  int HashValue() const 
+  { return hashvalue; }
+
+  ///
+  void SetHashValue(int hv) 
+  { hashvalue = hv; }
+
+  ///
+  friend class AdFront3;
+
+  int Cluster () const { return cluster; }
+};  
+
+
+
+
+/// Advancing front, 3D.
+class AdFront3
+{
+  ///
+ARRAY<FrontPoint3, PointIndex::BASE> points;
+  ///
+ARRAY<FrontFace> faces;
+  ///
+ARRAY<PointIndex> delpointl;
+
+  /// which points are connected to pi ?
+TABLE<int, PointIndex::BASE> * connectedpairs;
+  
+  /// number of total front faces;
+int nff;
+  /// number of quads in front
+int nff4; 
+  
+  ///
+double vol;
+
+  ///
+GeomSearch3d hashtable;
+
+  /// 
+int hashon;
+
+  ///
+int hashcreated;
+
+  /// counter for rebuilding internal tables
+int rebuildcounter;
+  /// last base element
+int lasti;
+  /// minimal selection-value of baseelements
+int minval;
+
+  ///
+class Box3dTree * facetree;
+public:
+
+  ///
+  AdFront3 ();
+  ///
+  ~AdFront3 ();
+  ///
+  void GetPoints (ARRAY<Point<3> > & apoints) const;
+  ///
+  int GetNP() const 
+  { return points.Size(); }
+  ///
+  const Point<3> & GetPoint (PointIndex pi) const
+  { return points[pi].P(); }
+  ///
+  int GetNF() const
+  { return nff; }
+  ///
+  const MiniElement2d & GetFace (int i) const
+  { return faces.Get(i).Face(); }
+  ///
+  void Print () const;
+  ///
+  bool Empty () const
+  { return nff == 0; }
+  ///
+  bool Empty (int elnp) const
+  {
+    if (elnp == 4)
+      return (nff4 == 0);
+    return (nff - nff4 == 0);
+  }
+  ///
+  int SelectBaseElement ();
+
+  ///
+  void CreateTrees ();
+
+  ///
+  void GetIntersectingFaces (const Point<3> & pmin, const Point<3> & pmax, 
+			     ARRAY<int> & ifaces) const;
+
+  ///
+  void GetFaceBoundingBox (int i, Box3d & box) const;
+
+  ///
+  int GetLocals (int baseelement,
+		 ARRAY<Point3d > & locpoints,
+                 ARRAY<MiniElement2d> & locfaces,   // local index
+                 ARRAY<PointIndex> & pindex,
+                 ARRAY<INDEX> & findex,
+		 INDEX_2_HASHTABLE<int> & connectedpairs,
+                 float xh,
+		 float relh,
+		 INDEX& facesplit);
+  
+  ///
+  void GetGroup (int fi,
+                 ARRAY<MeshPoint> & grouppoints,
+                 ARRAY<MiniElement2d> & groupelements,
+                 ARRAY<PointIndex> & pindex,
+                 ARRAY<INDEX> & findex
+                 ) const;
+
+  ///
+  void DeleteFace (INDEX fi);
+  ///
+  PointIndex AddPoint (const Point<3> & p, PointIndex globind);
+  ///
+  INDEX AddFace (const MiniElement2d & e);
+  ///
+  INDEX AddConnectedPair (const INDEX_2 & pair);
+  ///
+  void IncrementClass (INDEX fi)
+  { faces.Elem(fi).IncrementQualClass(); }
+
+  ///
+  void ResetClass (INDEX fi)
+  { faces.Elem(fi).ResetQualClass(); }
+
+  ///
+  void SetStartFront (int baseelnp = 0);
+
+  /// is Point p inside Surface ?
+  bool Inside (const Point<3> & p) const;
+  /// both points on same side ?
+  int SameSide (const Point<3> & lp1, const Point<3> & lp2, 
+		const ARRAY<int> * testfaces = NULL) const;
+
+
+  ///
+  PointIndex GetGlobalIndex (PointIndex pi) const
+  { return points[pi].GlobalIndex(); }
+  ///
+  double Volume () const
+  { return vol; }
+
+
+private:
+  void RebuildInternalTables();
+};
+
+
+
+
+#endif
diff --git a/contrib/Netgen/libsrc/meshing/bisect.cpp b/contrib/Netgen/libsrc/meshing/bisect.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..c56671b547ecdc076dea8840465c935cc0a18fcb
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/bisect.cpp
@@ -0,0 +1,3994 @@
+#include <mystdlib.h>
+#include "meshing.hpp"
+
+
+namespace netgen
+{
+  //#include "../interface/writeuser.hpp"
+  class MarkedTet;
+  class MarkedPrism;
+  class MarkedIdentification;
+  class MarkedTri;
+  class MarkedQuad;
+  
+  typedef MoveableArray<MarkedTet> T_MTETS;
+  typedef MoveableArray<MarkedPrism> T_MPRISMS;
+  typedef MoveableArray<MarkedIdentification> T_MIDS;
+  typedef MoveableArray<MarkedTri> T_MTRIS;
+  typedef MoveableArray<MarkedQuad> T_MQUADS;
+
+  class MarkedTet
+  {
+  public:
+    /// pnums of tet
+    PointIndex pnums[4];
+    /// material number
+    int matindex;
+    /// element marked for refinement
+    /// marked = 1: marked by element marker, marked = 2 due to closure
+    unsigned int marked:2;
+    /// flag of Arnold-Mukherjee algorithm
+    unsigned int flagged:1;
+    /// tetedge (local coordinates 0..3)
+    unsigned int tetedge1:3;
+    unsigned int tetedge2:3;
+    /// marked edge of faces
+			  /// face_j : face without node j,
+			  /// mark_k : edge without node k
+    unsigned char faceedges[4];
+
+    bool incorder;
+    unsigned int order:6;
+
+  };
+
+  ostream & operator<< (ostream & ost, const MarkedTet & mt)
+  {
+    for(int i=0; i<4; i++)
+      ost << mt.pnums[i] << " ";
+
+    ost << mt.matindex << " " << int(mt.marked) << " " << int(mt.flagged) << " " << int(mt.tetedge1) << " " << int(mt.tetedge2) << " ";
+    
+    for(int i=0; i<4; i++)
+      ost << char(mt.faceedges[i]) << " ";
+
+    ost << mt.incorder << " " << int(mt.order) << "\n";
+    return ost;
+  }
+  istream & operator>> (istream & ost, MarkedTet & mt)
+  {
+    for(int i=0; i<4; i++)
+      ost >> mt.pnums[i];
+
+    ost >> mt.matindex;
+
+    int auxint;
+    ost >> auxint;
+    mt.marked = auxint;
+    ost >> auxint;
+    mt.flagged = auxint;
+    ost >> auxint;
+    mt.tetedge1 = auxint;
+    ost >> auxint;
+    mt.tetedge2 = auxint;
+    
+    char auxchar;
+
+    for(int i=0; i<4; i++)
+      {
+	ost >> auxchar;
+	mt.faceedges[i] = auxchar;
+      }
+
+    ost >> mt.incorder;
+    ost >> auxint;
+    mt.order = auxint;
+    return ost;
+  }
+
+  class MarkedPrism
+  {
+  public:
+    /// 6 point numbers
+    PointIndex pnums[6];
+    /// material number
+    int matindex;
+    /// marked for refinement
+    int marked;
+    /// edge without node k (0,1,2)
+    int markededge;
+
+    bool incorder;
+    unsigned int order:6;
+  };
+
+  
+  ostream & operator<< (ostream & ost, const MarkedPrism & mp)
+  {
+    for(int i=0; i<6; i++)
+      ost << mp.pnums[i] << " ";
+
+    ost << mp.matindex << " " << mp.marked << " " << mp.markededge << " " << mp.incorder << " " << int(mp.order) << "\n";
+    return ost;
+  }
+  istream & operator>> (istream & ist, MarkedPrism & mp)
+  {
+    for(int i=0; i<6; i++)
+      ist >> mp.pnums[i];
+
+    ist >> mp.matindex >> mp.marked >> mp.markededge >> mp.incorder;
+    int auxint;
+    ist >> auxint;
+    mp.order = auxint;
+    return ist;
+  }
+
+
+  class MarkedIdentification
+  {
+  public:
+    // number of points of one face (3 or 4)
+    int np;
+    /// 6 or 8 point numbers
+    PointIndex pnums[8];
+    /// marked for refinement
+    int marked;
+    /// edge starting with node k (0,1,2, or 3)
+    int markededge;
+
+    bool incorder;
+    unsigned int order:6;
+  };
+    
+  
+  ostream & operator<< (ostream & ost, const MarkedIdentification & mi)
+  {
+    ost << mi.np << " ";
+    for(int i=0; i<2*mi.np; i++)
+      ost << mi.pnums[i] << " ";
+    ost << mi.marked << " " << mi.markededge << " " << mi.incorder << " " << int(mi.order) << "\n";
+    return ost;
+  }
+  istream & operator>> (istream & ist, MarkedIdentification & mi)
+  {
+    ist >> mi.np;
+    for(int i=0; i<2*mi.np; i++)
+      ist >> mi.pnums[i];
+    ist >> mi.marked >> mi.markededge >> mi.incorder;
+    int auxint;
+    ist >> auxint;
+    mi.order = auxint;
+    return ist;
+  }
+  
+
+
+
+
+  class MarkedTri
+  {
+  public:
+    /// three point numbers
+    PointIndex pnums[3];
+    /// three geominfos
+    PointGeomInfo pgeominfo[3];
+    /// marked for refinement
+    int marked;
+    /// edge without node k
+    int markededge;
+    /// surface id
+    int surfid;
+
+    bool incorder;
+    unsigned int order:6;
+  };
+  
+  ostream & operator<< (ostream & ost, const MarkedTri & mt)
+  {
+    for(int i=0; i<3; i++)
+      ost << mt.pnums[i] << " ";
+    for(int i=0; i<3; i++)
+      ost << mt.pgeominfo[i] << " ";
+    ost << mt.marked << " " << mt.markededge << " " << mt.surfid << " " << mt.incorder << " " << int(mt.order) << "\n";
+    return ost;
+  } 
+  istream & operator>> (istream & ist, MarkedTri & mt)
+  {
+    for(int i=0; i<3; i++)
+      ist >> mt.pnums[i];
+    for(int i=0; i<3; i++)
+      ist >> mt.pgeominfo[i];
+    ist >> mt.marked >> mt.markededge >> mt.surfid >> mt.incorder;
+    int auxint;
+    ist >> auxint;
+    mt.order = auxint;
+    return ist;
+  }
+    
+
+
+  class MarkedQuad
+  {
+  public:
+    /// point numbers
+    PointIndex pnums[4];
+    ///
+    PointGeomInfo pgeominfo[4];
+    /// marked for refinement
+    int marked;
+    /// marked edge: 0/2 = vertical, 1/3 = horizontal
+    int markededge;
+    /// surface id
+    int surfid;
+
+    bool incorder;
+    unsigned int order:6;
+  };
+
+  ostream & operator<< (ostream & ost, const MarkedQuad & mt)
+  {
+    for(int i=0; i<4; i++)
+      ost << mt.pnums[i] << " ";
+    for(int i=0; i<4; i++)
+      ost << mt.pgeominfo[i] << " ";
+    ost << mt.marked << " " << mt.markededge << " " << mt.surfid << " " << mt.incorder << " " << int(mt.order) << "\n";
+    return ost;
+  } 
+  istream & operator>> (istream & ist, MarkedQuad & mt)
+  {
+    for(int i=0; i<4; i++)
+      ist >> mt.pnums[i];
+    for(int i=0; i<4; i++)
+      ist >> mt.pgeominfo[i];
+    ist >> mt.marked >> mt.markededge >> mt.surfid >> mt.incorder;
+    int auxint;
+    ist >> auxint;
+    mt.order = auxint;
+    return ist;
+  }
+
+
+
+
+  void PrettyPrint(ostream & ost, const MarkedTet & mt)
+  {
+    int te1 = mt.tetedge1;
+    int te2 = mt.tetedge2;
+    int order = mt.order;
+
+    ost << "MT: " << mt.pnums[0] << " - " << mt.pnums[1] << " - " 
+	<< mt.pnums[2] << " - " << mt.pnums[3] << endl
+	<< "marked edge: " << te1 << " - " << te2
+	<< ", order = " << order << endl;
+    //for (int k = 0; k < 4; k++)
+    //  ost << int(mt.faceedges[k]) << "  ";
+    for (int k = 0; k < 4; k++)
+      {
+	ost << "face";
+	for (int j=0; j<4; j++)
+	  if(j != k)
+	    ost << " " << mt.pnums[j];
+	for(int i=0; i<3; i++)
+	  for(int j=i+1; j<4; j++)
+	    if(i != k && j != k && mt.faceedges[k] == 6-k-i-j)
+	      ost << " marked edge " << mt.pnums[i] << " " << mt.pnums[j] << endl;
+      }
+    ost << endl;
+  }
+
+
+
+
+  int BTSortEdges (const Mesh & mesh,
+		   const ARRAY< ARRAY<int,PointIndex::BASE>* > & idmaps,
+		   INDEX_2_CLOSED_HASHTABLE<int> & edgenumber)
+  {
+    PrintMessage(4,"sorting ... ");
+
+    //  if (mesh.PureTetMesh())
+    if (1)
+      {
+	// new, fast version
+      
+	ARRAY<INDEX_2> edges;
+	ARRAY<int> eclasses;
+      
+	int i, j, k;
+	int cntedges = 0;
+	int go_on;
+	int ned(0);
+      
+	// enumerate edges:
+	for (i = 1; i <= mesh.GetNE(); i++)
+	  {
+	    const Element & el = mesh.VolumeElement (i);
+	    static int tetedges[6][2] =
+	      { { 1, 2 },
+		{ 1, 3 },
+		{ 1, 4 },
+		{ 2, 3 },
+		{ 2, 4 },
+		{ 3, 4 } } ;
+	    static int prismedges[9][2] =
+	      { { 1, 2 },
+		{ 1, 3 },
+		{ 2, 3 },
+		{ 4, 5 },
+		{ 4, 6 },
+		{ 5, 6 },
+		{ 1, 4 },
+		{ 2, 5 },
+		{ 3, 6 } };
+	    int pyramidedges[6][2] =
+	      { { 1, 2 },
+		{ 3, 4 },
+		{ 1, 5 },
+		{ 2, 5 },
+		{ 3, 5 },
+		{ 4, 5 } };
+	  
+	    int (*tip)[2] = NULL;
+	  
+	    switch (el.GetType())
+	      {
+	      case TET:
+	      case TET10:
+		{
+		  tip = tetedges;
+		  ned = 6;
+		  break;
+		}
+	      case PRISM:
+	      case PRISM12:
+		{
+		  tip = prismedges;
+		  ned = 6;
+		  break;
+		}
+	      case PYRAMID:
+		{
+		  tip = pyramidedges;
+		  ned = 6;
+		  break;
+		}
+	      }
+	      
+	    for (j = 0; j < ned; j++)
+	      {
+		INDEX_2 i2(el.PNum(tip[j][0]), el.PNum(tip[j][1]));
+		i2.Sort();
+		//(*testout) << "edge " << i2 << endl;
+		if (!edgenumber.Used(i2))
+		  {
+		    cntedges++;
+		    edges.Append (i2);
+		    edgenumber.Set(i2, cntedges);
+		  }
+	      }
+	  }
+      
+	// additional surface edges:
+	for (i = 1; i <= mesh.GetNSE(); i++)
+	  {
+	    const Element2d & el = mesh.SurfaceElement (i);
+	    static int trigedges[3][2] =
+	      { { 1, 2 },
+		{ 2, 3 },
+		{ 3, 1 } };
+
+	    static int quadedges[4][2] =
+	      { { 1, 2 },
+		{ 2, 3 },
+		{ 3, 4 },
+		{ 4, 1 } };
+
+
+	    int (*tip)[2] = NULL;
+	  
+	    switch (el.GetType())
+	      {
+	      case TRIG:
+	      case TRIG6:
+		{
+		  tip = trigedges;
+		  ned = 3;
+		  break;
+		}
+	      case QUAD:
+	      case QUAD6:
+		{
+		  tip = quadedges;
+		  ned = 4;
+		  break;
+		}
+	      default:
+		{
+		  cerr << "Error: Sort for Bisect, SE has " << el.GetNP() << " points" << endl;
+		  ned = 0;
+		}
+	      }
+	      
+	    for (j = 0; j < ned; j++)
+	      {
+		INDEX_2 i2(el.PNum(tip[j][0]), el.PNum(tip[j][1]));
+		i2.Sort();
+		if (!edgenumber.Used(i2))
+		  {
+		    cntedges++;
+		    edges.Append (i2);
+		    edgenumber.Set(i2, cntedges);
+		  }
+	      }
+	  }
+
+
+
+
+
+	eclasses.SetSize (cntedges);
+	for (i = 1; i <= cntedges; i++)
+	  eclasses.Elem(i) = i;
+
+	// identify edges in element stack
+	do
+	  {
+	    go_on = 0;
+	    for (i = 1; i <= mesh.GetNE(); i++)
+	      {
+		const Element & el = mesh.VolumeElement (i);	     
+	      
+		if (el.GetType() != PRISM &&
+		    el.GetType() != PRISM12 &&
+		    el.GetType() != PYRAMID)
+		  continue;
+
+		int prismpairs[3][4] =
+		  { { 1, 2, 4, 5 },
+		    { 2, 3, 5, 6 },
+		    { 1, 3, 4, 6 } };
+	      
+		int pyramidpairs[3][4] =
+		  { { 1, 2, 4, 3 },
+		    { 1, 5, 4, 5 },
+		    { 2, 5, 3, 5 } };
+		      
+		int (*pairs)[4] = NULL;
+		switch (el.GetType())
+		  {
+		  case PRISM:
+		  case PRISM12:
+		    {
+		      pairs = prismpairs;
+		      break;
+		    }
+		  case PYRAMID:
+		    {
+		      pairs = pyramidpairs;
+		      break;
+		    }
+		  }
+
+		for (j = 0; j < 3; j++)
+		  {
+		    INDEX_2 e1 (el.PNum(pairs[j][0]), 
+				el.PNum(pairs[j][1]));
+		    INDEX_2 e2 (el.PNum(pairs[j][2]), 
+				el.PNum(pairs[j][3]));
+		    e1.Sort();
+		    e2.Sort();
+		      
+		    int eclass1 = edgenumber.Get (e1);
+		    int eclass2 = edgenumber.Get (e2);
+
+		    //		  (*testout) << "identify edges " << eclass1 << "-" << eclass2 << endl;
+
+		    if (eclasses.Get(eclass1) >
+			eclasses.Get(eclass2))
+		      {
+			eclasses.Elem(eclass1) = 
+			  eclasses.Get(eclass2);
+			go_on = 1;
+		      }
+		    else if (eclasses.Get(eclass2) >
+			     eclasses.Get(eclass1))
+		      {
+			eclasses.Elem(eclass2) = 
+			  eclasses.Get(eclass1);
+			go_on = 1;
+		      }
+		  }
+	      }
+
+	    for(SurfaceElementIndex sei = 0; sei < mesh.GetNSE(); sei++)
+	      {
+		const Element2d & el2d = mesh[sei];
+
+		for(i = 0; i < el2d.GetNP(); i++)
+		  {
+		    INDEX_2 e1(el2d[i], el2d[(i+1) % el2d.GetNP()]);
+		    e1.Sort();
+		    INDEX_2 e2;
+		    
+		    for(k = 0; k < idmaps.Size(); k++)
+		      {
+			e2.I1() = (*idmaps[k])[e1.I1()];
+			e2.I2() = (*idmaps[k])[e1.I2()];
+			
+			if(e2.I1() == 0 || e2.I2() == 0 ||
+			   e1.I1() == e2.I1() || e1.I2() == e2.I2())
+			  continue;
+			
+			e2.Sort();
+			if(!edgenumber.Used(e2))
+			  continue;
+			
+
+			int eclass1 = edgenumber.Get (e1);
+			int eclass2 = edgenumber.Get (e2);
+			
+			if (eclasses.Get(eclass1) >
+			    eclasses.Get(eclass2))
+			  {
+			    eclasses.Elem(eclass1) = 
+			      eclasses.Get(eclass2);
+
+
+			    go_on = 1;
+			  }
+			else if (eclasses.Get(eclass2) >
+				 eclasses.Get(eclass1))
+			  {
+			    eclasses.Elem(eclass2) = 
+			      eclasses.Get(eclass1);
+			    go_on = 1;
+			  }
+		      }		      
+		  }
+		
+	      }
+
+	  }
+	while (go_on);
+
+// 	for (i = 1; i <= cntedges; i++)
+// 	  {
+// 	    (*testout) << "edge " << i << ": " 
+// 		       << edges.Get(i).I1() << "-" << edges.Get(i).I2()
+// 		       << ", class = " << eclasses.Get(i) << endl;
+// 	  }
+	
+	// compute classlength:
+	ARRAY<double> edgelength(cntedges);
+
+	/*
+	for (i = 1; i <= cntedges; i++)
+	  edgelength.Elem(i) = 1e20;
+	*/
+
+	for (i = 1; i <= cntedges; i++)
+	  {
+	    INDEX_2 edge = edges.Get(i);
+	    double elen = Dist (mesh.Point(edge.I1()),
+				mesh.Point(edge.I2()));
+	    edgelength.Elem (i) = elen;
+	  }
+
+	/*
+	  for (i = 1; i <= mesh.GetNE(); i++)
+	  {
+	  const Element & el = mesh.VolumeElement (i);
+	  
+	  if (el.GetType() == TET)
+	  {
+	  for (j = 1; j <= 3; j++)
+	  for (k = j+1; k <= 4; k++)
+	  {
+	  INDEX_2 i2(el.PNum(j), el.PNum(k));
+	  i2.Sort();
+		    
+	  int enr = edgenumber.Get(i2);
+	  double elen = Dist (mesh.Point (i2.I1()), mesh.Point (i2.I2()));
+	  if (elen < edgelength.Get(enr))
+	  edgelength.Set (enr, elen);
+	  }
+	  }
+	  else if (el.GetType() == PRISM)
+	  {
+	  for (j = 1; j <= 3; j++)
+	  {
+	  k = (j % 3) + 1;
+		  
+	  INDEX_2 i2(el.PNum(j), el.PNum(k));
+	  i2.Sort();
+		  
+	  int enr = edgenumber.Get(i2);
+	  double elen = Dist (mesh.Point (i2.I1()), mesh.Point (i2.I2()));
+	  if (elen < edgelength.Get(enr))
+	  edgelength.Set (enr, elen);
+		  
+	  i2 = INDEX_2(el.PNum(j+3), el.PNum(k+3));
+	  i2.Sort();
+		  
+	  enr = edgenumber.Get(i2);
+	  elen = Dist (mesh.Point (i2.I1()), mesh.Point (i2.I2()));
+	  if (elen < edgelength.Get(enr))
+	  edgelength.Set (enr, elen);
+		  
+	  if (!edgenumber.Used(i2))
+	  {
+	  cntedges++;
+	  edgenumber.Set(i2, cntedges);
+	  }
+	  i2 = INDEX_2(el.PNum(j), el.PNum(j+3));
+	  i2.Sort();
+		  
+	  enr = edgenumber.Get(i2);
+	  elen = Dist (mesh.Point (i2.I1()), mesh.Point (i2.I2()));
+	  if (elen < edgelength.Get(enr))
+	  edgelength.Set (enr, elen);
+	  }
+	  }
+	  }
+	*/
+
+      
+	for (i = 1; i <= cntedges; i++)
+	  {
+	    if (eclasses.Get(i) != i)
+	      {
+		if (edgelength.Get(i) < edgelength.Get(eclasses.Get(i)))
+		  edgelength.Elem(eclasses.Get(i)) = edgelength.Get(i);
+		edgelength.Elem(i) = 1e20;
+	      }
+	  }
+
+
+	TABLE<int> eclasstab(cntedges);
+	for (i = 1; i <= cntedges; i++)
+	  eclasstab.Add1 (eclasses.Get(i), i);
+
+
+	// sort edges:
+	ARRAY<int> sorted(cntedges);
+      
+	QickSort (edgelength, sorted);
+      
+	int cnt = 0;
+	for (i = 1; i <= cntedges; i++)
+	  {
+	    int ii = sorted.Get(i);
+	    for (j = 1; j <= eclasstab.EntrySize(ii); j++)
+	      {
+		cnt++;
+		edgenumber.Set (edges.Get(eclasstab.Get(ii, j)), cnt); 
+	      }
+	  }
+	return cnt;
+      }
+
+    else
+    
+      {
+	// old version
+      
+	int i, j;
+	int cnt = 0;
+	int found;
+	double len2, maxlen2;
+	INDEX_2 ep;
+      
+	// sort edges by length, parallel edges (on prisms)
+	// are added in blocks
+      
+	do
+	  {
+	    found = 0;
+	    maxlen2 = 1e30;
+	  
+	    for (i = 1; i <= mesh.GetNE(); i++)
+	      {
+		const Element & el = mesh.VolumeElement (i);
+		int ned;
+		int tetedges[6][2] =
+		  { { 1, 2 },
+		    { 1, 3 },
+		    { 1, 4 },
+		    { 2, 3 },
+		    { 2, 4 },
+		    { 3, 4 } };
+		int prismedges[6][2] =
+		  { { 1, 2 },
+		    { 1, 3 },
+		    { 2, 4 },
+		    { 4, 5 },
+		    { 4, 6 },
+		    { 5, 6 } };
+		int pyramidedges[6][2] =
+		  { { 1, 2 },
+		    { 3, 4 },
+		    { 1, 5 },
+		    { 2, 5 },
+		    { 3, 5 },
+		    { 4, 5 } };
+
+		int (*tip)[2];
+
+		switch (el.GetType())
+		  {
+		  case TET:
+		    {
+		      tip = tetedges;
+		      ned = 6;
+		      break;
+		    }
+		  case PRISM:
+		    {
+		      tip = prismedges;
+		      ned = 6;
+		      break;
+		    }
+		  case PYRAMID:
+		    {
+		      tip = pyramidedges;
+		      ned = 6;
+		      break;
+		    }
+		  }
+	      
+		for (j = 0; j < ned; j++)
+		  {
+		    INDEX_2 i2(el.PNum(tip[j][0]), el.PNum(tip[j][1]));
+		    i2.Sort();
+		    if (!edgenumber.Used(i2))
+		      {
+			len2 = Dist (mesh.Point (i2.I1()),
+				     mesh.Point (i2.I2()));
+			if (len2 < maxlen2)
+			  {
+			    maxlen2 = len2;
+			    ep = i2;
+			    found = 1;
+			  }
+		      }
+		  }
+	      }
+	    if (found)
+	      {
+		cnt++;
+		edgenumber.Set (ep, cnt);
+	      
+	      
+		// find connected edges:
+		int go_on = 0;
+		do
+		  {
+		    go_on = 0;
+		    for (i = 1; i <= mesh.GetNE(); i++)
+		      {
+			const Element & el = mesh.VolumeElement (i);	      
+			if (el.GetNP() != 6) continue;
+
+			int prismpairs[3][4] =
+			  { { 1, 2, 4, 5 },
+			    { 2, 3, 5, 6 },
+			    { 1, 3, 4, 6 } };
+
+			int pyramidpairs[3][4] =
+			  { { 1, 2, 4, 3 },
+			    { 1, 5, 4, 5 },
+			    { 2, 5, 3, 5 } };
+		      
+			int (*pairs)[4];
+			switch (el.GetType())
+			  {
+			  case PRISM:
+			    {
+			      pairs = prismpairs;
+			      break;
+			    }
+			  case PYRAMID:
+			    {
+			      pairs = pyramidpairs;
+			      break;
+			    }
+			  }
+
+			for (j = 0; j < 3; j++)
+			  {
+			    INDEX_2 e1 (el.PNum(pairs[j][0]), 
+					el.PNum(pairs[j][1]));
+			    INDEX_2 e2 (el.PNum(pairs[j][2]), 
+					el.PNum(pairs[j][3]));
+			    e1.Sort();
+			    e2.Sort();
+			  
+			    int used1 = edgenumber.Used (e1);
+			    int used2 = edgenumber.Used (e2);
+			  
+			    if (used1 && !used2)
+			      {
+				cnt++;
+				edgenumber.Set (e2, cnt);
+				go_on = 1;
+			      }
+			    if (used2 && !used1)
+			      {
+				cnt++;
+				edgenumber.Set (e1, cnt);
+				go_on = 1;
+			      }
+			  }
+		      }
+		  }
+		while (go_on);
+	      }
+	  }
+	while (found);
+
+	return cnt;
+      }
+  }
+
+
+
+
+  void BTDefineMarkedTet (const Element & el,
+			  INDEX_2_CLOSED_HASHTABLE<int> & edgenumber,
+			  MarkedTet & mt)
+  {
+    int i, j, k;
+    for (i = 0; i < 4; i++)
+      mt.pnums[i] = el[i];
+
+    mt.marked = 0;
+    mt.flagged = 0;
+
+    mt.incorder = 0;
+    mt.order = 1;
+  
+    int val = 0;
+    // find marked edge of tet:
+    for (i = 0; i < 3; i++)
+      for (j = i+1; j < 4; j++)
+	{
+	  INDEX_2 i2(mt.pnums[i], mt.pnums[j]);
+	  i2.Sort();
+	  int hval = edgenumber.Get(i2);
+	  if (hval > val)
+	    {
+	      val = hval;
+	      mt.tetedge1 = i;
+	      mt.tetedge2 = j;    
+	    }
+	}
+
+
+    // find marked edges of faces:
+    for (k = 0; k < 4; k++)
+      {
+	val = 0;
+	for (i = 0; i < 3; i++)
+	  for (j = i+1; j < 4; j++)
+	    if (i != k && j != k)
+	      {
+		INDEX_2 i2(mt.pnums[i], mt.pnums[j]);
+		i2.Sort();
+		int hval = edgenumber.Get(i2);
+		if (hval > val)
+		  {
+		    val = hval;
+		    mt.faceedges[k] = 6 - k - i - j;
+		  }
+	      }
+      }
+  }
+
+
+
+
+  void BTDefineMarkedPrism (const Element & el,
+			    INDEX_2_CLOSED_HASHTABLE<int> & edgenumber,
+			    MarkedPrism & mp)
+  {
+    int i, j;
+
+    if (el.GetType() == PRISM ||
+	el.GetType() == PRISM12)
+      {
+	for (i = 0; i < 6; i++)
+	  mp.pnums[i] = el[i];
+      }
+    else if (el.GetType() == PYRAMID)
+      {
+	static int map[6] = 
+	  { 1, 2, 5, 4, 3, 5 };
+	for (i = 0; i < 6; i++)
+	  mp.pnums[i] = el.PNum(map[i]);
+      }
+    else if (el.GetType() == TET ||
+	     el.GetType() == TET10)
+      {
+	static int map[6] = 
+	  { 1, 4, 3, 2, 4, 3 };
+	for (i = 0; i < 6; i++)
+	  mp.pnums[i] = el.PNum(map[i]);
+      
+      }
+    else
+      {
+	PrintSysError ("Define marked prism called for non-prism and non-pyramid");
+      }
+  
+
+
+    mp.marked = 0;
+
+    mp.incorder = 0;
+    mp.order = 1;
+
+    int val = 0;
+    for (i = 0; i < 2; i++)
+      for (j = i+1; j < 3; j++)
+	{
+	  INDEX_2 i2(mp.pnums[i], mp.pnums[j]);
+	  i2.Sort();
+	  int hval = edgenumber.Get(i2);
+	  if (hval > val)
+	    {
+	      val = hval;
+	      mp.markededge = 3 - i - j;
+	    }
+	}
+  }
+
+
+
+  bool BTDefineMarkedId(const Element2d & el, 
+			INDEX_2_CLOSED_HASHTABLE<int> & edgenumber, 
+			const ARRAY<int,PointIndex::BASE> & idmap,
+			MarkedIdentification & mi)
+  {
+
+    bool identified = true;
+    mi.np = el.GetNP();
+    int min1(0),min2(0);
+    for(int j = 0; identified && j < mi.np; j++)
+      {
+	mi.pnums[j] = el[j];
+	mi.pnums[j+mi.np] = idmap[el[j]];
+
+	if(j == 0 || el[j] < min1)
+	  min1 = el[j];
+	if(j == 0 || mi.pnums[j+mi.np] < min2)
+	  min2 = mi.pnums[j+mi.np];
+
+	identified = (mi.pnums[j+mi.np] != 0 && mi.pnums[j+mi.np] != mi.pnums[j]);
+      }
+
+    identified = identified && (min1 < min2);
+
+    if(identified)
+      {
+	mi.marked = 0;
+	
+	mi.incorder = 0;
+	mi.order = 1;
+
+	int val = 0;
+	for (int i = 0; i < mi.np; i++)
+	  {
+	    INDEX_2 i2(mi.pnums[i], mi.pnums[(i+1)%mi.np]);
+	    i2.Sort();
+	    int hval = edgenumber.Get(i2);
+	    if (hval > val)
+	      {
+		val = hval;
+		mi.markededge = i;
+	      }
+	  }
+      }
+
+    return identified;
+  }
+
+
+  void BTDefineMarkedTri (const Element2d & el,
+			  INDEX_2_CLOSED_HASHTABLE<int> & edgenumber,
+			  MarkedTri & mt)
+  {
+    int i, j;
+    for (i = 0; i < 3; i++)
+      {
+	mt.pnums[i] = el[i];
+	mt.pgeominfo[i] = el.GeomInfoPi (i+1);
+      }
+
+    mt.marked = 0;
+    mt.surfid = el.GetIndex();
+
+    mt.incorder = 0;
+    mt.order = 1;
+
+    int val = 0;
+    for (i = 0; i < 2; i++)
+      for (j = i+1; j < 3; j++)
+	{
+	  INDEX_2 i2(mt.pnums[i], mt.pnums[j]);
+	  i2.Sort();
+	  int hval = edgenumber.Get(i2);
+	  if (hval > val)
+	    {
+	      val = hval;
+	      mt.markededge = 3 - i - j;
+	    }
+	}
+  }
+  
+
+  
+  void PrettyPrint(ostream & ost, const MarkedTri & mt)
+  {
+    ost << "MarkedTrig: " << endl;
+    ost << "  pnums = "; for (int i=0; i<3; i++) ost << mt.pnums[i] << " "; ost << endl; 
+    ost << "  marked = " << mt.marked << ", markededge=" << mt.markededge << endl;
+    for(int i=0; i<2; i++)
+      for(int j=i+1; j<3; j++)
+	if(mt.markededge == 3-i-j)
+	  ost << "  marked edge pnums = " << mt.pnums[i] << " " << mt.pnums[j] << endl;
+  }
+
+
+  void PrettyPrint(ostream & ost, const MarkedQuad & mq)
+  {
+    ost << "MarkedQuad: " << endl;
+    ost << "  pnums = "; for (int i=0; i<4; i++) ost << mq.pnums[i] << " "; ost << endl; 
+    ost << "  marked = " << mq.marked << ", markededge=" << mq.markededge << endl;
+  }
+
+
+
+
+
+  void BTDefineMarkedQuad (const Element2d & el,
+			   INDEX_2_CLOSED_HASHTABLE<int> & edgenumber,
+			   MarkedQuad & mq)
+  {
+    int i;
+    for (i = 0; i < 4; i++)
+      mq.pnums[i] = el[i];
+    Swap (mq.pnums[2], mq.pnums[3]);  
+
+    mq.marked = 0;
+    mq.markededge = 0;
+    mq.surfid = el.GetIndex();
+  }
+
+
+
+
+  // mark elements due to local h
+  int BTMarkTets (T_MTETS & mtets,
+		  T_MPRISMS & mprisms,
+		  const Mesh & mesh)
+  {
+    int i, j, k;
+    int step;
+
+    int marked = 0;
+
+    int np = mesh.GetNP();
+    Vector hv(np);
+    for (i = 1; i <= np; i++)
+      hv.Elem(i) = mesh.GetH (mesh.Point(i));
+
+    double hfac = 1;
+  
+    for (step = 1; step <= 2; step++)
+      {
+	for (i = 1; i <= mtets.Size(); i++)
+	  {
+	    double h = 0;
+	  
+	    for (j = 0; j < 3; j++)
+	      for (k = j+1; k < 4; k++)
+		{
+		  const Point<3> & p1 = mesh.Point (mtets.Get(i).pnums[j]);
+		  const Point<3> & p2 = mesh.Point (mtets.Get(i).pnums[k]);
+		  double hh = Dist2 (p1, p2);
+		  if (hh > h) h = hh;
+		}
+	    h = sqrt (h);
+	  
+	    double hshould = 1e10;
+	    for (j = 0; j < 4; j++)
+	      {
+		double hi = hv.Get (mtets.Get(i).pnums[j]);
+		if (hi < hshould)
+		  hshould = hi;
+	      }
+	  
+	
+	    if (step == 1)
+	      {
+		if (h / hshould > hfac)
+		  hfac = h / hshould;
+	      }
+	    else
+	      {
+		if (h > hshould * hfac)
+		  {
+		    mtets.Elem(i).marked = 1;
+		    marked = 1;
+		  }
+		else
+		  mtets.Elem(i).marked = 0;
+	      }
+	  
+	  }
+	for (i = 1; i <= mprisms.Size(); i++)
+	  {
+	    double h = 0;
+	  
+	    for (j = 0; j < 2; j++)
+	      for (k = j+1; k < 3; k++)
+		{
+		  const Point<3> & p1 = mesh.Point (mprisms.Get(i).pnums[j]);
+		  const Point<3> & p2 = mesh.Point (mprisms.Get(i).pnums[k]);
+		  double hh = Dist2 (p1, p2);
+		  if (hh > h) h = hh;
+		}
+	    h = sqrt (h);
+	  
+	    double hshould = 1e10;
+	    for (j = 0; j < 6; j++)
+	      {
+		double hi = hv.Get (mprisms.Get(i).pnums[j]);
+		if (hi < hshould)
+		  hshould = hi;
+	      }
+	  
+	
+	    if (step == 1)
+	      {
+		if (h / hshould > hfac)
+		  hfac = h / hshould;
+	      }
+	    else
+	      {
+		if (h > hshould * hfac)
+		  {
+		    mprisms.Elem(i).marked = 1;
+		    marked = 1;
+		  }
+		else
+		  mprisms.Elem(i).marked = 0;
+	      }
+	  
+	  }
+
+
+
+	if (step == 1)
+	  {
+	    if (hfac > 2)
+	      hfac /= 2;
+	    else
+	      hfac = 1;
+	  }
+
+      }
+    return marked;
+  }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+  void BTBisectTet (const MarkedTet & oldtet, int newp, 
+		    MarkedTet & newtet1, MarkedTet & newtet2)
+  {
+    int i, j, k;
+  
+  
+    // points vis a vis from tet-edge
+    int vis1, vis2;
+    vis1 = 0;
+    while (vis1 == oldtet.tetedge1 || vis1 == oldtet.tetedge2)
+      vis1++;
+    vis2 = 6 - vis1 - oldtet.tetedge1 - oldtet.tetedge2;
+
+
+    // is tet of type P ?
+    int istypep = 0;
+    for (i = 0; i < 4; i++)
+      {
+	int cnt = 0;
+	for (j = 0; j < 4; j++)
+	  if (oldtet.faceedges[j] == i)
+	    cnt++;
+	if (cnt == 3)
+	  istypep = 1;
+      }
+
+
+  
+    for (i = 0; i < 4; i++)
+      {
+	newtet1.pnums[i] = oldtet.pnums[i];
+	newtet2.pnums[i] = oldtet.pnums[i];
+      }
+    newtet1.flagged = istypep && !oldtet.flagged;
+    newtet2.flagged = istypep && !oldtet.flagged;
+
+    int nm = oldtet.marked - 1;
+    if (nm < 0) nm = 0;
+    newtet1.marked = nm;
+    newtet2.marked = nm;
+
+
+    for (i = 0; i < 4; i++)
+      {
+	if (i == oldtet.tetedge1)
+	  {
+	    newtet2.pnums[i] = newp;
+	    newtet2.faceedges[i] = oldtet.faceedges[i];  // inherited face
+	    newtet2.faceedges[vis1] = i;        // cut faces
+	    newtet2.faceedges[vis2] = i;
+
+	    j = 0;
+	    while (j == i || j == oldtet.faceedges[i])
+	      j++;
+	    k = 6 - i - oldtet.faceedges[i] - j;
+	    newtet2.tetedge1 = j;                        // tet-edge
+	    newtet2.tetedge2 = k;         
+
+	    // new face:
+	    if (istypep && oldtet.flagged)
+	      newtet2.faceedges[oldtet.tetedge2] = 
+		6 - oldtet.tetedge1 - j - k;
+	    else
+	      newtet2.faceedges[oldtet.tetedge2] = oldtet.tetedge1;
+	  }
+
+	if (i == oldtet.tetedge2)
+	  {
+	    newtet1.pnums[i] = newp;
+	    newtet1.faceedges[i] = oldtet.faceedges[i];  // inherited face
+	    newtet1.faceedges[vis1] = i;
+	    newtet1.faceedges[vis2] = i;
+	    j = 0;
+	    while (j == i || j == oldtet.faceedges[i])
+	      j++;
+	    k = 6 - i - oldtet.faceedges[i] - j;
+	    newtet1.tetedge1 = j;        
+	    newtet1.tetedge2 = k;
+
+	    // new face:
+	    if (istypep && oldtet.flagged)
+	      newtet1.faceedges[oldtet.tetedge1] = 
+		6 - oldtet.tetedge2 - j - k;
+	    else
+	      newtet1.faceedges[oldtet.tetedge1] = oldtet.tetedge2;
+	  }
+      }
+
+    newtet1.matindex = oldtet.matindex;
+    newtet2.matindex = oldtet.matindex;
+    newtet1.incorder = 0;
+    newtet1.order = oldtet.order;
+    newtet2.incorder = 0;
+    newtet2.order = oldtet.order;
+  }
+
+
+  
+
+  void BTBisectPrism (const MarkedPrism & oldprism, int newp1, int newp2,
+		      MarkedPrism & newprism1, MarkedPrism & newprism2)
+  {
+    int i;
+
+    for (i = 0; i < 6; i++)
+      {
+	newprism1.pnums[i] = oldprism.pnums[i];
+	newprism2.pnums[i] = oldprism.pnums[i];
+      }  
+    
+    int pe1, pe2;
+    pe1 = 0;
+    if (pe1 == oldprism.markededge)
+      pe1++;
+    pe2 = 3 - oldprism.markededge - pe1;
+
+    newprism1.pnums[pe2] = newp1;
+    newprism1.pnums[pe2+3] = newp2;
+    newprism1.markededge = pe2;
+    newprism2.pnums[pe1] = newp1;
+    newprism2.pnums[pe1+3] = newp2;
+    newprism2.markededge = pe1;
+
+    newprism1.matindex = oldprism.matindex;
+    newprism2.matindex = oldprism.matindex;
+
+    int nm = oldprism.marked - 1;
+    if (nm < 0) nm = 0;
+    newprism1.marked = nm;
+    newprism2.marked = nm;
+
+    newprism1.incorder = 0;
+    newprism1.order = oldprism.order;
+    newprism2.incorder = 0;
+    newprism2.order = oldprism.order;
+  }
+
+
+  void BTBisectIdentification (const MarkedIdentification & oldid,
+			       ARRAY<int> & newp,
+			       MarkedIdentification & newid1,
+			       MarkedIdentification & newid2)
+  {
+    for(int i=0; i<2*oldid.np; i++)
+      {
+	newid1.pnums[i] = oldid.pnums[i];
+	newid2.pnums[i] = oldid.pnums[i];
+      }
+    newid1.np = newid2.np = oldid.np;
+
+    if(oldid.np == 3)
+      {
+	newid1.pnums[(oldid.markededge+1)%3] = newp[0];
+	newid1.pnums[(oldid.markededge+1)%3+3] = newp[1];
+	newid1.markededge = (oldid.markededge+2)%3;
+
+	newid2.pnums[oldid.markededge] = newp[0];
+	newid2.pnums[oldid.markededge+3] = newp[1];
+	newid2.markededge = (oldid.markededge+1)%3;
+      }
+    else if(oldid.np == 4)
+      {
+	newid1.pnums[(oldid.markededge+1)%4] = newp[0];
+	newid1.pnums[(oldid.markededge+2)%4] = newp[2];
+	newid1.pnums[(oldid.markededge+1)%4+4] = newp[1];
+	newid1.pnums[(oldid.markededge+2)%4+4] = newp[3];
+	newid1.markededge = (oldid.markededge+3)%4;
+
+	newid2.pnums[oldid.markededge] = newp[0];
+	newid2.pnums[(oldid.markededge+3)%4] = newp[2];
+	newid2.pnums[oldid.markededge+4] = newp[1];
+	newid2.pnums[(oldid.markededge+3)%4+4] = newp[3];
+	newid2.markededge = (oldid.markededge+1)%4;
+      }
+
+    
+    int nm = oldid.marked - 1;
+    if (nm < 0) nm = 0;
+    newid1.marked = newid2.marked = nm;
+
+    newid1.incorder = newid2.incorder = 0;
+    newid1.order = newid2.order = oldid.order;
+  }
+
+
+
+  void BTBisectTri (const MarkedTri & oldtri, int newp, const PointGeomInfo & newpgi,
+		    MarkedTri & newtri1, MarkedTri & newtri2)
+  {
+    int i;
+
+    for (i = 0; i < 3; i++)
+      {
+	newtri1.pnums[i] = oldtri.pnums[i];
+	newtri1.pgeominfo[i] = oldtri.pgeominfo[i];
+	newtri2.pnums[i] = oldtri.pnums[i];
+	newtri2.pgeominfo[i] = oldtri.pgeominfo[i];
+      }  
+
+    int pe1, pe2;
+    pe1 = 0;
+    if (pe1 == oldtri.markededge)
+      pe1++;
+    pe2 = 3 - oldtri.markededge - pe1;
+
+    newtri1.pnums[pe2] = newp;
+    newtri1.pgeominfo[pe2] = newpgi;
+    newtri1.markededge = pe2;
+
+    newtri2.pnums[pe1] = newp;
+    newtri2.pgeominfo[pe1] = newpgi;
+    newtri2.markededge = pe1;
+
+
+    newtri1.surfid = oldtri.surfid;
+    newtri2.surfid = oldtri.surfid;
+
+    int nm = oldtri.marked - 1;
+    if (nm < 0) nm = 0;
+    newtri1.marked = nm;
+    newtri2.marked = nm;
+
+    newtri1.incorder = 0;
+    newtri1.order = oldtri.order;
+    newtri2.incorder = 0;
+    newtri2.order = oldtri.order;
+    
+    
+  }
+
+
+  void BTBisectQuad (const MarkedQuad & oldquad, 
+		     int newp1, const PointGeomInfo & npgi1, 
+		     int newp2, const PointGeomInfo & npgi2, 
+		     MarkedQuad & newquad1, MarkedQuad & newquad2)
+  {
+    int i;
+
+    for (i = 0; i < 4; i++)
+      {
+	newquad1.pnums[i] = oldquad.pnums[i];
+	newquad1.pgeominfo[i] = oldquad.pgeominfo[i];
+	newquad2.pnums[i] = oldquad.pnums[i];
+	newquad2.pgeominfo[i] = oldquad.pgeominfo[i];
+      }  
+
+/*    if (oldquad.marked==1) // he/sz: 2d quads or 3d prism
+    {   
+      newquad1.pnums[1] = newp1;
+      newquad1.pgeominfo[1] = npgi1;
+      newquad1.pnums[3] = newp2;
+      newquad1.pgeominfo[3] = npgi2;
+
+      newquad2.pnums[0] = newp1;
+      newquad2.pgeominfo[0] = npgi1;
+      newquad2.pnums[2] = newp2;
+      newquad2.pgeominfo[2] = npgi2;
+    }
+      
+    else if (oldquad.marked==2) // he/sz: 2d quads only
+    {
+      newquad1.pnums[0] = newp1;
+      newquad1.pnums[1] = newp2;
+      newquad1.pnums[3] = oldquad.pnums[2];  
+      newquad1.pnums[2] = oldquad.pnums[0]; 
+      newquad1.pgeominfo[0] = npgi1;
+      newquad1.pgeominfo[1] = npgi2;
+      newquad1.pgeominfo[3] = oldquad.pgeominfo[2]; 
+      newquad1.pgeominfo[2] = oldquad.pgeominfo[0];
+
+      newquad2.pnums[0] = newp2;
+      newquad2.pnums[1] = newp1;
+      newquad2.pnums[3] = oldquad.pnums[1];  
+      newquad2.pnums[2] = oldquad.pnums[3]; 
+      newquad2.pgeominfo[0] = npgi2;
+      newquad2.pgeominfo[1] = npgi1;
+      newquad2.pgeominfo[3] = oldquad.pgeominfo[1]; 
+      newquad2.pgeominfo[2] = oldquad.pgeominfo[3];
+    }
+      
+    */
+      
+    if (oldquad.markededge==0 || oldquad.markededge==2)
+    {
+      newquad1.pnums[1] = newp1;
+      newquad1.pgeominfo[1] = npgi1;
+      newquad1.pnums[3] = newp2;
+      newquad1.pgeominfo[3] = npgi2;
+
+      newquad2.pnums[0] = newp1;
+      newquad2.pgeominfo[0] = npgi1;
+      newquad2.pnums[2] = newp2;
+      newquad2.pgeominfo[2] = npgi2;
+    }
+    else // 1 || 3 
+    {
+      newquad1.pnums[2] = newp1;
+      newquad1.pgeominfo[2] = npgi1;
+      newquad1.pnums[3] = newp2;
+      newquad1.pgeominfo[3] = npgi2;
+
+      newquad2.pnums[0] = newp1;
+      newquad2.pgeominfo[0] = npgi1;
+      newquad2.pnums[1] = newp2;
+      newquad2.pgeominfo[1] = npgi2;
+    }
+    newquad1.surfid = oldquad.surfid;
+    newquad2.surfid = oldquad.surfid;
+
+    int nm = oldquad.marked - 1;
+    if (nm < 0) nm = 0;
+
+    newquad1.marked = nm;
+    newquad2.marked = nm;
+    
+    if (nm==1)
+    {
+      newquad1.markededge=1;
+      newquad2.markededge=1;
+    }
+    else
+    {
+      newquad1.markededge=0;
+      newquad2.markededge=0;
+    }
+    
+  }
+
+
+  int MarkHangingIdentifications(T_MIDS & mids, 
+				 const INDEX_2_CLOSED_HASHTABLE<int> & cutedges)
+  {
+    int i, j;
+    
+    int hanging = 0;
+    for (i = 1; i <= mids.Size(); i++)
+      {
+	if (mids.Elem(i).marked)
+	  {
+	    hanging = 1;
+	    continue;
+	  }
+
+	const int np = mids.Get(i).np;
+
+	for(j = 0; j < np; j++)
+	  {
+	    INDEX_2 edge1(mids.Get(i).pnums[j],
+			  mids.Get(i).pnums[(j+1) % np]);
+	    INDEX_2 edge2(mids.Get(i).pnums[j+np],
+			  mids.Get(i).pnums[((j+1) % np) + np]);
+
+	    edge1.Sort();
+	    edge2.Sort();
+	    if (cutedges.Used (edge1) ||
+		cutedges.Used (edge2))
+	      {
+		mids.Elem(i).marked = 1;
+		hanging = 1;
+	      }
+	  }
+      }
+
+    return hanging;
+  }
+
+
+  /*
+  void IdentifyCutEdges(Mesh & mesh,
+			INDEX_2_CLOSED_HASHTABLE<int> & cutedges)
+  {
+    int i,j,k;
+
+    ARRAY< ARRAY<int,PointIndex::BASE>* > idmaps;
+    for(i=1; i<=mesh.GetIdentifications().GetMaxNr(); i++)
+      {
+	idmaps.Append(new ARRAY<int,PointIndex::BASE>);
+	mesh.GetIdentifications().GetMap(i,*idmaps.Last());
+      }
+
+
+    
+    for(SurfaceElementIndex sei = 0; sei < mesh.GetNSE(); sei++)
+      {
+	const Element2d & el2d = mesh[sei];
+	
+	for(i = 0; i < el2d.GetNP(); i++)
+	  {
+	    INDEX_2 e1(el2d[i], el2d[(i+1) % el2d.GetNP()]);
+	    e1.Sort();
+
+	    if(!cutedges.Used(e1))
+	      continue;
+
+	    
+	    for(k = 0; k < idmaps.Size(); k++)
+	      {
+		INDEX_2 e2((*idmaps[k])[e1.I1()],
+			   (*idmaps[k])[e1.I2()]);
+		
+		if(e2.I1() == 0 || e2.I2() == 0 ||
+		   e1.I1() == e2.I1() || e1.I2() == e2.I2())
+		  continue;
+		
+		e2.Sort();
+
+		if(cutedges.Used(e2))
+		  continue;
+
+		Point3d np = Center(mesh.Point(e2.I1()),
+				    mesh.Point(e2.I2()));
+		int newp = mesh.AddPoint(np);
+		cutedges.Set(e2,newp);
+		(*testout) << "DAAA" << endl;
+	      }
+	  }
+      }
+
+    
+    for(i=0; i<idmaps.Size(); i++)
+      delete idmaps[i];
+    idmaps.DeleteAll();
+  }
+  */
+
+
+  int MarkHangingTets (T_MTETS & mtets, 
+		       const INDEX_2_CLOSED_HASHTABLE<int> & cutedges)
+  {
+    int i, j, k;
+
+    int hanging = 0;
+    for (i = 1; i <= mtets.Size(); i++)
+      {
+	MarkedTet & teti = mtets.Elem(i);
+
+	if (teti.marked)
+	  {
+	    hanging = 1;
+	    continue;
+	  }
+
+	for (j = 0; j < 3; j++)
+	  for (k = j+1; k < 4; k++)
+	    {
+	      INDEX_2 edge(teti.pnums[j],
+			   teti.pnums[k]);
+	      edge.Sort();
+	      if (cutedges.Used (edge))
+		{
+		  teti.marked = 1;
+		  hanging = 1;
+		}
+	    }
+      }
+
+    return hanging;
+  }
+
+
+
+  int MarkHangingPrisms (T_MPRISMS & mprisms, 
+			 const INDEX_2_CLOSED_HASHTABLE<int> & cutedges)
+  {
+    int i, j, k;
+
+    int hanging = 0;
+    for (i = 1; i <= mprisms.Size(); i++)
+      {
+	if (mprisms.Elem(i).marked)
+	  {
+	    hanging = 1;
+	    continue;
+	  }
+
+	for (j = 0; j < 2; j++)
+	  for (k = j+1; k < 3; k++)
+	    {
+	      INDEX_2 edge1(mprisms.Get(i).pnums[j],
+			    mprisms.Get(i).pnums[k]);
+	      INDEX_2 edge2(mprisms.Get(i).pnums[j+3],
+			    mprisms.Get(i).pnums[k+3]);
+	      edge1.Sort();
+	      edge2.Sort();
+	      if (cutedges.Used (edge1) ||
+		  cutedges.Used (edge2))
+		{
+		  mprisms.Elem(i).marked = 1;
+		  hanging = 1;
+		}
+	    }
+      }
+    return hanging;
+  }
+
+
+
+  int MarkHangingTris (T_MTRIS & mtris, 
+		       const INDEX_2_CLOSED_HASHTABLE<int> & cutedges)
+  {
+    int i, j, k;
+
+    int hanging = 0;
+    for (i = 1; i <= mtris.Size(); i++)
+      {
+	if (mtris.Get(i).marked)
+	  {
+	    hanging = 1;
+	    continue;
+	  }
+	for (j = 0; j < 2; j++)
+	  for (k = j+1; k < 3; k++)
+	    {
+	      INDEX_2 edge(mtris.Get(i).pnums[j],
+			   mtris.Get(i).pnums[k]);
+	      edge.Sort();
+	      if (cutedges.Used (edge))
+		{
+		  mtris.Elem(i).marked = 1;
+		  hanging = 1;
+                }
+	    }
+      }  
+      return hanging;
+  }
+
+
+
+  int MarkHangingQuads (T_MQUADS & mquads, 
+			const INDEX_2_CLOSED_HASHTABLE<int> & cutedges)
+  {
+    int i;
+
+    int hanging = 0;
+    for (i = 1; i <= mquads.Size(); i++)
+      {
+	if (mquads.Elem(i).marked)
+	  {
+	    hanging = 1;
+	    continue;
+	  }
+
+	INDEX_2 edge1(mquads.Get(i).pnums[0],
+		      mquads.Get(i).pnums[1]);
+	INDEX_2 edge2(mquads.Get(i).pnums[2],
+		      mquads.Get(i).pnums[3]);
+	edge1.Sort();
+	edge2.Sort();
+	if (cutedges.Used (edge1) ||
+	    cutedges.Used (edge2))
+	  {
+	    mquads.Elem(i).marked = 1;
+            mquads.Elem(i).markededge = 0;
+	    hanging = 1;
+            continue;
+	  }
+          
+        // he/sz: second case: split horizontally
+        INDEX_2 edge3(mquads.Get(i).pnums[1],
+                      mquads.Get(i).pnums[3]);
+        INDEX_2 edge4(mquads.Get(i).pnums[2],
+                      mquads.Get(i).pnums[0]);
+
+        edge3.Sort();
+        edge4.Sort();
+        if (cutedges.Used (edge3) ||
+            cutedges.Used (edge4))
+        {
+          mquads.Elem(i).marked = 1;
+          mquads.Elem(i).markededge = 1;
+          hanging = 1; 
+          continue; 
+        }
+    
+      }
+    return hanging;
+  }
+
+
+
+  void ConnectToNodeRec (int node, int tonode, 
+			 const TABLE<int> & conto, ARRAY<int> & connecttonode)
+  {
+    int i, n2;
+    //  (*testout) << "connect " << node << " to " << tonode << endl;
+    for (i = 1; i <= conto.EntrySize(node); i++)
+      {
+	n2 = conto.Get(node, i);
+	if (!connecttonode.Get(n2))
+	  {
+	    connecttonode.Elem(n2) = tonode;
+	    ConnectToNodeRec (n2, tonode, conto, connecttonode);
+	  }
+      }
+  }
+
+
+
+
+  T_MTETS mtets;
+  T_MPRISMS mprisms;
+  T_MIDS mids;
+  T_MTRIS mtris;
+  T_MQUADS mquads;
+
+
+  void WriteMarkedElements(ostream & ost)
+  {
+    ost << "Marked Elements\n";
+
+    ost << mtets.Size() << "\n";
+    for(int i=0; i<mtets.Size(); i++)
+      ost << mtets[i];
+
+    ost << mprisms.Size() << "\n";
+    for(int i=0; i<mprisms.Size(); i++)
+      ost << mprisms[i];
+
+    ost << mids.Size() << "\n";
+    for(int i=0; i<mids.Size(); i++)
+      ost << mids[i];
+
+    ost << mtris.Size() << "\n";
+    for(int i=0; i<mtris.Size(); i++)
+      ost << mtris[i];
+
+    ost << mquads.Size() << "\n";
+    for(int i=0; i<mquads.Size(); i++)
+      ost << mquads[i];
+    ost << endl;
+  }
+
+  bool ReadMarkedElements(istream & ist, const Mesh & mesh)
+  {
+    string auxstring("");
+    if(ist)
+      ist >> auxstring;
+
+    if(auxstring != "Marked")
+      return false;
+
+    if(ist)
+      ist >> auxstring;
+
+    if(auxstring != "Elements")
+      return false;
+
+    int size;
+
+    ist >> size;
+    mtets.SetSize(size);
+    for(int i=0; i<size; i++)
+		{
+			ist >> mtets[i];
+			if(mtets[i].pnums[0] > mesh.GetNV() || 
+				mtets[i].pnums[1] > mesh.GetNV() || 
+				mtets[i].pnums[2] > mesh.GetNV() || 
+				mtets[i].pnums[3] > mesh.GetNV())
+				return false;
+		}
+
+    ist >> size;
+    mprisms.SetSize(size);
+    for(int i=0; i<size; i++)
+      ist >> mprisms[i];
+
+    ist >> size;
+    mids.SetSize(size);
+    for(int i=0; i<size; i++)
+      ist >> mids[i];
+
+    ist >> size;
+    mtris.SetSize(size);
+    for(int i=0; i<size; i++)
+      ist >> mtris[i];
+
+    ist >> size;
+    mquads.SetSize(size);
+    for(int i=0; i<size; i++)
+      ist >> mquads[i];
+
+    return true;
+  }
+
+
+
+
+
+  void BisectTetsCopyMesh (Mesh & mesh, const class CSGeometry *,
+			   BisectionOptions & opt,
+			   const ARRAY< ARRAY<int,PointIndex::BASE>* > & idmaps,
+			   const string & refinfofile)
+  {
+    mtets.SetName ("bisection, tets");
+    mprisms.SetName ("bisection, prisms");
+    mtris.SetName ("bisection, trigs");
+    mquads.SetName ("bisection, quads");
+    mids.SetName ("bisection, identifications");
+
+    //int np = mesh.GetNP();
+    int ne = mesh.GetNE();
+    int nse = mesh.GetNSE();
+    int i, j, k, l, m;
+
+    /*
+      if (mtets.Size() + mprisms.Size() == mesh.GetNE())
+      return;
+    */
+
+    bool readok = false;
+
+    if(refinfofile != "")
+      {
+	PrintMessage(3,"Reading marked-element information from \"",refinfofile,"\"");
+	ifstream ist(refinfofile.c_str());
+
+	readok = ReadMarkedElements(ist,mesh);
+
+	ist.close();
+      }
+
+    if(!readok)
+      {
+	PrintMessage(3,"resetting marked-element information");
+	mtets.SetSize(0);
+	mprisms.SetSize(0);
+	mids.SetSize(0);
+	mtris.SetSize(0);
+	mquads.SetSize(0);
+	
+	
+	INDEX_2_HASHTABLE<int> shortedges(100);
+	for (i = 1; i <= ne; i++)
+	  {
+	    const Element & el = mesh.VolumeElement(i);
+	    if (el.GetType() == PRISM ||
+		el.GetType() == PRISM12)
+	      {
+		for (j = 1; j <= 3; j++)
+		  {
+		    INDEX_2 se(el.PNum(j), el.PNum(j+3));
+		    se.Sort();
+		    shortedges.Set (se, 1);
+		  }
+	      }
+	  }
+	
+	
+	
+	// INDEX_2_HASHTABLE<int> edgenumber(np);
+	INDEX_2_CLOSED_HASHTABLE<int> edgenumber(9*ne+4*nse);  
+	
+	BTSortEdges (mesh, idmaps, edgenumber);
+	
+	
+	for (i = 1; i <= ne; i++)
+	  {
+	    const Element & el = mesh.VolumeElement(i);
+	    
+	    switch (el.GetType())
+	      {
+	      case TET:
+	      case TET10:
+		{
+		  // if tet has short edge, it is handled as degenerated prism
+		  
+		  int foundse = 0;
+		  for (j = 1; j <= 3; j++)
+		    for (k = j+1; k <= 4; k++)
+		      {
+			INDEX_2 se(el.PNum(j), el.PNum(k));
+			se.Sort();
+			if (shortedges.Used (se))
+			  {
+			    //		      cout << "tet converted to prism" << endl;
+			    
+			    foundse = 1;
+			    int p3 = 1;
+			    while (p3 == j || p3 == k)
+			      p3++;
+			    int p4 = 10 - j - k - p3;
+			    
+			    // even permutation ?
+			    int pi[4];
+			    pi[0] = j;
+			    pi[1] = k;
+			    pi[2] = p3;
+			    pi[3] = p4;
+			    int cnt = 0;
+			    for (l = 1; l <= 4; l++)
+			      for (m = 0; m < 3; m++)
+				if (pi[m] > pi[m+1])
+				  {
+				    Swap (pi[m], pi[m+1]);
+				    cnt++;
+				  }
+			    if (cnt % 2)
+			      Swap (p3, p4);
+			    
+			    Element hel = el;
+			    hel.PNum(1) = el.PNum(j);
+			    hel.PNum(2) = el.PNum(k);
+			    hel.PNum(3) = el.PNum(p3);
+			    hel.PNum(4) = el.PNum(p4);
+			    
+			    MarkedPrism mp;
+			    BTDefineMarkedPrism (hel, edgenumber, mp);
+			    mp.matindex = el.GetIndex();
+			    mprisms.Append (mp);
+			  }
+		      }
+		  if (!foundse)
+		    {
+		      MarkedTet mt;
+		      BTDefineMarkedTet (el, edgenumber, mt);
+		      mt.matindex = el.GetIndex();
+		      mtets.Append (mt);
+		    }
+		  break;
+		}
+	      case PYRAMID:
+		{
+		  // eventually rotate
+		  MarkedPrism mp;
+		  
+		  INDEX_2 se(el.PNum(1), el.PNum(2));
+		  se.Sort();
+		  if (shortedges.Used (se))
+		    {
+		      Element hel = el;
+		      hel.PNum(1) = el.PNum(2);
+		      hel.PNum(2) = el.PNum(3);
+		      hel.PNum(3) = el.PNum(4);
+		      hel.PNum(4) = el.PNum(1);
+		      BTDefineMarkedPrism (hel, edgenumber, mp);
+		    }
+		  else
+		    {
+		      BTDefineMarkedPrism (el, edgenumber, mp);
+		    }
+		  
+		  mp.matindex = el.GetIndex();
+		  mprisms.Append (mp);
+		  break;
+		}
+	      case PRISM:
+	      case PRISM12:
+		{
+		  MarkedPrism mp;
+		  BTDefineMarkedPrism (el, edgenumber, mp);
+		  mp.matindex = el.GetIndex();
+		  mprisms.Append (mp);
+		  break;
+		}
+	      }
+	  }
+	
+	for (i = 1; i <= nse; i++)
+	  {
+	    const Element2d & el = mesh.SurfaceElement(i);
+	    if (el.GetType() == TRIG ||
+		el.GetType() == TRIG6)
+	      {
+		MarkedTri mt;
+		BTDefineMarkedTri (el, edgenumber, mt);
+		mtris.Append (mt);
+	      }
+	    else
+	      {
+		MarkedQuad mq;
+		BTDefineMarkedQuad (el, edgenumber, mq);
+		mquads.Append (mq);
+	      }
+	    
+	    MarkedIdentification mi;
+	    for(j=0; j<idmaps.Size(); j++)
+	      if(BTDefineMarkedId(el, edgenumber, *idmaps[j], mi))
+		mids.Append(mi);
+	  }
+      }
+	
+
+
+
+    mesh.mlparentelement.SetSize(ne);
+    for (i = 1; i <= ne; i++)
+      mesh.mlparentelement.Elem(i) = 0;
+    mesh.mlparentsurfaceelement.SetSize(nse);
+    for (i = 1; i <= nse; i++)
+      mesh.mlparentsurfaceelement.Elem(i) = 0;
+  
+    if (printmessage_importance>0)
+    {
+      ostringstream str1,str2;
+      str1 << "copied " << mtets.Size() << " tets, " << mprisms.Size() << " prisms";
+      str2 << "       " << mtris.Size() << " trigs, " << mquads.Size() << " quads";
+
+      PrintMessage(4,str1.str());
+      PrintMessage(4,str2.str());
+    }
+  }
+
+
+  /*
+  void UpdateEdgeMarks2(Mesh & mesh,
+			const ARRAY< ARRAY<int,PointIndex::BASE>* > & idmaps)
+  {
+    ARRAY< ARRAY<MarkedTet>*,PointIndex::BASE > mtets_old(mesh.GetNP());
+    ARRAY< ARRAY<MarkedPrism>*,PointIndex::BASE > mprisms_old(mesh.GetNP());
+    ARRAY< ARRAY<MarkedIdentification>*,PointIndex::BASE > mids_old(mesh.GetNP());
+    ARRAY< ARRAY<MarkedTri>*,PointIndex::BASE > mtris_old(mesh.GetNP());
+    ARRAY< ARRAY<MarkedQuad>*,PointIndex::BASE > mquads_old(mesh.GetNP());
+
+    for(int i=PointIndex::BASE; i<mesh.GetNP()+PointIndex::BASE; i++)
+      mtets_old[i] = new ARRAY<MarkedTet>;
+    for(int i=PointIndex::BASE; i<mesh.GetNP()+PointIndex::BASE; i++)
+      mprisms_old[i] = new ARRAY<MarkedPrism>;
+    for(int i=PointIndex::BASE; i<mesh.GetNP()+PointIndex::BASE; i++)
+      mids_old[i] = new ARRAY<MarkedIdentification>;
+    for(int i=PointIndex::BASE; i<mesh.GetNP()+PointIndex::BASE; i++)
+      mtris_old[i] = new ARRAY<MarkedTri>;
+    for(int i=PointIndex::BASE; i<mesh.GetNP()+PointIndex::BASE; i++)
+      mquads_old[i] = new ARRAY<MarkedQuad>;
+
+    for(int i=0; i<mtets.Size(); i++)
+      mtets_old[mtets[i].pnums[0]]->Append(mtets[i]);
+    for(int i=0; i<mprisms.Size(); i++)
+      mprisms_old[mprisms[i].pnums[0]]->Append(mprisms[i]);
+    for(int i=0; i<mids.Size(); i++)
+      mids_old[mids[i].pnums[0]]->Append(mids[i]);
+    for(int i=0; i<mtris.Size(); i++)
+      {
+	(*testout) << "i " << i << endl;
+	(*testout) << "mtris[i] " << mtris[i].pnums[0] << " " << mtris[i].pnums[1] << " " << mtris[i].pnums[2] << endl; 
+	mtris_old[mtris[i].pnums[0]]->Append(mtris[i]);
+      }
+    for(int i=0; i<mquads.Size(); i++)
+      mquads_old[mquads[i].pnums[0]]->Append(mquads[i]);
+
+   
+    
+    int np = mesh.GetNP();
+    int ne = mesh.GetNE();
+    int nse = mesh.GetNSE();
+    int i, j, k, l, m;
+
+
+//       if (mtets.Size() + mprisms.Size() == mesh.GetNE())
+//       return;
+
+    
+
+    mtets.SetSize(0);
+    mprisms.SetSize(0);
+    mids.SetSize(0);
+    mtris.SetSize(0);
+    mquads.SetSize(0);
+
+
+    INDEX_2_HASHTABLE<int> shortedges(100);
+    for (i = 1; i <= ne; i++)
+      {
+	const Element & el = mesh.VolumeElement(i);
+	if (el.GetType() == PRISM ||
+	    el.GetType() == PRISM12)
+	  {
+	    for (j = 1; j <= 3; j++)
+	      {
+		INDEX_2 se(el.PNum(j), el.PNum(j+3));
+		se.Sort();
+		shortedges.Set (se, 1);
+	      }
+	  }
+      }
+
+
+
+    // INDEX_2_HASHTABLE<int> edgenumber(np);
+    INDEX_2_CLOSED_HASHTABLE<int> edgenumber(9*ne+4*nse);  
+
+    BTSortEdges (mesh, idmaps, edgenumber);
+
+
+    for (i = 1; i <= ne; i++)
+      {
+	const Element & el = mesh.VolumeElement(i);
+	  
+	switch (el.GetType())
+	  {
+	  case TET:
+	  case TET10:
+	    {
+	      // if tet has short edge, it is handled as degenerated prism
+
+	      int foundse = 0;
+	      for (j = 1; j <= 3; j++)
+		for (k = j+1; k <= 4; k++)
+		  {
+		    INDEX_2 se(el.PNum(j), el.PNum(k));
+		    se.Sort();
+		    if (shortedges.Used (se))
+		      {
+//		      cout << "tet converted to prism" << endl;
+
+			foundse = 1;
+			int p3 = 1;
+			while (p3 == j || p3 == k)
+			  p3++;
+			int p4 = 10 - j - k - p3;
+
+			// even permutation ?
+			int pi[4];
+			pi[0] = j;
+			pi[1] = k;
+			pi[2] = p3;
+			pi[3] = p4;
+			int cnt = 0;
+			for (l = 1; l <= 4; l++)
+			  for (m = 0; m < 3; m++)
+			    if (pi[m] > pi[m+1])
+			      {
+				Swap (pi[m], pi[m+1]);
+				cnt++;
+			      }
+			if (cnt % 2)
+			  Swap (p3, p4);
+
+			Element hel = el;
+			hel.PNum(1) = el.PNum(j);
+			hel.PNum(2) = el.PNum(k);
+			hel.PNum(3) = el.PNum(p3);
+			hel.PNum(4) = el.PNum(p4);
+
+			MarkedPrism mp;
+
+			BTDefineMarkedPrism (hel, edgenumber, mp);
+			mp.matindex = el.GetIndex();
+			mprisms.Append (mp);
+		      }
+		  }
+	      if (!foundse)
+		{
+		  MarkedTet mt;
+		  
+		  int oldind = -1;
+		  for(l = 0; oldind < 0 && l<mtets_old[el[0]]->Size(); l++)
+		    if(el[1] == (*mtets_old[el[0]])[l].pnums[1] &&
+		       el[2] == (*mtets_old[el[0]])[l].pnums[2] &&
+		       el[3] == (*mtets_old[el[0]])[l].pnums[3])
+		      oldind = l;
+
+		  if(oldind >= 0)
+		    mtets.Append((*mtets_old[el[0]])[oldind]);
+		  else
+		    {
+		      BTDefineMarkedTet (el, edgenumber, mt);
+		      mt.matindex = el.GetIndex();
+		      mtets.Append (mt);
+		    }
+		}
+	      break;
+	    }
+	  case PYRAMID:
+	    {
+	      // eventually rotate
+	      MarkedPrism mp;
+	    
+	      INDEX_2 se(el.PNum(1), el.PNum(2));
+	      se.Sort();
+	      if (shortedges.Used (se))
+		{
+		  Element hel = el;
+		  hel.PNum(1) = el.PNum(2);
+		  hel.PNum(2) = el.PNum(3);
+		  hel.PNum(3) = el.PNum(4);
+		  hel.PNum(4) = el.PNum(1);
+		  BTDefineMarkedPrism (hel, edgenumber, mp);
+		}
+	      else
+		{
+		  BTDefineMarkedPrism (el, edgenumber, mp);
+		}
+
+	      mp.matindex = el.GetIndex();
+	      mprisms.Append (mp);
+	      break;
+	    }
+	  case PRISM:
+	  case PRISM12:
+	    {
+	      MarkedPrism mp;
+	      BTDefineMarkedPrism (el, edgenumber, mp);
+	      mp.matindex = el.GetIndex();
+	      mprisms.Append (mp);
+	      break;
+	    }
+	  }
+      }
+
+    for (i = 1; i <= nse; i++)
+      {
+	const Element2d & el = mesh.SurfaceElement(i);
+	if (el.GetType() == TRIG ||
+	    el.GetType() == TRIG6)
+	  {
+	    MarkedTri mt;
+	    BTDefineMarkedTri (el, edgenumber, mt);
+	    mtris.Append (mt);
+	  }
+	else
+	  {
+	    MarkedQuad mq;
+	    BTDefineMarkedQuad (el, edgenumber, mq);
+	    mquads.Append (mq);
+	  }
+	
+	MarkedIdentification mi;
+
+	
+
+	for(j=0; j<idmaps.Size(); j++)
+	  if(BTDefineMarkedId(el, edgenumber, *idmaps[j], mi))
+	    {
+	      mids.Append(mi);
+		
+	      int oldind = -1;
+	      for(l = 0; oldind < 0 && l<mids_old[mi.pnums[0]]->Size(); l++)
+		{
+		  bool equal = true;
+		  for(int m = 1; equal && m < mi.np; m++)
+		    equal = (mi.pnums[m] == (*mids_old[el[0]])[l].pnums[m]);
+		  if(equal)
+		    oldind = l;
+		}
+
+	      if(oldind >= 0)
+		mids.Last() = (*mids_old[mi.pnums[0]])[oldind];
+	    }
+
+      }
+
+
+
+    for(int i=PointIndex::BASE; i<mesh.GetNP()+PointIndex::BASE; i++)
+      delete mtets_old[i];
+    for(int i=PointIndex::BASE; i<mesh.GetNP()+PointIndex::BASE; i++)
+      delete mprisms_old[i];
+    for(int i=PointIndex::BASE; i<mesh.GetNP()+PointIndex::BASE; i++)
+      delete mids_old[i];
+    for(int i=PointIndex::BASE; i<mesh.GetNP()+PointIndex::BASE; i++)
+      delete mtris_old[i];
+    for(int i=PointIndex::BASE; i<mesh.GetNP()+PointIndex::BASE; i++)
+      delete mquads_old[i];
+  }
+*/
+
+  
+  void UpdateEdgeMarks (Mesh & mesh,
+			const ARRAY< ARRAY<int,PointIndex::BASE>* > & idmaps)
+  //const ARRAY < ARRAY<Element>* > & elements_before,
+  //const ARRAY < ARRAY<int>* > & markedelts_num,
+  //		const ARRAY < ARRAY<Element2d>* > & surfelements_before,
+  //		const ARRAY < ARRAY<int>* > & markedsurfelts_num)
+  {
+    T_MTETS mtets_old; mtets_old.Copy(mtets);
+    T_MPRISMS mprisms_old; mprisms_old.Copy(mprisms);
+    T_MIDS mids_old; mids_old.Copy(mids);
+    T_MTRIS mtris_old; mtris_old.Copy(mtris);
+    T_MQUADS mquads_old; mquads_old.Copy(mquads);
+
+
+
+    
+    mtets.SetSize(0);
+    mprisms.SetSize(0);
+    mids.SetSize(0);
+    mtris.SetSize(0);
+    mquads.SetSize(0);
+
+    //int nv = mesh.GetNV();
+
+
+    INDEX_2_CLOSED_HASHTABLE<int> edgenumber(9*mesh.GetNE()+4*mesh.GetNSE());  
+    
+    int maxnum = BTSortEdges (mesh, idmaps, edgenumber);
+
+    for(int m = 0; m < mtets_old.Size(); m++)
+      {
+	MarkedTet & mt = mtets_old[m];
+
+	//(*testout) << "old mt " << mt;
+	
+	INDEX_2 edge (mt.pnums[mt.tetedge1],mt.pnums[mt.tetedge2]);
+	edge.Sort();
+	if(edgenumber.Used(edge))
+	  {
+	    int val = edgenumber.Get(edge);
+	    //(*testout) << "set voledge " << edge << " from " << val;
+	    if(val <= maxnum)
+	      {
+		val += 2*maxnum;
+		edgenumber.Set(edge,val);
+	      }
+	    else if(val <= 2*maxnum)
+	      {
+		val += maxnum;
+		edgenumber.Set(edge,val);
+	      }
+	    //(*testout) << " to " << val << endl;
+	  }
+	
+	for(int k=0; k<4; k++)
+	  for(int i=0; i<3; i++)
+	    for(int j=i+1; i != k && j<4; j++)
+	      if(j != k && mt.faceedges[k] == 6-k-i-j)
+		{
+		  edge[0] = mt.pnums[i];
+		  edge[1] = mt.pnums[j];
+		  edge.Sort();
+		  if(edgenumber.Used(edge))
+		    {
+		      int val = edgenumber.Get(edge);
+		      //(*testout) << "set faceedge " << edge << " from " << val;
+		      if(val <= maxnum)
+			{
+			  val += maxnum;
+			  edgenumber.Set(edge,val);
+			}
+		      //(*testout) << " to " << val << endl;
+		    }		      
+		}
+      }
+
+	
+    
+    
+    for(ElementIndex ei = 0; ei < mesh.GetNE(); ei++)
+      {
+	const Element & el = mesh[ei];
+	
+	//int pos = elements_before[el[0]]->Pos(el);
+	//int elnum = (pos >= 0) ? (*markedelts_num[el[0]])[pos] : -1;
+	 
+	switch (el.GetType())
+	  {
+	  case TET:
+	  case TET10:
+	    {
+	      //if(elnum >= 0)
+	      // {
+	      //   mtets.Append(mtets_old[elnum]);
+	      // } 
+	      //else
+	      // {
+	      MarkedTet mt;
+	      BTDefineMarkedTet (el, edgenumber, mt);
+	      mt.matindex = el.GetIndex();
+	      
+	      mtets.Append (mt);
+	    
+	      //(*testout) << "mtet " << mtets.Last() << endl;
+	      break;
+	    }
+	  case PYRAMID:
+	    {
+	      cerr << "Refinement :: UpdateEdgeMarks not yet implemented for pyramids"
+		   << endl;
+	      break;
+	    }
+	    
+	  case PRISM:
+	  case PRISM12:
+	    {
+	      cerr << "Refinement :: UpdateEdgeMarks not yet implemented for prisms"
+		   << endl;
+	      break;
+	    }
+	  }
+	
+      }
+    
+
+    
+     for(SurfaceElementIndex sei = 0; sei < mesh.GetNSE(); sei++)
+       {
+	 const Element2d & el = mesh[sei];
+
+	 /*
+	 for(int k=0; k<3; k++)
+	   auxind3[k] = el[k];
+
+	 auxind3.Sort();
+	 
+	 int pos = oldfaces[auxind3[0]]->Pos(auxind3);
+	 if(pos < 0)
+	   cout << "UIUIUI" << endl;
+	 */	 
+	 
+	 switch (el.GetType())
+	   {
+	   case TRIG:
+	   case TRIG6:
+	     {
+	       MarkedTri mt;
+	       BTDefineMarkedTri (el, edgenumber, mt);
+	       mtris.Append (mt);
+	       break;
+	     }
+	     
+	   case QUAD:
+	   case QUAD6:
+	     {
+	       MarkedQuad mt;
+	       BTDefineMarkedQuad (el, edgenumber, mt);
+	       mquads.Append (mt);
+	       break;
+	     }
+	   }
+
+	 
+	MarkedIdentification mi;
+	for(int j=0; j<idmaps.Size(); j++)
+	  if(BTDefineMarkedId(el, edgenumber, *idmaps[j], mi))
+	    mids.Append(mi);
+
+
+	 /*
+	 int pos = surfelements_before[el[0]]->Pos(el);
+	 int elnum = (pos >= 0) ? (*markedsurfelts_num[el[0]])[pos] : -1;
+	 
+	 
+	 switch (el.GetType())
+	   {
+	   case TRIG:
+	   case TRIG6:
+	     {
+	       if(elnum >= 0)
+		 mtris.Append(mtris_old[elnum]);
+	       else
+		 {
+		   MarkedTri mt;
+		   BTDefineMarkedTri (el, edgenumber, mt);
+		   mtris.Append (mt);
+		   (*testout) << "(new) ";
+		 }
+	       (*testout) << "mtri " << mtris.Last();
+	       break;
+	     }
+	     
+	   case QUAD:
+	   case QUAD6:
+	     {
+	       if(elnum >= 0)
+		 mquads.Append(mquads_old[elnum]);
+	       else
+		 {
+		   MarkedQuad mt;
+		   BTDefineMarkedQuad (el, edgenumber, mt);
+		   mquads.Append (mt);
+		 }
+	       break;
+	     }
+	   }
+	 */
+       }
+     
+     /*
+     for(int i=0; i<oldfaces.Size(); i++)
+       {
+	 delete oldfaces[i];
+	 delete oldmarkededges[i];
+       }
+     */
+     
+  }
+				      
+
+
+
+  void Refinement :: Bisect (Mesh & mesh, 
+			     BisectionOptions & opt,
+			     ARRAY<double> * quality_loss)
+  {
+    PrintMessage(1,"Mesh bisection");
+    PushStatus("Mesh bisection");
+
+    static int localizetimer = NgProfiler::CreateTimer("localize edgepoints");
+    NgProfiler::RegionTimer * loct = new NgProfiler::RegionTimer(localizetimer);   
+    LocalizeEdgePoints(mesh);
+    delete loct;
+
+    ARRAY< ARRAY<int,PointIndex::BASE>* > idmaps;
+    for(int i=1; i<=mesh.GetIdentifications().GetMaxNr(); i++)
+      {
+	if(mesh.GetIdentifications().GetType(i) == Identifications::PERIODIC)
+	  {
+	    idmaps.Append(new ARRAY<int,PointIndex::BASE>);
+	    mesh.GetIdentifications().GetMap(i,*idmaps.Last(),true);
+	  }
+      }
+
+    
+    string refelementinfofileread = "";
+    string refelementinfofilewrite = "";
+
+    if(opt.refinementfilename)
+      {
+	ifstream inf(opt.refinementfilename);
+	string st;
+	inf >> st;
+	if(st == "refinementinfo")
+	  {
+	    while(inf)
+	      {
+		while(inf && st != "markedelementsfile")
+		  inf >> st;
+		
+		if(inf)
+		  inf >> st;
+		
+		if(st == "read" && inf)
+		  ReadEnclString(inf,refelementinfofileread,'\"');
+		else if(st == "write" && inf)
+		  ReadEnclString(inf,refelementinfofilewrite,'\"');
+	      }
+	  }
+	inf.close();
+      }
+	
+
+
+    if (mesh.mglevels == 1 || idmaps.Size() > 0)
+      BisectTetsCopyMesh(mesh, NULL, opt, idmaps, refelementinfofileread);
+
+
+    mesh.ComputeNVertices();
+  
+    int np = mesh.GetNV();
+    mesh.SetNP(np);
+
+    // int ne = mesh.GetNE();
+    // int nse = mesh.GetNSE();
+    int i, j, l;
+
+    // int initnp = np;
+    //  int maxsteps = 3;
+
+    mesh.mglevels++;
+
+    /*
+      if (opt.refinementfilename || opt.usemarkedelements)
+      maxsteps = 3;
+    */
+
+
+
+    if (opt.refine_p)   
+      {
+	int ne = mesh.GetNE();
+	int nse = mesh.GetNSE();
+	int ox,oy,oz; 
+	for (ElementIndex ei = 0; ei < ne; ei++)
+	  if (mesh[ei].TestRefinementFlag())
+	    {
+	      mesh[ei].GetOrder(ox,oy,oz);
+	      mesh[ei].SetOrder (ox+1,oy+1,oz+1);
+	      if (mesh[ei].TestStrongRefinementFlag())
+		mesh[ei].SetOrder (ox+2,oy+2,oz+2);
+	    }
+	for (SurfaceElementIndex sei = 0; sei < nse; sei++)
+	  if (mesh[sei].TestRefinementFlag())
+	    {
+	      mesh[sei].GetOrder(ox,oy);
+	      mesh[sei].SetOrder(ox+1,oy+1);
+	      if (mesh[sei].TestStrongRefinementFlag())
+		mesh[sei].SetOrder(ox+2,oy+2);
+	    }
+
+	/*
+	  #ifndef SABINE //Nachbarelemente mit ordx,ordy,ordz 
+      
+	  ARRAY<int,PointIndex::BASE> v_order (mesh.GetNP());
+	  v_order = 0;
+
+	  for (ElementIndex ei = 0; ei < ne; ei++)
+	  for (j = 0; j < mesh[ei].GetNP(); j++)
+	  if (mesh[ei].GetOrder() > v_order[mesh[ei][j]])
+	  v_order[mesh[ei][j]] = mesh[ei].GetOrder();
+
+	  for (SurfaceElementIndex sei = 0; sei < nse; sei++)
+	  for (j = 0; j < mesh[sei].GetNP(); j++)
+	  if (mesh[sei].GetOrder() > v_order[mesh[sei][j]])
+	  v_order[mesh[sei][j]] = mesh[sei].GetOrder();
+
+	  for (ElementIndex ei = 0; ei < ne; ei++)
+	  for (j = 0; j < mesh[ei].GetNP(); j++)
+	  if (mesh[ei].GetOrder() < v_order[mesh[ei][j]]-1)
+	  mesh[ei].SetOrder(v_order[mesh[ei][j]]-1);
+
+	  for (SurfaceElementIndex sei = 0; sei < nse; sei++)
+	  for (j = 0; j < mesh[sei].GetNP(); j++)
+	  if (mesh[sei].GetOrder() < v_order[mesh[sei][j]]-1)
+	  mesh[sei].SetOrder(v_order[mesh[sei][j]]-1);
+	    
+	  #endif
+	*/
+
+	PopStatus();
+	return;
+      }
+
+
+
+    // INDEX_2_HASHTABLE<int> cutedges(10 + 5 * (mtets.Size()+mprisms.Size()+mtris.Size()+mquads.Size()));
+    INDEX_2_CLOSED_HASHTABLE<int> cutedges(10 + 9 * (mtets.Size()+mprisms.Size()+mtris.Size()+mquads.Size()));
+
+    bool noprojection = false;
+
+    for (l = 1; l <= 1; l++)
+      {
+	int marked = 0;
+	if (opt.refinementfilename)
+	  {
+	    ifstream inf(opt.refinementfilename);
+	    PrintMessage(3,"load refinementinfo from file ",opt.refinementfilename);
+
+	    string st;
+	    inf >> st;
+	    if(st == "refinementinfo")
+	      // new version
+	      {
+		for(i=1; i<=mtets.Size(); i++)
+		  mtets.Elem(i).marked = 0;
+		for(i=1; i<=mprisms.Size(); i++)
+		  mprisms.Elem(i).marked = 0;
+		for(i=1; i<=mtris.Size(); i++)
+		  mtris.Elem(i).marked = 0;
+		for(i=1; i<=mquads.Size(); i++)
+		  mquads.Elem(i).marked = 0;
+		for(i=1; i<=mprisms.Size(); i++)
+		  mids.Elem(i).marked = 0;
+
+		inf >> st;
+		while(inf)
+		  {
+		    if(st[0] == '#')
+		      {
+			inf.ignore(10000,'\n');
+			inf >> st;
+		      }
+		    else if(st == "markedelementsfile")
+		      {
+			inf >> st;
+			ReadEnclString(inf,st,'\"');
+			inf >> st;
+		      }
+		    else if(st == "noprojection")
+		      {
+			noprojection = true;
+			inf >> st;
+		      }
+		    else if(st == "refine")
+		      {
+			inf >> st;
+			if(st == "elements")
+			  {
+			    inf >> st;
+			    bool isint = true;
+				for(string::size_type ii=0; isint && ii<st.size(); ii++)
+			      isint = (isdigit(st[ii]) != 0);
+			    
+			    while(inf && isint)
+			      {
+				mtets.Elem(atoi(st.c_str())).marked = 3;
+				marked = 1;
+
+				inf >> st;
+				isint = true;
+				for(string::size_type ii=0; isint && ii<st.size(); ii++)
+				  isint = (isdigit(st[ii]) != 0);
+			      }
+			  }
+			else if(st == "orthobrick")
+			  {
+			    double bounds[6];
+			    for(i=0; i<6; i++)
+			      inf >> bounds[i];
+			    
+			    int cnt = 0;
+
+			    for(ElementIndex ei = 0; ei < mesh.GetNE(); ei++)
+			      {
+				const Element & el = mesh[ei];
+				
+				//
+				Point<3> center(0,0,0);
+				for(i=0; i<el.GetNP(); i++)
+				  {
+				    const MeshPoint & point = mesh[el[i]];
+				    center(0) += point(0);
+				    center(1) += point(1);
+				    center(2) += point(2);
+				  }
+				for(i=0; i<3; i++)
+				  center(i) *= 1./double(el.GetNP());
+				if(bounds[0] <= center(0) && center(0) <= bounds[3] &&
+				   bounds[1] <= center(1) && center(1) <= bounds[4] &&
+				   bounds[2] <= center(2) && center(2) <= bounds[5])
+				  {
+				    mtets[ei].marked = 3;
+				    cnt++;
+				  }
+				
+				  
+// 				bool contained = false;
+// 				for(int i=0; !contained && i<el.GetNP(); i++)
+// 				  {
+// 				    const MeshPoint & point = mesh[el[i]];
+// 				    contained = (bounds[0] <= point.X() && point.X() <= bounds[3] &&
+// 						 bounds[1] <= point.Y() && point.Y() <= bounds[4] &&
+// 						 bounds[2] <= point.Z() && point.Z() <= bounds[5]);
+// 				  }
+// 				if(contained)
+// 				  {
+// 				    mtets[ei].marked = 3;
+// 				    cnt++;
+// 				  }
+			      }
+
+
+			    ostringstream strstr;
+			    strstr.precision(2);
+			    strstr << "marked " << float(cnt)/float(mesh.GetNE())*100. 
+#ifdef WIN32
+				   << "%%"
+#else
+				   << "%"
+#endif
+				   <<" of the elements";
+			    PrintMessage(4,strstr.str());
+
+			    if(cnt > 0)
+			      marked = 1;
+
+
+			    inf >> st;
+			  }
+			else
+			  {
+			    throw NgException("something wrong with refinementinfo file");
+			  }
+		      }
+		  }		
+	      }
+	    else
+	      {
+		inf.close();
+		inf.open(opt.refinementfilename);
+
+		char ch;
+		for (i = 1; i <= mtets.Size(); i++)
+		  {
+		    inf >> ch;
+		    if(!inf)
+		      throw NgException("something wrong with refinementinfo file (old format)");
+		    mtets.Elem(i).marked = (ch == '1');
+		  }
+		marked = 1;
+	      }
+	    inf.close();
+	  }
+
+	else if (opt.usemarkedelements)
+	  {
+	    int cntm = 0;
+
+	    // all in one !
+	    if (mprisms.Size())
+	      {
+		int cnttet = 0;
+		int cntprism = 0;
+		for (i = 1; i <= mesh.GetNE(); i++)
+		  {
+		    if (mesh.VolumeElement(i).GetType() == TET ||
+			mesh.VolumeElement(i).GetType() == TET10)
+		      {
+			cnttet++;
+			mtets.Elem(cnttet).marked =
+			  3 * mesh.VolumeElement(i).TestRefinementFlag();
+			if (mtets.Elem(cnttet).marked)
+			  cntm++;
+		      }
+		    else
+		      {
+			cntprism++;
+			mprisms.Elem(cntprism).marked =
+			  2 * mesh.VolumeElement(i).TestRefinementFlag();
+			if (mprisms.Elem(cntprism).marked)
+			  cntm++;
+		      }
+
+		  }
+	      }
+	    else
+	      for (i = 1; i <= mtets.Size(); i++)
+		{
+		  mtets.Elem(i).marked =
+		    3 * mesh.VolumeElement(i).TestRefinementFlag();
+		  if (mtets.Elem(i).marked)
+		    cntm++;
+		}
+
+	    // (*testout) << "mtets = " << mtets << endl;
+
+	    /*
+	      for (i = 1; i <= mtris.Size(); i++)
+	      mtris.Elem(i).marked = 0;
+	      for (i = 1; i <= mquads.Size(); i++)
+	      mquads.Elem(i).marked = 0;
+	    */
+
+	    if (printmessage_importance>0)
+	      {
+		ostringstream str;
+		str << "marked elements: " << cntm;
+		PrintMessage(4,str.str());
+	      }
+
+	    int cnttrig = 0;
+	    int cntquad = 0;
+	    for (i = 1; i <= mesh.GetNSE(); i++)
+	      {
+		if (mesh.SurfaceElement(i).GetType() == TRIG ||
+		    mesh.SurfaceElement(i).GetType() == TRIG6)
+		  {
+		    cnttrig++;
+		    mtris.Elem(cnttrig).marked =
+		      mesh.SurfaceElement(i).TestRefinementFlag() ? 2 : 0;
+		    // mtris.Elem(cnttrig).marked = 0;
+		    if (mtris.Elem(cnttrig).marked)
+		      cntm++;
+		  }
+		else
+		  {
+		    cntquad++;
+                    // 2d: marked=2, 3d prisms: marked=1
+		    mquads.Elem(cntquad).marked =
+                        mesh.SurfaceElement(i).TestRefinementFlag() ? 4-mesh.GetDimension() : 0 ;
+		    // mquads.Elem(cntquad).marked = 0;
+		    if (mquads.Elem(cntquad).marked)
+		      cntm++;
+		  }
+	      }
+
+              if (printmessage_importance>0)
+		{
+		  ostringstream str;
+		  str << "with surface-elements: " << cntm;
+		  PrintMessage(4,str.str());
+		}
+
+            // he/sz: das wird oben schon richtig gemacht.
+            // hier sind die quads vergessen!
+            /*
+	    if (mesh.GetDimension() == 2)
+	      {
+		cntm = 0;
+		for (i = 1; i <= mtris.Size(); i++)
+		  {
+		    mtris.Elem(i).marked =
+		      2 * mesh.SurfaceElement(i).TestRefinementFlag();
+		    //		  mtris.Elem(i).marked = 2;
+		    if (mtris.Elem(i).marked)
+		      cntm++;
+		  }
+
+		if (!cntm)
+		  {
+		    for (i = 1; i <= mtris.Size(); i++)
+		      {
+			mtris.Elem(i).marked = 2;
+			cntm++;
+		      }
+		  }
+		cout << "trigs: " << mtris.Size() << " ";
+		cout << "marked: " << cntm << endl;
+	      }
+            */ 
+            
+	    marked = (cntm > 0);
+	  }
+	else
+	  {
+	    marked = BTMarkTets (mtets, mprisms, mesh);
+	  }
+
+	if (!marked) break;
+        
+
+	//(*testout) << "mtets " << mtets << endl;
+
+	if (opt.refine_p)
+	  {
+	    PrintMessage(3,"refine p");
+
+	    for (i = 1; i <= mtets.Size(); i++)
+	      mtets.Elem(i).incorder = mtets.Elem(i).marked ? 1 : 0;
+
+	    for (i = 1; i <= mtets.Size(); i++)
+	      if (mtets.Elem(i).incorder)
+		mtets.Elem(i).marked = 0;
+
+
+	    for (i = 1; i <= mprisms.Size(); i++)
+	      mprisms.Elem(i).incorder = mprisms.Elem(i).marked ? 1 : 0;
+
+	    for (i = 1; i <= mprisms.Size(); i++)
+	      if (mprisms.Elem(i).incorder)
+		mprisms.Elem(i).marked = 0;
+
+
+	    for (i = 1; i <= mtris.Size(); i++)
+	      mtris.Elem(i).incorder = mtris.Elem(i).marked ? 1 : 0;
+
+	    for (i = 1; i <= mtris.Size(); i++)
+	      {
+		if (mtris.Elem(i).incorder)
+		  mtris.Elem(i).marked = 0;
+	      }
+	  }
+
+	if (opt.refine_hp)
+	  {
+	    PrintMessage(3,"refine hp");
+	    BitArray singv(np);
+	    singv.Clear();
+
+	    if (mesh.GetDimension() == 3)
+	      {
+		for (i = 1; i <= mesh.GetNSeg(); i++)
+		  {
+		    const Segment & seg = mesh.LineSegment(i);
+		    singv.Set (seg.p1);
+		    singv.Set (seg.p2);
+		  }
+		/*
+		  for ( i=1; i<= mesh.GetNSE(); i++)
+		  {
+		  const Element2d & sel = mesh.SurfaceElement(i);
+		  for(int j=1; j<=sel.GetNP(); j++)
+		  singv.Set(sel.PNum(j));
+		  }
+		*/
+	      }
+	    else
+	      {
+		// vertices with 2 different bnds
+		ARRAY<int> bndind(np);
+		bndind = 0;
+		for (i = 1; i <= mesh.GetNSeg(); i++)
+		  {
+		    const Segment & seg = mesh.LineSegment(i);
+		    for (j = 0; j < 2; j++)
+		      {
+			int pi = (j == 0) ? seg.p1 : seg.p2;
+			if (bndind.Elem(pi) == 0)
+			  bndind.Elem(pi) = seg.edgenr;
+			else if (bndind.Elem(pi) != seg.edgenr)
+			  singv.Set (pi);
+		      }
+		  }
+	      }
+
+
+
+	    for (i = 1; i <= mtets.Size(); i++)
+	      mtets.Elem(i).incorder = 1;
+	    for (i = 1; i <= mtets.Size(); i++)
+	      {
+		if (!mtets.Elem(i).marked)
+		  mtets.Elem(i).incorder = 0;
+		for (j = 0; j < 4; j++)
+		  if (singv.Test (mtets.Elem(i).pnums[j]))
+		    mtets.Elem(i).incorder = 0;
+	      }
+	    for (i = 1; i <= mtets.Size(); i++)
+	      if (mtets.Elem(i).incorder)
+		mtets.Elem(i).marked = 0;
+
+
+	    for (i = 1; i <= mprisms.Size(); i++)
+	      mprisms.Elem(i).incorder = 1;
+	    for (i = 1; i <= mprisms.Size(); i++)
+	      {
+		if (!mprisms.Elem(i).marked)
+		  mprisms.Elem(i).incorder = 0;
+		for (j = 0; j < 6; j++)
+		  if (singv.Test (mprisms.Elem(i).pnums[j]))
+		    mprisms.Elem(i).incorder = 0;
+	      }
+	    for (i = 1; i <= mprisms.Size(); i++)
+	      if (mprisms.Elem(i).incorder)
+		mprisms.Elem(i).marked = 0;
+
+
+	    for (i = 1; i <= mtris.Size(); i++)
+	      mtris.Elem(i).incorder = 1;
+	    for (i = 1; i <= mtris.Size(); i++)
+	      {
+		if (!mtris.Elem(i).marked)
+		  mtris.Elem(i).incorder = 0;
+		for (j = 0; j < 3; j++)
+		  if (singv.Test (mtris.Elem(i).pnums[j]))
+		    mtris.Elem(i).incorder = 0;
+	      }
+	    for (i = 1; i <= mtris.Size(); i++)
+	      {
+		if (mtris.Elem(i).incorder)
+		  mtris.Elem(i).marked = 0;
+	      }
+	  }
+
+
+
+
+
+	int hangingvol, hangingsurf, hangingedge;
+
+	//cout << "write?" << endl;
+	//string yn;
+	//cin >> yn;
+
+	(*testout) << "refine volume elements" << endl;
+	do
+	  {
+	    // refine volume elements
+
+	    int nel = mtets.Size();
+	    for (i = 1; i <= nel; i++)
+	      if (mtets.Elem(i).marked)
+		{
+		  MarkedTet oldtet;
+		  MarkedTet newtet1, newtet2;
+		  int newp;
+
+
+		  oldtet = mtets.Get(i);
+		  //if(yn == "y")
+		  //  (*testout) << "bisected tet " << oldtet;
+		  INDEX_2 edge(oldtet.pnums[oldtet.tetedge1],
+			       oldtet.pnums[oldtet.tetedge2]);
+		  edge.Sort();
+		  if (cutedges.Used (edge))
+		    {
+		      newp = cutedges.Get(edge);
+		    }
+		  else
+		    {
+		      Point<3> npt = Center (mesh.Point (edge.I1()),
+					   mesh.Point (edge.I2()));
+		      newp = mesh.AddPoint (npt);
+		      cutedges.Set (edge, newp);
+		    }
+
+		  BTBisectTet (oldtet, newp, newtet1, newtet2);
+
+		  mtets.Elem(i) = newtet1;
+		  mtets.Append (newtet2);
+		  //if(yn == "y")
+		  //  (*testout) << "and got " << newtet1 << "and " << newtet2 << endl;
+
+		  mesh.mlparentelement.Append (i);
+		}
+
+	    int npr = mprisms.Size();
+	    for (i = 1; i <= npr; i++)
+	      if (mprisms.Elem(i).marked)
+		{
+		  MarkedPrism oldprism;
+		  MarkedPrism newprism1, newprism2;
+		  int newp1, newp2;
+
+		  oldprism = mprisms.Get(i);
+		  int pi1 = 0;
+		  if (pi1 == oldprism.markededge)
+		    pi1++;
+		  int pi2 = 3-pi1-oldprism.markededge;
+
+		  INDEX_2 edge1(oldprism.pnums[pi1],
+				oldprism.pnums[pi2]);
+		  INDEX_2 edge2(oldprism.pnums[pi1+3],
+				oldprism.pnums[pi2+3]);
+		  edge1.Sort();
+		  edge2.Sort();
+
+		  if (cutedges.Used (edge1))
+		    newp1 = cutedges.Get(edge1);
+		  else
+		    {
+		      Point<3> npt = Center (mesh.Point (edge1.I1()),
+					    mesh.Point (edge1.I2()));
+		      newp1 = mesh.AddPoint (npt);
+		      cutedges.Set (edge1, newp1);
+		    }
+		  if (cutedges.Used (edge2))
+		    newp2 = cutedges.Get(edge2);
+		  else
+		    {
+		      Point<3> npt = Center (mesh.Point (edge2.I1()),
+					    mesh.Point (edge2.I2()));
+		      newp2 = mesh.AddPoint (npt);
+		      cutedges.Set (edge2, newp2);
+		    }
+		
+
+		  BTBisectPrism (oldprism, newp1, newp2, newprism1, newprism2);
+		  //if(yn == "y")
+		  //  (*testout) << "bisected prism " << oldprism << "and got " << newprism1 << "and " << newprism2 << endl;
+		  mprisms.Elem(i) = newprism1;
+		  mprisms.Append (newprism2);
+		}
+
+	    int nid = mids.Size();
+	    for (i = 1; i <= nid; i++)
+	      if (mids.Elem(i).marked)
+		{
+		  MarkedIdentification oldid,newid1,newid2;
+		  ARRAY<int> newp;
+
+		  oldid = mids.Get(i);
+		  
+		  ARRAY<INDEX_2> edges;
+		  edges.Append(INDEX_2(oldid.pnums[oldid.markededge],
+				       oldid.pnums[(oldid.markededge+1)%oldid.np]));
+		  edges.Append(INDEX_2(oldid.pnums[oldid.markededge + oldid.np],
+				       oldid.pnums[(oldid.markededge+1)%oldid.np + oldid.np]));
+
+		  if(oldid.np == 4)
+		    {
+		      edges.Append(INDEX_2(oldid.pnums[(oldid.markededge+2)%oldid.np],
+					   oldid.pnums[(oldid.markededge+3)%oldid.np]));
+		      edges.Append(INDEX_2(oldid.pnums[(oldid.markededge+2)%oldid.np + oldid.np],
+					   oldid.pnums[(oldid.markededge+3)%oldid.np + oldid.np]));
+		    }
+		  for (j = 0; j < edges.Size(); j++)
+		    {
+		      edges[j].Sort();
+
+		      if(cutedges.Used(edges[j]))
+			newp.Append(cutedges.Get(edges[j]));
+		      else
+			{
+			  Point<3> npt = Center (mesh.Point (edges[j].I1()),
+						mesh.Point (edges[j].I2()));
+			  newp.Append(mesh.AddPoint(npt));
+			  cutedges.Set(edges[j],newp[j]);
+			}			 
+		    }
+		  
+		  BTBisectIdentification(oldid,newp,newid1,newid2);
+		  mids.Elem(i) = newid1;
+		  mids.Append(newid2);		  
+		}
+
+	    
+	    //IdentifyCutEdges(mesh, cutedges);
+
+
+	    hangingvol = 
+	      MarkHangingTets (mtets, cutedges) +
+	      MarkHangingPrisms (mprisms, cutedges) +
+	      MarkHangingIdentifications (mids, cutedges);
+
+
+	    int nsel = mtris.Size();
+
+	    for (i = 1; i <= nsel; i++)
+	      if (mtris.Elem(i).marked)
+		{
+		  MarkedTri oldtri;
+		  MarkedTri newtri1, newtri2;
+		  PointIndex newp;
+		
+		  oldtri = mtris.Get(i);
+		  int oldpi1 = oldtri.pnums[(oldtri.markededge+1)%3];
+		  int oldpi2 = oldtri.pnums[(oldtri.markededge+2)%3];
+		  INDEX_2 edge(oldpi1, oldpi2);
+		  edge.Sort();
+
+		  //		cerr << "edge = " << edge.I1() << "-" << edge.I2() << endl;
+
+		  if (cutedges.Used (edge))
+		    {
+		      newp = cutedges.Get(edge);
+		    }
+		  else
+		    {
+		      Point<3> npt = Center (mesh.Point (edge.I1()),
+					    mesh.Point (edge.I2()));
+		      newp = mesh.AddPoint (npt);
+                      cutedges.Set (edge, newp);
+		    }
+		  //		newp = cutedges.Get(edge);
+		
+		  int si = mesh.GetFaceDescriptor (oldtri.surfid).SurfNr();
+		  //  geom->GetSurface(si)->Project (mesh.Point(newp));
+		  PointGeomInfo npgi;
+		
+//                   cerr << "project point " << newp << " old: " << mesh.Point(newp);
+                  if (mesh[newp].Type() != EDGEPOINT)
+                    PointBetween (mesh.Point (oldpi1), mesh.Point (oldpi2),
+                                  0.5, si,
+                                  oldtri.pgeominfo[(oldtri.markededge+1)%3],
+                                  oldtri.pgeominfo[(oldtri.markededge+2)%3],
+                                  mesh.Point (newp), npgi);
+//                   cerr << " new: " << mesh.Point(newp) << endl;
+		
+		  BTBisectTri (oldtri, newp, npgi, newtri1, newtri2);
+		  //if(yn == "y")
+		  //  (*testout) << "bisected tri " << oldtri << "and got " << newtri1 << "and " << newtri2 << endl;
+		
+		
+		  mtris.Elem(i) = newtri1;
+		  mtris.Append (newtri2);
+		  mesh.mlparentsurfaceelement.Append (i);
+		}
+	  
+	    int nquad = mquads.Size();
+	    for (i = 1; i <= nquad; i++)
+	      if (mquads.Elem(i).marked)
+		{
+		  MarkedQuad oldquad;
+		  MarkedQuad newquad1, newquad2;
+		  int newp1, newp2;
+		
+		  oldquad = mquads.Get(i);
+                  /*
+		  INDEX_2 edge1(oldquad.pnums[0],
+				oldquad.pnums[1]);
+		  INDEX_2 edge2(oldquad.pnums[2],
+				oldquad.pnums[3]);
+                  */
+                  INDEX_2 edge1, edge2;
+                  PointGeomInfo pgi11, pgi12, pgi21, pgi22;
+                  if (oldquad.markededge==0 || oldquad.markededge==2)
+                  {
+                    edge1.I1()=oldquad.pnums[0]; pgi11=oldquad.pgeominfo[0];
+                    edge1.I2()=oldquad.pnums[1]; pgi12=oldquad.pgeominfo[1];
+                    edge2.I1()=oldquad.pnums[2]; pgi21=oldquad.pgeominfo[2];
+                    edge2.I2()=oldquad.pnums[3]; pgi22=oldquad.pgeominfo[3];
+                  }
+                  else // 3 || 1
+                  {
+                    edge1.I1()=oldquad.pnums[0]; pgi11=oldquad.pgeominfo[0];
+                    edge1.I2()=oldquad.pnums[2]; pgi12=oldquad.pgeominfo[2];
+                    edge2.I1()=oldquad.pnums[1]; pgi21=oldquad.pgeominfo[1];
+                    edge2.I2()=oldquad.pnums[3]; pgi22=oldquad.pgeominfo[3];
+                  }
+                  
+                  edge1.Sort();
+		  edge2.Sort();
+
+		  if (cutedges.Used (edge1))
+		    {
+		      newp1 = cutedges.Get(edge1);
+		    }
+		  else
+		    {
+		      Point<3> np1 = Center (mesh.Point (edge1.I1()),
+					   mesh.Point (edge1.I2()));
+		      newp1 = mesh.AddPoint (np1);
+		      cutedges.Set (edge1, newp1);
+                    }
+
+		  if (cutedges.Used (edge2))
+		    {
+		      newp2 = cutedges.Get(edge2);
+		    }
+		  else
+		    {
+		      Point<3> np2 = Center (mesh.Point (edge2.I1()),
+					   mesh.Point (edge2.I2()));
+		      newp2 = mesh.AddPoint (np2);
+		      cutedges.Set (edge2, newp2);
+                    }
+
+		  PointGeomInfo npgi1, npgi2;
+		
+		  int si = mesh.GetFaceDescriptor (oldquad.surfid).SurfNr();
+		  //		geom->GetSurface(si)->Project (mesh.Point(newp1));
+		  //		geom->GetSurface(si)->Project (mesh.Point(newp2));
+
+//                   (*testout)
+//                   cerr << "project point 1 " << newp1 << " old: " << mesh.Point(newp1);
+                  PointBetween (mesh.Point (edge1.I1()), mesh.Point (edge1.I2()),
+				0.5, si,
+				pgi11,
+				pgi12,
+				mesh.Point (newp1), npgi1);
+// 		  (*testout)
+//                   cerr << " new: " << mesh.Point(newp1) << endl;
+
+		
+//                   cerr << "project point 2 " << newp2 << " old: " << mesh.Point(newp2);
+                  PointBetween (mesh.Point (edge2.I1()), mesh.Point (edge2.I2()),
+				0.5, si,
+				pgi21,
+				pgi22,
+				mesh.Point (newp2), npgi2);
+//                   cerr << " new: " << mesh.Point(newp2) << endl;
+		
+
+		  BTBisectQuad (oldquad, newp1, npgi1, newp2, npgi2,
+				newquad1, newquad2);
+                  
+		  mquads.Elem(i) = newquad1;
+		  mquads.Append (newquad2);
+		}
+	  
+
+	    hangingsurf = 
+	      MarkHangingTris (mtris, cutedges) +
+	      MarkHangingQuads (mquads, cutedges);
+
+	    hangingedge = 0;
+	  
+	    int nseg = mesh.GetNSeg ();
+	    for (i = 1; i <= nseg; i++)
+	      {
+		Segment & seg = mesh.LineSegment (i);
+		INDEX_2 edge(seg.p1, seg.p2);
+		edge.Sort();
+		if (cutedges.Used (edge))
+		  {
+		    hangingedge = 1;
+		    Segment nseg1 = seg;
+		    Segment nseg2 = seg;
+		  
+		    int newpi = cutedges.Get(edge);
+		  
+		    nseg1.p2 = newpi;
+		    nseg2.p1 = newpi;
+		  
+		    EdgePointGeomInfo newepgi;
+		  
+ 
+//                     
+//                     cerr << "move edgepoint " << newpi << " from " << mesh.Point(newpi);
+		    PointBetween (mesh.Point (seg.p1), mesh.Point (seg.p2),
+				  0.5, seg.surfnr1, seg.surfnr2, 
+				  seg.epgeominfo[0], seg.epgeominfo[1],
+				  mesh.Point (newpi), newepgi);
+// 		    cerr << " to " << mesh.Point (newpi) << endl;
+
+		    
+		    nseg1.epgeominfo[1] = newepgi;
+		    nseg2.epgeominfo[0] = newepgi;
+		  
+		    mesh.LineSegment (i) = nseg1;
+		    mesh.AddSegment (nseg2);
+		  }
+	      }
+	  }
+	while (hangingvol || hangingsurf || hangingedge);
+        
+        if (printmessage_importance>0)
+	  {
+	    ostringstream strstr;
+	    strstr << mtets.Size() << " tets" << endl
+		   << mtris.Size() << " trigs" << endl;
+	    if (mprisms.Size())
+	      {
+		strstr << mprisms.Size() << " prisms" << endl
+		       << mquads.Size() << " quads" << endl;
+	      }
+	    strstr << mesh.GetNP() << " points";
+	    PrintMessage(4,strstr.str());
+	    
+	  }
+      }
+
+
+    // (*testout) << "mtets = " << mtets << endl;
+
+    if (opt.refine_hp)
+      {
+	//
+	ARRAY<int> v_order (mesh.GetNP());
+	v_order = 0;
+	if (mesh.GetDimension() == 3)
+	  {
+	    for (i = 1; i <= mtets.Size(); i++)
+	      if (mtets.Elem(i).incorder)
+		mtets.Elem(i).order++;
+      
+	    for (i = 0; i < mtets.Size(); i++)
+	      for (j = 0; j < 4; j++)
+		if (int(mtets[i].order) > v_order.Elem(mtets[i].pnums[j]))
+		  v_order.Elem(mtets[i].pnums[j]) = mtets[i].order;
+	    for (i = 0; i < mtets.Size(); i++)
+	      for (j = 0; j < 4; j++)
+		if (int(mtets[i].order) < v_order.Elem(mtets[i].pnums[j])-1)
+		  mtets[i].order = v_order.Elem(mtets[i].pnums[j])-1;
+	  }
+	else
+	  {
+	    for (i = 1; i <= mtris.Size(); i++)
+	      if (mtris.Elem(i).incorder)
+		{
+		  mtris.Elem(i).order++;
+		}
+
+	    for (i = 0; i < mtris.Size(); i++)
+	      for (j = 0; j < 3; j++)
+		if (int(mtris[i].order) > v_order.Elem(mtris[i].pnums[j]))
+		  v_order.Elem(mtris[i].pnums[j]) = mtris[i].order;
+	    for (i = 0; i < mtris.Size(); i++)
+	      {
+		for (j = 0; j < 3; j++)
+		  if (int(mtris[i].order) < v_order.Elem(mtris[i].pnums[j])-1)
+		    mtris[i].order = v_order.Elem(mtris[i].pnums[j])-1;
+	      }
+	  }
+      }
+  
+    mtets.SetAllocSize (mtets.Size());
+    mprisms.SetAllocSize (mprisms.Size());
+    mids.SetAllocSize (mids.Size());
+    mtris.SetAllocSize (mtris.Size());
+    mquads.SetAllocSize (mquads.Size());
+  
+  
+    mesh.ClearVolumeElements();
+    mesh.VolumeElements().SetAllocSize (mtets.Size()+mprisms.Size());
+    for (i = 1; i <= mtets.Size(); i++)
+      {
+	Element el(TET);
+	el.SetIndex (mtets.Get(i).matindex);
+	for (j = 1; j <= 4; j++)
+	  el.PNum(j) = mtets.Get(i).pnums[j-1];
+	el.SetOrder (mtets.Get(i).order);
+	mesh.AddVolumeElement (el);
+      }
+    for (i = 1; i <= mprisms.Size(); i++)
+      {
+	Element el(PRISM);
+	el.SetIndex (mprisms.Get(i).matindex);
+	for (j = 1; j <= 6; j++)
+	  el.PNum(j) = mprisms.Get(i).pnums[j-1];
+	el.SetOrder (mprisms.Get(i).order);
+
+	// degenerated prism ?
+	static const int map1[] = { 3, 2, 5, 6, 1 };
+	static const int map2[] = { 1, 3, 6, 4, 2 };
+	static const int map3[] = { 2, 1, 4, 5, 3 };
+      
+
+	const int * map = NULL;
+	int deg1 = 0, deg2 = 0, deg3 = 0;
+	// int deg = 0;
+	if (el.PNum(1) == el.PNum(4)) { map = map1; deg1 = 1; }
+	if (el.PNum(2) == el.PNum(5)) { map = map2; deg2 = 1; }
+	if (el.PNum(3) == el.PNum(6)) { map = map3; deg3 = 1; }
+	  
+	switch (deg1+deg2+deg3)
+	  {
+	  case 1:
+	    {
+	      for (j = 1; j <= 5; j++)
+		el.PNum(j) = mprisms.Get(i).pnums[map[j-1]-1];
+	    
+	      el.SetType (PYRAMID);
+	      break;
+	    }
+	  case 2:
+	    {
+	      static const int tetmap1[] = { 1, 2, 3, 4 };
+	      static const int tetmap2[] = { 2, 3, 1, 5 };
+	      static const int tetmap3[] = { 3, 1, 2, 6 };
+	      if (!deg1) map = tetmap1;
+	      if (!deg2) map = tetmap2;
+	      if (!deg3) map = tetmap3; 
+	      for (j = 1; j <= 4; j++)
+		el.PNum(j) = mprisms.Get(i).pnums[map[j-1]-1];
+	      /*
+		if (!deg1) el.PNum(4) = el.PNum(4);
+		if (!deg2) el.PNum(4) = el.PNum(5);
+		if (!deg3) el.PNum(4) = el.PNum(6);
+	      */
+	      el.SetType(TET);
+	      break;
+	    }
+	  default:
+	    ;
+	  }
+	mesh.AddVolumeElement (el);
+      }
+  
+    mesh.ClearSurfaceElements();
+    for (i = 1; i <= mtris.Size(); i++)
+      {
+	Element2d el(TRIG);
+	el.SetIndex (mtris.Get(i).surfid);
+	el.SetOrder (mtris.Get(i).order);
+	for (j = 1; j <= 3; j++)
+	  {
+	    el.PNum(j) = mtris.Get(i).pnums[j-1];
+	    el.GeomInfoPi(j) = mtris.Get(i).pgeominfo[j-1];
+	  }
+	mesh.AddSurfaceElement (el);
+      }
+    for (i = 1; i <= mquads.Size(); i++)
+      {
+	Element2d el(QUAD);
+	el.SetIndex (mquads.Get(i).surfid);
+	for (j = 1; j <= 4; j++)
+	  el.PNum(j) = mquads.Get(i).pnums[j-1];
+	Swap (el.PNum(3), el.PNum(4));
+	mesh.AddSurfaceElement (el);
+      }
+
+
+      
+    // write multilevel hierarchy to mesh:
+    np = mesh.GetNP();
+    mesh.mlbetweennodes.SetSize(np);
+    if (mesh.mglevels <= 2)
+      {
+	PrintMessage(4,"RESETTING mlbetweennodes");
+	for (i = 1; i <= np; i++)
+	  {
+	    mesh.mlbetweennodes.Elem(i).I1() = 0;
+	    mesh.mlbetweennodes.Elem(i).I2() = 0;
+	  }
+      }
+
+    /*
+      for (i = 1; i <= cutedges.GetNBags(); i++)
+      for (j = 1; j <= cutedges.GetBagSize(i); j++)
+      {
+      INDEX_2 edge;
+      int newpi;
+      cutedges.GetData (i, j, edge, newpi);
+      mesh.mlbetweennodes.Elem(newpi) = edge;
+      }
+    */
+
+    BitArray isnewpoint(np);
+    isnewpoint.Clear();
+
+    for (i = 1; i <= cutedges.Size(); i++)
+      if (cutedges.UsedPos(i))
+	{
+	  INDEX_2 edge;
+	  int newpi;
+	  cutedges.GetData (i, edge, newpi);
+	  isnewpoint.Set(newpi);
+	  mesh.mlbetweennodes.Elem(newpi) = edge;
+	}
+
+
+    /*
+      mesh.PrintMemInfo (cout);
+      cout << "tets ";
+      mtets.PrintMemInfo (cout);
+      cout << "prims ";
+      mprisms.PrintMemInfo (cout);
+      cout << "tris ";
+      mtris.PrintMemInfo (cout);
+      cout << "quads ";
+      mquads.PrintMemInfo (cout);
+      cout << "cutedges ";
+      cutedges.PrintMemInfo (cout);
+    */
+
+
+    /*
+
+    // find connected nodes (close nodes)
+    TABLE<int> conto(np);
+    for (i = 1; i <= mprisms.Size(); i++)
+    for (j = 1; j <= 6; j++)
+    {
+    int n1 = mprisms.Get(i).pnums[j-1];
+    int n2 = mprisms.Get(i).pnums[(j+2)%6];
+    //	    if (n1 != n2)
+    {
+    int found = 0;
+    for (k = 1; k <= conto.EntrySize(n1); k++)
+    if (conto.Get(n1, k) == n2)
+    {
+    found = 1;
+    break;
+    }
+    if (!found)
+    conto.Add (n1, n2);
+    }
+    }
+    mesh.connectedtonode.SetSize(np);
+    for (i = 1; i <= np; i++)
+    mesh.connectedtonode.Elem(i) = 0;
+  
+
+    //       (*testout) << "connection table: " << endl;
+    //       for (i = 1; i <= np; i++)
+    //       {
+    //       (*testout) << "node " << i << ": ";
+    // 	  for (j = 1; j <= conto.EntrySize(i); j++)
+    // 	  (*testout) << conto.Get(i, j) << " ";
+    // 	  (*testout) << endl;
+    // 	}
+
+  
+    for (i = 1; i <= np; i++)
+    if (mesh.connectedtonode.Elem(i) == 0)
+    {
+    mesh.connectedtonode.Elem(i) = i;
+    ConnectToNodeRec (i, i, conto, mesh.connectedtonode);
+    }
+    */  
+
+    //  mesh.BuildConnectedNodes();
+
+    
+
+
+    mesh.ComputeNVertices();
+
+  
+    
+    // update identification tables
+    for (i = 1; i <= mesh.GetIdentifications().GetMaxNr(); i++)
+      {
+	ARRAY<int,PointIndex::BASE> identmap;
+
+	mesh.GetIdentifications().GetMap (i, identmap);
+
+
+	/*
+	  for (j = 1; j <= cutedges.GetNBags(); j++)
+	  for (k = 1; k <= cutedges.GetBagSize(j); k++)
+	  {
+	  INDEX_2 i2;
+	  int newpi;
+	  cutedges.GetData (j, k, i2, newpi);
+	  INDEX_2 oi2(identmap.Get(i2.I1()),
+	  identmap.Get(i2.I2()));
+	  oi2.Sort();
+	  if (cutedges.Used (oi2))
+	  {
+	  int onewpi = cutedges.Get(oi2);
+	  mesh.GetIdentifications().Add (newpi, onewpi, i);
+	  }
+	  }
+	*/
+
+	for (j = 1; j <= cutedges.Size(); j++)
+	  if (cutedges.UsedPos(j))
+	    {
+	      INDEX_2 i2;
+	      int newpi;
+	      cutedges.GetData (j, i2, newpi);
+	      INDEX_2 oi2(identmap.Get(i2.I1()),
+			  identmap.Get(i2.I2()));
+	      oi2.Sort();
+	      if (cutedges.Used (oi2))
+		{
+		  int onewpi = cutedges.Get(oi2);
+		  mesh.GetIdentifications().Add (newpi, onewpi, i);
+		}
+	    }
+      }
+
+    
+
+
+    
+    bool do_repair = true;
+
+    //if(mesh.mglevels == 3)
+    //  noprojection = true;
+
+    //noprojection = true;
+
+    if(noprojection)
+      {
+	do_repair = false;
+	for(int ii=1; ii<=mesh.GetNP(); ii++)
+	  {
+	    if(isnewpoint.Test(ii) && mesh.mlbetweennodes[ii][0] > 0)
+	      {
+		mesh.Point(ii) = Center(mesh.Point(mesh.mlbetweennodes[ii][0]),mesh.Point(mesh.mlbetweennodes[ii][1]));
+	      }
+	  }
+      }
+
+
+    // Check/Repair
+
+	//cout << "Hallo Welt" << endl;
+	//getchar();
+
+    static bool repaired_once;
+    if(mesh.mglevels == 1)
+      repaired_once = false;
+
+    //mesh.Save("before.vol");
+
+    static int reptimer = NgProfiler::CreateTimer("check/repair");
+	NgProfiler::RegionTimer * regt(NULL);
+    regt = new NgProfiler::RegionTimer(reptimer); 
+
+    ARRAY<ElementIndex> bad_elts;
+    ARRAY<double> pure_badness;
+   
+    if(do_repair || quality_loss != NULL)
+      {
+	pure_badness.SetSize(mesh.GetNP()+2);
+	GetPureBadness(mesh,pure_badness,isnewpoint);
+      }
+
+
+    if(do_repair)
+      {
+	const double max_worsening = 1;
+	
+	const bool uselocalworsening = false;
+	
+	bool repaired = false;
+	
+	Validate(mesh,bad_elts,pure_badness,max_worsening,uselocalworsening);
+	
+        if (printmessage_importance>0)
+	  {
+	    ostringstream strstr;
+	    for(int ii=0; ii<bad_elts.Size(); ii++)
+	      strstr << "bad element " << bad_elts[ii] << "\n";
+	    PrintMessage(1,strstr.str());
+	  }
+	if(repaired_once || bad_elts.Size() > 0)
+	  {
+	    clock_t t1(clock());
+	    
+	    
+	    // update id-maps
+	    j=0;
+	    for(i=1; i<=mesh.GetIdentifications().GetMaxNr(); i++)
+	      {
+		if(mesh.GetIdentifications().GetType(i) == Identifications::PERIODIC)
+		  {
+		    mesh.GetIdentifications().GetMap(i,*idmaps[j],true);
+		    j++;
+		  }
+	      }
+
+    
+	    // do the repair
+	    try
+	      {
+		RepairBisection(mesh,bad_elts,isnewpoint,*this,
+				pure_badness,
+				max_worsening,uselocalworsening,
+				idmaps);
+		repaired = true;
+		repaired_once = true;
+	      }
+	    catch(NgException & ex)
+	      {
+		PrintMessage(1,string("Problem: ") + ex.What());
+	      }
+
+
+            if (printmessage_importance>0)
+            {
+	      ostringstream strstr;
+              strstr << "Time for Repair: " << double(clock() - t1)/double(CLOCKS_PER_SEC) << endl
+		     << "bad elements after repair: " << bad_elts << endl;
+	      PrintMessage(1,strstr.str());
+            }
+	    
+	    if(quality_loss != NULL)
+	      Validate(mesh,bad_elts,pure_badness,1e100,uselocalworsening,quality_loss);
+
+	    if(idmaps.Size() == 0)
+	      UpdateEdgeMarks(mesh,idmaps);
+	    
+	    /*
+	    if(1==1)
+	      UpdateEdgeMarks(mesh,idmaps);
+	    else
+	      mesh.mglevels = 1;
+	    */
+	    
+	    //mesh.ImproveMesh();
+	    
+	  }
+      }
+    delete regt;
+
+
+    
+    
+
+
+
+    for(i=0; i<idmaps.Size(); i++)
+      delete idmaps[i];
+    idmaps.DeleteAll();
+
+    mesh.UpdateTopology();
+
+    if(refelementinfofilewrite != "")
+      {
+	PrintMessage(3,"writing marked-elements information to \"",refelementinfofilewrite,"\"");
+	ofstream ofst(refelementinfofilewrite.c_str());
+
+	WriteMarkedElements(ofst);
+
+	ofst.close();
+      }
+
+
+    PrintMessage (1, "Bisection done");
+
+    PopStatus();
+  }
+
+
+
+
+  BisectionOptions :: BisectionOptions ()
+  {
+    outfilename = NULL;
+    mlfilename = NULL;
+    refinementfilename = NULL;
+    femcode = NULL;
+    maxlevel = 50;
+    usemarkedelements = 0;
+    refine_hp = 0;
+    refine_p = 0;
+  }
+
+
+  Refinement :: Refinement ()
+  {
+    optimizer2d = NULL;
+  }
+
+  Refinement :: ~Refinement ()
+  {
+    ;
+  }
+
+
+  void Refinement :: PointBetween (const Point<3> & p1, const Point<3> & p2, double secpoint,
+				   int surfi, 
+				   const PointGeomInfo & gi1, 
+				   const PointGeomInfo & gi2,
+				   Point<3> & newp, PointGeomInfo & newgi)
+  {
+    newp = p1+secpoint*(p2-p1);
+  }
+
+  void Refinement :: PointBetween (const Point<3> & p1, const Point<3> & p2, double secpoint,
+				   int surfi1, int surfi2, 
+				   const EdgePointGeomInfo & ap1, 
+				   const EdgePointGeomInfo & ap2,
+				   Point<3> & newp, EdgePointGeomInfo & newgi)
+  {
+    newp = p1+secpoint*(p2-p1);
+  }
+
+
+  Vec<3> Refinement :: GetTangent (const Point<3> & p, int surfi1, int surfi2,
+                                   const EdgePointGeomInfo & ap1) const
+  {
+    cerr << "Refinement::GetTangent not overloaded" << endl;
+    return Vec<3> (0,0,0);
+  }
+
+  Vec<3> Refinement :: GetNormal (const Point<3> & p, int surfi1, 
+                                  const PointGeomInfo & gi) const
+  {
+    cerr << "Refinement::GetNormal not overloaded" << endl;
+    return Vec<3> (0,0,0);
+  }
+
+
+  void Refinement :: ProjectToSurface (Point<3> & p, int surfi)
+  {
+    if (printmessage_importance>0)
+      cerr << "Refinement :: ProjectToSurface    ERROR: no geometry set" << endl;
+  };
+
+  void Refinement :: ProjectToEdge (Point<3> & p, int surfi1, int surfi2, const EdgePointGeomInfo & egi) const
+  {
+    cerr << "Refinement::ProjectToEdge not overloaded" << endl;
+  }
+}
diff --git a/contrib/Netgen/libsrc/meshing/bisect.hpp b/contrib/Netgen/libsrc/meshing/bisect.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..e47033f255de9ce30e1f170767629b908328d5e3
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/bisect.hpp
@@ -0,0 +1,99 @@
+#ifndef BISECT
+#define BISECT
+
+class BisectionOptions
+{
+public:
+  const char * outfilename;
+  const char * mlfilename;
+  const char * refinementfilename;
+  const char * femcode;
+  int maxlevel;
+  int usemarkedelements;
+  bool refine_hp;
+  bool refine_p;
+  BisectionOptions ();
+};
+
+class ZRefinementOptions
+{
+public:
+  int minref;
+  ZRefinementOptions();
+};
+
+
+/*
+extern void BisectTets (Mesh &, const CSGeometry *,
+			BisectionOptions & opt);
+*/
+
+extern void BisectTetsCopyMesh (Mesh &, const class CSGeometry *,
+				BisectionOptions & opt);
+
+extern void ZRefinement (Mesh &, const CSGeometry *,
+			 ZRefinementOptions & opt);
+
+
+
+
+
+class Refinement
+{
+  MeshOptimize2d * optimizer2d;
+
+public:
+  Refinement ();
+  virtual ~Refinement ();
+  
+  void Refine (Mesh & mesh);
+  void Bisect (Mesh & mesh, class BisectionOptions & opt, ARRAY<double> * quality_loss = NULL);
+  void MakeSecondOrder (Mesh & mesh);
+
+  virtual void PointBetween (const Point<3> & p1, const Point<3> & p2, double secpoint, 
+			     int surfi, 
+			     const PointGeomInfo & gi1, 
+			     const PointGeomInfo & gi2,
+			     Point<3> & newp, PointGeomInfo & newgi);
+
+  virtual void PointBetween (const Point<3> & p1, const Point<3> & p2, double secpoint,
+			     int surfi1, int surfi2, 
+			     const EdgePointGeomInfo & ap1, 
+			     const EdgePointGeomInfo & ap2,
+			     Point<3> & newp, EdgePointGeomInfo & newgi);
+
+  virtual Vec<3> GetTangent (const Point<3> & p, int surfi1, int surfi2,
+                             const EdgePointGeomInfo & egi) const;
+
+  virtual Vec<3> GetNormal (const Point<3> & p, int surfi1, 
+                            const PointGeomInfo & gi) const;
+
+
+  virtual void ProjectToSurface (Point<3> & p, int surfi);
+
+  virtual void ProjectToSurface (Point<3> & p, int surfi, const PointGeomInfo & /* gi */)
+  {
+    ProjectToSurface (p, surfi);
+  }
+
+  virtual void ProjectToEdge (Point<3> & p, int surfi1, int surfi2, const EdgePointGeomInfo & egi) const;
+
+
+  void ValidateSecondOrder (Mesh & mesh);
+  void ValidateRefinedMesh (Mesh & mesh, 
+			    ARRAY<INDEX_2> & parents);
+
+  MeshOptimize2d * Get2dOptimizer(void)
+  {
+    return optimizer2d;
+  }
+  void Set2dOptimizer(MeshOptimize2d * opti)
+  {
+    optimizer2d = opti;
+  }
+
+  
+  virtual void LocalizeEdgePoints(Mesh & mesh) const {;}
+};
+
+#endif
diff --git a/contrib/Netgen/libsrc/meshing/boundarylayer.cpp b/contrib/Netgen/libsrc/meshing/boundarylayer.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..1dd3403807c843bf14ed69892c5c8c079a8e71a4
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/boundarylayer.cpp
@@ -0,0 +1,92 @@
+#include <mystdlib.h>
+#include "meshing.hpp"
+
+namespace netgen
+{
+
+void InsertVirtualBoundaryLayer (Mesh & mesh)
+{
+  cout << "Insert virt. b.l." << endl;
+  
+  int surfid;
+
+  cout << "Boundary Nr:";
+  cin >> surfid;
+
+  int i, j;
+  int np = mesh.GetNP();
+
+  cout << "Old NP: " << mesh.GetNP() << endl;
+  cout << "Trigs: " << mesh.GetNSE() << endl;
+
+  BitArray bndnodes(np);
+  ARRAY<int> mapto(np);
+
+  bndnodes.Clear();
+  for (i = 1; i <= mesh.GetNSeg(); i++)
+    {
+      int snr = mesh.LineSegment(i).edgenr;
+      cout << "snr = " << snr << endl;
+      if (snr == surfid)
+	{
+	  bndnodes.Set (mesh.LineSegment(i).p1);
+	  bndnodes.Set (mesh.LineSegment(i).p2);
+	}
+    }
+  for (i = 1; i <= mesh.GetNSeg(); i++)
+    {
+      int snr = mesh.LineSegment(i).edgenr;
+      if (snr != surfid)
+	{
+	  bndnodes.Clear (mesh.LineSegment(i).p1);
+	  bndnodes.Clear (mesh.LineSegment(i).p2);
+	}
+    }
+  
+  for (i = 1; i <= np; i++)
+    {
+      if (bndnodes.Test(i))
+	mapto.Elem(i) = mesh.AddPoint (mesh.Point (i));
+      else
+	mapto.Elem(i) = 0;
+    }
+
+  for (i = 1; i <= mesh.GetNSE(); i++)
+    {
+      Element2d & el = mesh.SurfaceElement(i);
+      for (j = 1; j <= el.GetNP(); j++)
+	if (mapto.Get(el.PNum(j)))
+	  el.PNum(j) = mapto.Get(el.PNum(j));
+    }
+
+
+  int nq = 0;
+  for (i = 1; i <= mesh.GetNSeg(); i++)
+    {
+      int snr = mesh.LineSegment(i).edgenr;
+      if (snr == surfid)
+	{
+	  int p1 = mesh.LineSegment(i).p1;
+	  int p2 = mesh.LineSegment(i).p2;
+	  int p3 = mapto.Get (p1);
+	  if (!p3) p3 = p1;
+	  int p4 = mapto.Get (p2);
+	  if (!p4) p4 = p2;
+	  
+	  Element2d el(QUAD);
+	  el.PNum(1) = p1;
+	  el.PNum(2) = p2;
+	  el.PNum(3) = p3;
+	  el.PNum(4) = p4;
+	  el.SetIndex (2);
+	  mesh.AddSurfaceElement (el);
+	  nq++;
+	}
+    }
+
+  cout << "New NP: " << mesh.GetNP() << endl;
+  cout << "Quads: " << nq << endl;
+}
+
+}
+
diff --git a/contrib/Netgen/libsrc/meshing/boundarylayer.hpp b/contrib/Netgen/libsrc/meshing/boundarylayer.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..e5a047b6bb0239c3ebd3e7a839a4ee830bef2183
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/boundarylayer.hpp
@@ -0,0 +1,9 @@
+#ifndef FILE_BOUNDARYLAYER
+#define FILE_BOUNDARYLAYER
+
+
+///
+extern void InsertVirtualBoundaryLayer (Mesh & mesh);
+
+
+#endif
diff --git a/contrib/Netgen/libsrc/meshing/classifyhpel.hpp b/contrib/Netgen/libsrc/meshing/classifyhpel.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..96bf1b62c43e43bc968e5463202119f01a361f87
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/classifyhpel.hpp
@@ -0,0 +1,1713 @@
+HPREF_ELEMENT_TYPE ClassifyTet(HPRefElement & el, INDEX_2_HASHTABLE<int> & edges, INDEX_2_HASHTABLE<int> & edgepoint_dom, 
+		 BitArray & cornerpoint, BitArray & edgepoint, INDEX_3_HASHTABLE<int> & faces, INDEX_2_HASHTABLE<int> & face_edges, 
+		 INDEX_2_HASHTABLE<int> & surf_edges, ARRAY<int, PointIndex::BASE> & facepoint)
+{
+  int ep1(0), ep2(0), ep3(0), ep4(0), cp1(0), cp2(0), cp3(0), cp4(0), fp1, fp2, fp3, fp4;
+  int isedge1(0), isedge2(0), isedge3(0), isedge4(0), isedge5(0), isedge6(0);
+  int isfedge1, isfedge2, isfedge3, isfedge4, isfedge5, isfedge6;
+  int isface1(0), isface2(0), isface3(0), isface4(0);
+
+  HPREF_ELEMENT_TYPE type = HP_NONE; 
+  
+
+  int debug = 0;
+  for (int j = 0;j < 4; j++)
+    {
+      if (el.pnums[j] == 444) debug++;
+      if (el.pnums[j] == 115) debug++;
+      if (el.pnums[j] == 382) debug++;
+      if (el.pnums[j] == 281) debug++;
+    }
+  if (debug < 4) debug = 0;
+  
+
+
+  for (int j = 0; j < 4; j++)
+    for (int k = 0; k < 4; k++)
+      {
+	if (j == k) continue;
+	if (type) break;
+	
+	int pi3 = 0;
+	while (pi3 == j || pi3 == k) pi3++;
+	int pi4 = 6 - j - k - pi3;
+	
+	// preserve orientation
+	int sort[4];
+	sort[0] = j; sort[1] = k; sort[2] = pi3; sort[3] = pi4;
+	int cnt = 0;
+	for (int jj = 0; jj < 4; jj++)
+	  for (int kk = 0; kk < 3; kk++)
+	    if (sort[kk] > sort[kk+1])
+	      {
+		cnt++;
+		Swap (sort[kk], sort[kk+1]); 
+	      }
+	if (cnt % 2 == 1) Swap (pi3, pi4);
+	
+	ep1 = edgepoint.Test (el.pnums[j]);
+	ep2 = edgepoint.Test (el.pnums[k]);
+	ep3 = edgepoint.Test (el.pnums[pi3]);
+	ep4 = edgepoint.Test (el.pnums[pi4]);
+	
+	cp1 = cornerpoint.Test (el.pnums[j]);
+	cp2 = cornerpoint.Test (el.pnums[k]);
+	cp3 = cornerpoint.Test (el.pnums[pi3]);
+	cp4 = cornerpoint.Test (el.pnums[pi4]);
+	
+	isedge1 = edges.Used (INDEX_2::Sort (el.pnums[j], el.pnums[k]));
+	isedge2 = edges.Used (INDEX_2::Sort (el.pnums[j], el.pnums[pi3]));
+	isedge3 = edges.Used (INDEX_2::Sort (el.pnums[j], el.pnums[pi4]));
+	isedge4 = edges.Used (INDEX_2::Sort (el.pnums[k], el.pnums[pi3]));
+	isedge5 = edges.Used (INDEX_2::Sort (el.pnums[k], el.pnums[pi4]));
+	isedge6 = edges.Used (INDEX_2::Sort (el.pnums[pi3], el.pnums[pi4]));
+	
+	if (debug)
+	  {
+	    cout << "debug" << endl;
+	    *testout  << "debug" << endl;
+	    *testout << "ep = " << ep1 << ep2 << ep3 << ep4 << endl;
+	    *testout << "cp = " << cp1 << cp2 << cp3 << cp4 << endl;
+	    *testout << "edge = " << isedge1 << isedge2 << isedge3 << isedge4 << isedge5 << isedge6 << endl;
+	  }
+
+
+	isface1 = isface2 = isface3 = isface4 = 0;
+	for (int l = 0; l < 4; l++)
+	  {
+	    INDEX_3 i3(0,0,0);
+	    switch (l)
+	      {
+		case 0: i3.I1() = el.pnums[k]; i3.I1() = el.pnums[pi3]; i3.I1() = el.pnums[pi4]; break;
+		case 1: i3.I1() = el.pnums[j]; i3.I1() = el.pnums[pi3]; i3.I1() = el.pnums[pi4]; break;
+		case 2: i3.I1() = el.pnums[j]; i3.I1() = el.pnums[k]; i3.I1() = el.pnums[pi4]; break;
+		case 3: i3.I1() = el.pnums[j]; i3.I1() = el.pnums[k]; i3.I1() = el.pnums[pi3]; break;
+	      }
+	    i3.Sort();
+	    if (faces.Used (i3))
+	      {
+		int domnr = faces.Get(i3);
+		if (domnr == -1 || domnr == el.GetIndex())
+		  {
+		    switch (l)
+		      {
+		      case 0: isface1 = 1; break;
+		      case 1: isface2 = 1; break;
+		      case 2: isface3 = 1; break;
+		      case 3: isface4 = 1; break;
+		      }
+		  }
+	      }
+	  }
+	/*
+	  isface1 = faces.Used (INDEX_3::Sort (el.pnums[k], el.pnums[pi3], el.pnums[pi4]));
+	  isface2 = faces.Used (INDEX_3::Sort (el.pnums[j], el.pnums[pi3], el.pnums[pi4]));
+	  isface3 = faces.Used (INDEX_3::Sort (el.pnums[j], el.pnums[k], el.pnums[pi4]));
+	  isface4 = faces.Used (INDEX_3::Sort (el.pnums[j], el.pnums[k], el.pnums[pi3]));
+	*/
+	
+	isfedge1 = isfedge2 = isfedge3 = isfedge4 = isfedge5 = isfedge6 = 0;
+	for (int l = 0; l < 6; l++)
+	  {
+	    INDEX_2 i2(0,0);
+	    switch (l)
+	      {
+		case 0: i2.I1() = el.pnums[j]; i2.I2() = el[k]; break;
+		case 1: i2.I1() = el.pnums[j]; i2.I2() = el.pnums[pi3]; break;
+		case 2: i2.I1() = el.pnums[j]; i2.I2() = el.pnums[pi4]; break;
+		case 3: i2.I1() = el.pnums[k]; i2.I2() = el.pnums[pi3]; break;
+		case 4: i2.I1() = el.pnums[k]; i2.I2() = el.pnums[pi4]; break;
+		case 5: i2.I1() = el.pnums[pi3]; i2.I2() = el.pnums[pi4]; break;
+	      }
+	    i2.Sort();
+	    if (face_edges.Used (i2))
+	      {
+		int domnr = face_edges.Get(i2);
+		if (domnr == -1 || domnr == el.GetIndex())
+		  {
+		    switch (l)
+		      {
+		      case 0: isfedge1 = 1; break;
+		      case 1: isfedge2 = 1; break;
+		      case 2: isfedge3 = 1; break;
+		      case 3: isfedge4 = 1; break;
+		      case 4: isfedge5 = 1; break;
+		      case 5: isfedge6 = 1; break;
+		      }
+		  }
+	      }
+	  }
+	/*
+	  isfedge1 = face_edges.Used (INDEX_2::Sort (el.pnums[j], el.pnums[k]));
+	  isfedge2 = face_edges.Used (INDEX_2::Sort (el.pnums[j], el.pnums[pi3]));
+	  isfedge3 = face_edges.Used (INDEX_2::Sort (el.pnums[j], el.pnums[pi4]));
+	  isfedge4 = face_edges.Used (INDEX_2::Sort (el.pnums[k], el.pnums[pi3]));
+	  isfedge5 = face_edges.Used (INDEX_2::Sort (el.pnums[k], el.pnums[pi4]));
+	  isfedge6 = face_edges.Used (INDEX_2::Sort (el.pnums[pi3], el.pnums[pi4]));
+	*/
+	
+	fp1 = fp2 = fp3 = fp4 = 0;
+	for (int l = 0; l < 4; l++)
+	  {
+	    int pti(0);
+	    switch (l)
+	      {
+	      case 0: pti = el.pnums[j]; break;
+	      case 1: pti = el.pnums[k]; break;
+	      case 2: pti = el.pnums[pi3]; break;
+	      case 3: pti = el.pnums[pi4]; break;
+	      }
+	    int domnr = facepoint[pti];
+	    if (domnr == -1 || domnr == el.GetIndex())
+	      {
+		switch (l)
+		  {
+		  case 0: fp1 = 1; break;
+		  case 1: fp2 = 1; break;
+		  case 2: fp3 = 1; break;
+		  case 3: fp4 = 1; break;
+		  }
+	      }
+	  }
+	
+	/*
+	  fp1 = facepoint[el.pnums[j]] != 0;
+	  fp2 = facepoint[el.pnums[k]] != 0;
+	  fp3 = facepoint[el.pnums[pi3]] != 0;
+	  fp4 = facepoint[el.pnums[pi4]] != 0;
+	*/
+	
+	
+	switch (isface1+isface2+isface3+isface4)
+	  {
+	  case 0:
+	    {
+	      isedge1 |= isfedge1;
+	      isedge2 |= isfedge2;
+	      isedge3 |= isfedge3;
+	      isedge4 |= isfedge4;
+	      isedge5 |= isfedge5;
+	      isedge6 |= isfedge6;
+	      
+	      ep1 |= fp1;
+	      ep2 |= fp2;
+	      ep3 |= fp3;
+	      ep4 |= fp4;
+	      
+	      switch (isedge1+isedge2+isedge3+isedge4+isedge5+isedge6)
+		{
+		case 0:
+		  {		
+		    if (!ep1 && !ep2 && !ep3 && !ep4)
+		      type = HP_TET;
+				
+		    if (ep1 && !ep2 && !ep3 && !ep4)
+		      type = HP_TET_0E_1V;
+		    
+		    if (ep1 && ep2 && !ep3 && !ep4)
+		      type = HP_TET_0E_2V;
+		    
+		    if (ep1 && ep2 && ep3 && !ep4)
+		      type = HP_TET_0E_3V;
+		    
+		    if (ep1 && ep2 && ep3 && ep4)
+		      type = HP_TET_0E_4V;
+		    
+		    break;
+		  }
+		  
+		case 1:
+		  {
+		    if (!isedge1) break;
+		    
+		    if (!cp1 && !cp2 && !ep3 && !ep4)
+		      type = HP_TET_1E_0V;
+		    
+		    if (cp1 && !cp2 && !ep3 && !ep4)
+		      type = HP_TET_1E_1VA;
+		    
+		    if (!cp1 && !cp2 && !ep3 && ep4)
+		      type = HP_TET_1E_1VB;
+		    
+		    if (cp1 && cp2 && !ep3 && !ep4)
+		      type = HP_TET_1E_2VA;
+		    
+		    if (cp1 && !cp2 && ep3 && !ep4)
+		      type = HP_TET_1E_2VB;
+		    
+		    if (cp1 && !cp2 && !ep3 && ep4)
+		      type = HP_TET_1E_2VC;
+		    
+		    if (!cp1 && !cp2 && ep3 && ep4)
+		      type = HP_TET_1E_2VD;
+		    
+		    if (cp1 && cp2 && ep3 && !ep4)
+		      type = HP_TET_1E_3VA;
+		    
+		    if (cp1 && !cp2 && ep3 && ep4)
+		      type = HP_TET_1E_3VB;
+		    
+		    if (cp1 && cp2 && ep3 && ep4)
+		      type = HP_TET_1E_4V;
+		    
+		    break;
+		  }
+		case 2:
+		  {
+		    if (isedge1 && isedge2)
+		      {
+			if (!cp2 && !cp3 && !ep4)
+			  type = HP_TET_2EA_0V;
+			
+			if (cp2 && !cp3 && !ep4)
+			  type = HP_TET_2EA_1VA;
+			if (!cp2 && cp3 && !ep4)
+			  type = HP_TET_2EA_1VB;
+			
+			if (!cp2 && !cp3 && ep4)
+			  type = HP_TET_2EA_1VC;
+			
+			if (cp2 && cp3 && !ep4)
+			  type = HP_TET_2EA_2VA;
+			if (cp2 && !cp3 && ep4)
+			  type = HP_TET_2EA_2VB;
+			if (!cp2 && cp3 && ep4)
+			  type = HP_TET_2EA_2VC;
+			
+			if (cp2 && cp3 && ep4)
+			  type = HP_TET_2EA_3V;
+		      }
+		    if (isedge1 && isedge6)
+		      {
+			if (!cp1 && !cp2 && !cp3 && !cp4)
+			  type = HP_TET_2EB_0V;
+			if (cp1 && !cp2 && !cp3 && !cp4)
+			  type = HP_TET_2EB_1V;
+			if (cp1 && cp2 && !cp3 && !cp4)
+			  type = HP_TET_2EB_2VA;
+			if (cp1 && !cp2 && cp3 && !cp4)
+			  type = HP_TET_2EB_2VB;
+			if (cp1 && !cp2 && !cp3 && cp4)
+			  type = HP_TET_2EB_2VC;
+			if (cp1 && cp2 && cp3 && !cp4)
+			  type = HP_TET_2EB_3V;
+			if (cp1 && cp2 && cp3 && cp4)
+			  type = HP_TET_2EB_4V;
+		      }
+		    break;
+		  }
+		case 3:
+		  {
+		    if (isedge1 && isedge2 && isedge3)
+		      {
+			if (!cp2 && !cp3 && !cp4)
+			  type = HP_TET_3EA_0V;
+			if (cp2 && !cp3 && !cp4)
+			  type = HP_TET_3EA_1V;
+			if (cp2 && cp3 && !cp4)
+			  type = HP_TET_3EA_2V;
+			if (cp2 && cp3 && cp4)
+			  type = HP_TET_3EA_3V;
+		      }
+		    if (isedge1 && isedge3 && isedge4)
+		      {
+			if (!cp3 && !cp4)
+			  type = HP_TET_3EB_0V;
+			if (cp3 && !cp4)
+				      type = HP_TET_3EB_1V;
+			if (cp3 && cp4)
+			  type = HP_TET_3EB_2V;
+		      }
+		    if (isedge1 && isedge2 && isedge5)
+		      {
+			if (!cp3 && !cp4)
+			  type = HP_TET_3EC_0V;
+			if (cp3 && !cp4)
+			  type = HP_TET_3EC_1V;
+			if (cp3 && cp4)
+			  type = HP_TET_3EC_2V;
+		      }
+		    break;
+		  }
+		}
+	      break;
+	    }
+	    
+	    
+	    
+	  case 1:  // one singular face
+	    {
+	      if (!isface1) break;
+	      
+	      switch (isfedge1+isfedge2+isfedge3+isedge4+isedge5+isedge6)
+		{
+		case 0:
+		  {
+		    if (!fp1 && !ep2 && !ep3 && !ep4)
+		      type = HP_TET_1F_0E_0V;
+		    if (fp1 && !ep2 && !ep3 && !ep4)
+		      type = HP_TET_1F_0E_1VB;
+		    if (!fp1 && ep2 && !ep3 & !ep4)
+		      type = HP_TET_1F_0E_1VA;
+		    break;
+		  }
+		case 1:
+		  {
+		    if (isfedge1)
+		      {
+			if (!ep1 && !ep3 && !ep4)
+			  type = HP_TET_1F_1EA_0V;
+		      }
+		    if (isedge4) // V1-V3
+		      {
+			if (!ep1 && !cp2 && !cp3 && !ep4)
+			  type = HP_TET_1F_1EB_0V;
+		      }
+		    break;
+		  }
+		}
+	      break;
+	    }
+	    
+	    
+	  case 2:  // two singular faces
+	    {
+	      if (!isface1 || !isface2) break;
+	      
+	      switch (isfedge1+isedge2+isedge3+isedge4+isedge5)
+		{
+		case 0:
+		  {
+		    if (!ep1 && !ep2 && !cp3 && !cp4)
+		      type = HP_TET_2F_0E_0V;
+		    break;
+		  }
+		}
+	      break;
+	    }
+	    
+	    
+	  }
+	
+	if (type != HP_NONE)
+	  {
+	    int pnums[4]; 
+	    pnums[0] = el.pnums[j];
+	    pnums[1] = el.pnums[k];
+	    pnums[2] = el.pnums[pi3];
+	    pnums[3] = el.pnums[pi4];
+	    for(k=0;k<4;k++) el.pnums[k] = pnums[k]; 
+	    break;
+	  }
+      }
+  
+  
+  if (debug) cout << "type = " << type << endl;
+
+  if (type == HP_NONE)
+    {
+      //     cnt_undef++;
+      (*testout) << "undefined element" << endl
+		 << "cp = " << cp1 << cp2 << cp3 << cp4 << endl
+		 << "ep = " << ep1 << ep2 << ep3 << ep4 << endl
+		 << "isedge = " << isedge1 << isedge2 << isedge3 
+		 << isedge4 << isedge5 << isedge6 << endl
+		 << "isface = " << isface1 << isface2 << isface3 << isface4 << endl;
+      cout << "undefined element !!! " << endl;
+
+      
+    }
+  return(type); 
+}
+
+
+
+HPREF_ELEMENT_TYPE ClassifyPrism(HPRefElement & el, INDEX_2_HASHTABLE<int> & edges, INDEX_2_HASHTABLE<int> & edgepoint_dom, 
+		 BitArray & cornerpoint, BitArray & edgepoint, INDEX_3_HASHTABLE<int> & faces, INDEX_2_HASHTABLE<int> & face_edges, 
+		 INDEX_2_HASHTABLE<int> & surf_edges, ARRAY<int, PointIndex::BASE> & facepoint)
+{
+
+  HPREF_ELEMENT_TYPE type = HP_NONE;
+  
+  int p[6];
+  for(int m=1;m<=6;m++)
+    {
+      int point_sing[6]={0,0,0,0,0,0}; 
+      int face_sing[5]={0,0,0,0,0};
+      int edge_sing[9]={0,0,0,0,0,0,0,0,0}; 
+      
+      if(m<4)
+	{ 
+	  p[0]= m; p[1]=m%3+1; p[2]=(m%3+1)%3+1;
+	  for(int l=3;l<6;l++) p[l]=p[l-3]+3;  
+	}
+      else
+	{
+	  p[0] = m; p[1]=(m%3+1)%3+4; p[2]=m%3+4;
+	  for(int l=3;l<6;l++) p[l]=p[l-3]-3; 
+	}
+      
+      for(int j=0;j<6;j++) 
+	{ 
+	  if(cornerpoint.Test(el.PNum(p[j])))  { point_sing[p[j]-1]=3;}
+	  else if(edgepoint.Test(el.PNum(p[j]))) point_sing[p[j]-1]=2;
+	  else if (facepoint[el.PNum(p[j])] == -1 || facepoint[el.PNum(p[j])] == el.GetIndex())
+	    point_sing[p[j]-1] = 1;  
+	}
+      
+      const ELEMENT_EDGE * eledges = MeshTopology::GetEdges (PRISM);
+      for(int k=0;k<9;k++)
+	{
+	  INDEX_2 i2 = INDEX_2 :: Sort(el.PNum(p[eledges[k][0]-1]),el.PNum(p[eledges[k][1]-1])); 
+	  if (edges.Used(i2)) edge_sing[k] = 2;
+	  else edge_sing[k] = face_edges.Used(i2);
+	}
+      
+      const ELEMENT_FACE * elfaces  = MeshTopology::GetFaces (PRISM);
+      for (int k=0;k<5;k++)
+	{
+	  INDEX_3 i3; 
+	  
+	  if(k<2) 
+	    i3 = INDEX_3::Sort(el.pnums[p[elfaces[k][0]-1]-1], el.pnums[p[elfaces[k][1]-1]-1], 
+			       el.pnums[p[elfaces[k][2]-1]-1]); 
+	  else 
+	    { 
+	      INDEX_4  i4 = INDEX_4(el.pnums[p[elfaces[k][0]-1]-1], el.pnums[p[elfaces[k][1]-1]-1], el.pnums[p[elfaces[k][2]-1]-1],el.pnums[p[elfaces[k][3]-1]-1]); 
+	      i4.Sort();
+	      i3 = INDEX_3(i4.I1(), i4.I2(), i4.I3()); 
+	    }
+	  
+	  if (faces.Used (i3))
+	    {
+	      int domnr = faces.Get(i3); 
+	      if (domnr == -1 || domnr == el.GetIndex())
+		face_sing[k] = 1; 
+	      
+	    } 
+	} 
+      if (face_sing[1] > face_sing[0]) {m=m+2; continue;}  
+      
+      
+      //int cp = 0;  
+      
+      int qfsing = face_sing[2] + face_sing[3] + face_sing[4];
+      int tfsing = face_sing[0] + face_sing[1]; 
+      int evsing = edge_sing[6] + edge_sing[7] + edge_sing[8];
+      int ehsing = edge_sing[0] + edge_sing[1] + edge_sing[2] + edge_sing[3] + edge_sing[4] + edge_sing[5];
+      
+      if (qfsing + tfsing + evsing + ehsing == 0)  
+	{ type = HP_PRISM;  break;}
+      
+      HPREF_ELEMENT_TYPE types[] = {HP_NONE,HP_NONE,HP_NONE};   
+      
+      int fb = (1-face_sing[4])* face_sing[3] * (face_sing[2] + face_sing[3]) + 3*face_sing[4]*face_sing[3]*face_sing[2];  
+      int sve[3] = {edge_sing[7] , edge_sing[8], edge_sing[6]}; 
+      
+            
+      if(fb!=qfsing) continue; 
+      
+      
+      switch(fb)
+	{ 
+	case 0: 
+	  if (evsing == 0 && ehsing==3*tfsing) 
+	    {
+	      types[0] = HP_PRISM; 
+	      types[1] = HP_PRISM_1FA_0E_0V;   
+	      types[2] = HP_PRISM_2FA_0E_0V; 
+	    } 
+	  if(evsing > 0 &&  sve[0] == evsing) // 1 vertical edge 1-4 
+	    { 
+	      types[0] = HP_PRISM_SINGEDGE;
+	      types[1] = HP_PRISM_1FA_1E_0V;
+	      types[2] = HP_PRISM_2FA_1E_0V;   
+	    }
+	  
+	  if(sve[0] > 0 && sve[1] > 0 && sve[2] == 0)
+	    {
+	      types[0] = HP_PRISM_SINGEDGE_V12;
+	      types[1] = HP_PRISM_1FA_2E_0V; 
+	      types[2] = HP_PRISM_2FA_2E_0V; 
+	    }
+	  if(sve[0] > 0 && sve[1] > 0 && sve[2] > 0) 
+	    {
+	      types[0] = HP_PRISM_3E_0V;
+	      types[1] = HP_PRISM_1FA_3E_0V;
+	      types[2] = HP_PRISM_2FA_3E_0V;
+	      
+	      if ( edge_sing[0] > 1 && edge_sing[2] > 1 &&  
+		   edge_sing[4] > 1 && edge_sing[5] > 1 && tfsing==0)
+		types[0] = HP_PRISM_3E_4EH; 
+	    }
+	  
+	  break;
+	case 1:
+	  if(sve[0] <= 1 && sve[1] <= 1)  
+	    if(sve[2]==0)
+	      { 
+		types[0] = HP_PRISM_1FB_0E_0V;
+		types[1] = HP_PRISM_1FA_1FB_0E_0V;
+		types[2] = HP_PRISM_2FA_1FB_0E_0V;  
+	      }
+	    else
+	      { 
+		types[0] = HP_PRISM_1FB_1EC_0V;
+		types[1] = HP_PRISM_1FA_1FB_1EC_0V;
+		types[2] = HP_PRISM_2FA_1FB_1EC_0V; 
+	      }
+	  
+	  if(sve[0] > 1 && sve[2] >= 1 && sve[1] <= 1)
+	    { 
+	      types[0] = HP_PRISM_1FB_2EB_0V;  
+	      types[1] = HP_PRISM_1FA_1FB_2EB_0V;
+	      types[2] = HP_PRISM_2FA_1FB_2EB_0V; 
+	    }
+	  
+	  if(sve[0] > 1 && sve[1] <= 1 && sve[2] == 0) // ea && !eb  
+	    {
+	      types[0] = HP_PRISM_1FB_1EA_0V;
+	      types[1] = HP_PRISM_1FA_1FB_1EA_0V;
+	      types[2] = HP_PRISM_2FA_1FB_1EA_0V; 
+	    } 
+	  
+	  if(sve[0] <= 1 && sve[1] > 1 && sve[2] == 0)
+	    types[1] = HP_PRISM_1FA_1FB_1EB_0V; 
+	  
+	  if(sve[0] > 1 && sve[1]>1) 
+	    if(sve[2] == 0)  // ea && eb 
+	      {
+		types[0] = HP_PRISM_1FB_2EA_0V;
+		types[1] = HP_PRISM_1FA_1FB_2EA_0V;
+		types[2] = HP_PRISM_2FA_1FB_2EA_0V; 
+	      }
+	  if(sve[0] <= 1 && sve[1] > 1 && sve[2] >0)
+	    types[1] = HP_PRISM_1FA_1FB_2EC_0V; 
+	  
+	  if(sve[0] > 1 && sve[1] > 1 && sve[2] >= 1) //sve[2] can also be a face-edge  
+	    {
+	      types[0] = HP_PRISM_1FB_3E_0V;  
+	      types[1] = HP_PRISM_1FA_1FB_3E_0V; 
+	      types[2] = HP_PRISM_2FA_1FB_3E_0V; 
+	    } 
+	  
+	  break;  
+	  
+	case 2:
+	  if(sve[0] <= 1) 
+	    cout << " **** WARNING: Edge between to different singular faces should be marked singular " << endl; 
+		      
+	  if(sve[1] <= 1)   
+	    if(sve[2] <=1) 
+	      { 
+		types[0] = HP_PRISM_2FB_0E_0V; 
+		types[1] = HP_PRISM_1FA_2FB_0E_0V;
+		types[2] = HP_PRISM_2FA_2FB_0E_0V;
+	      }
+	    else
+	      { 
+		types[0] = HP_PRISM_2FB_1EC_0V; 
+		types[1] = HP_PRISM_1FA_2FB_1EC_0V; 
+		types[2] = HP_PRISM_2FA_2FB_1EC_0V;   
+	      }
+	  else
+	    if(sve[2] <= 1) 
+	      types[1] = HP_PRISM_1FA_2FB_1EB_0V; 
+	    else
+	      { 
+		types[0] = HP_PRISM_2FB_3E_0V; 
+		types[1] = HP_PRISM_1FA_2FB_3E_0V; 
+		types[2] = HP_PRISM_2FA_2FB_3E_0V; 
+	      }
+	  
+	  break;
+	  
+	case 3: 
+	  types[0] = HP_PRISM_3FB_0V; 
+	  types[1] = HP_PRISM_1FA_3FB_0V; 
+	  types[2] = HP_PRISM_2FA_3FB_0V; 
+	  break;
+	}
+      type = types[tfsing];
+      
+         
+      if(type != HP_NONE)  
+	break;
+    }
+	 
+  /*
+   *testout << " Prism with pnums " << endl; 
+   for(int j=0;j<6;j++) *testout << el.pnums[j] << "\t"; 
+   *testout << endl; 
+   */
+  
+  if(type != HP_NONE) 
+    {
+      int pnums[6]; 
+      for(int j=0;j<6;j++) pnums[j] = el.PNum (p[j]);
+      for(int k=0;k<6;k++) el.pnums[k] = pnums[k]; 
+    }
+
+  /* *testout << " Classified Prism with pnums " << endl; 
+  for(int j=0;j<6;j++) *testout << el.pnums[j] << "\t"; 
+  *testout << endl; 
+  */ 
+  return(type); 
+}
+
+
+// #ifdef SABINE 
+HPREF_ELEMENT_TYPE ClassifyTrig(HPRefElement & el, INDEX_2_HASHTABLE<int> & edges, INDEX_2_HASHTABLE<int> & edgepoint_dom, 
+		 BitArray & cornerpoint, BitArray & edgepoint, INDEX_3_HASHTABLE<int> & faces, INDEX_2_HASHTABLE<int>  & face_edges, 
+				INDEX_2_HASHTABLE<int> & surf_edges, ARRAY<int, PointIndex::BASE> & facepoint, int dim, const FaceDescriptor & fd)
+
+{
+  HPREF_ELEMENT_TYPE type = HP_NONE; 
+  
+  int pnums[3]; 
+  int p[3];   
+  
+  INDEX_3 i3 (el.pnums[0], el.pnums[1], el.pnums[2]);
+  i3.Sort();
+  bool sing_face = faces.Used (i3);
+  
+  // *testout << " facepoint " << facepoint << endl;  
+      
+
+  // Try all rotations of the trig 
+  for (int j=0;j<3;j++) 
+    {
+      int point_sing[3] = {0,0,0}; 
+      int edge_sing[3] = {0,0,0}; 
+      // *testout << " actual rotation of trig points " ;  
+      for(int m=0;m<3;m++) 
+	{ 
+	  p[m] = (j+m)%3 +1; // local vertex number
+	  pnums[m] = el.PNum(p[m]); // global vertex number 
+	  // *testout << pnums[m] << " \t "; 
+	}
+      // *testout << endl ; 
+      
+      if(dim == 3) 
+	{
+	  // face point 
+	  for(int k=0;k<3;k++)
+	    if(!sing_face)
+	      { 
+		//	*testout << " fp [" << k << "] = " << facepoint[pnums[k]] << endl;   
+		//	*testout << " fd.DomainIn()" <<  fd.DomainIn() << endl; 
+		//	*testout  << " fd.DomainOut()" <<  fd.DomainOut() << endl; 
+		if( facepoint[pnums[k]]  && (facepoint[pnums[k]] ==-1 || 
+					     facepoint[pnums[k]] == fd.DomainIn() ||   facepoint[pnums[k]] == fd.DomainOut()))
+		  point_sing[p[k]-1] = 1; 
+	      } 
+	  // if point is on face_edge in next step sing = 2 
+
+	  /*	  *testout << " pointsing NACH FACEPOints ... FALLS EDGEPOINT UMSETZEN" ; 
+	  for (int k=0;k<3;k++) *testout << "\t" << point_sing[p[k]-1] ;
+	  *testout << endl; */
+	}
+      
+      const ELEMENT_EDGE * eledges = MeshTopology::GetEdges(TRIG); 
+      
+      if(dim==3)
+	{
+	  for(int k=0;k<3;k++) 
+	    { 
+	      int ep1=p[eledges[k][0]-1];  
+	      int ep2=p[eledges[k][1]-1];  
+	      INDEX_2 i2(el.PNum(ep1),el.PNum(ep2)); 
+	      
+	      if(edges.Used(i2)) 
+		{
+		  
+		  edge_sing[k]=2;
+		  point_sing[ep1-1] = 2; 
+		  point_sing[ep2-1] = 2; 
+		}
+	      else // face_edge? 
+		{	  
+		  i2.Sort();  
+		  if(surf_edges.Used(i2) && surf_edges.Get(i2) != fd.SurfNr()+1)  // edge not face_edge acc. to surface in which trig lies
+		    if(face_edges.Get(i2)==-1 ||face_edges.Get(i2) == fd.DomainIn() || face_edges.Get(i2) == fd.DomainOut() )
+		      { 
+			edge_sing[k]=1;
+		      } 
+		    else
+		      { 
+			point_sing[ep1-1] = 0; // set to edge_point 
+			point_sing[ep2-1] = 0; // set to edge_point
+		      } 
+		}
+	      
+	      /*  *testout << " pointsing NACH edges UND FACEEDGES UMSETZEN ... " ; 
+	      for (int k=0;k<3;k++) *testout << "\t" << point_sing[p[k]-1] ; 
+	      *testout << endl;          
+	      */
+	    }
+	}
+      /*
+      *testout << " dim " << dim << endl; 
+      *testout << " edgepoint_dom " << edgepoint_dom << endl; 
+      */
+      if(dim==2)
+	{
+	  for(int k=0;k<3;k++) 
+	    { 
+	      int ep1=p[eledges[k][0]-1];  
+	      int ep2=p[eledges[k][1]-1];  
+	     
+	      INDEX_2 i2(el.PNum(ep1),el.PNum(ep2));  
+	     
+	      if(edges.Used(i2)) 
+		{
+		  
+		  if(edgepoint_dom.Used(INDEX_2(fd.SurfNr(),pnums[ep1-1])) || 
+		     edgepoint_dom.Used(INDEX_2(-1,pnums[ep1-1])) || 
+		     edgepoint_dom.Used(INDEX_2(fd.SurfNr(),pnums[ep2-1])) || 
+		     edgepoint_dom.Used(INDEX_2(-1,pnums[ep2-1]))) 
+		    {
+		      edge_sing[k]=2;
+		      point_sing[ep1-1] = 2;
+		      point_sing[ep2-1] = 2; 
+		    }
+		}
+	     
+	    }
+	}
+
+     
+	 
+      for(int k=0;k<3;k++) 
+	if(edgepoint.Test(pnums[k])) //edgepoint, but not member of sing_edge on trig -> cp 
+	  {
+	    INDEX_2 i2a=INDEX_2::Sort(el.PNum(p[k]), el.PNum(p[(k+1)%3])); 
+	    INDEX_2 i2b=INDEX_2::Sort(el.PNum(p[k]), el.PNum(p[(k+2)%3])); 
+	    
+	    if(!edges.Used(i2a) && !edges.Used(i2b)) 
+	      point_sing[p[k]-1] = 3; 	
+	  } 
+      
+      for(int k=0;k<3;k++) 
+	if(cornerpoint.Test(el.PNum(p[k]))) 
+	  point_sing[p[k]-1] = 3; 
+      
+
+     if(edge_sing[0] + edge_sing[1] + edge_sing[2] == 0) 
+       { 
+	 int ps = point_sing[0] + point_sing[1] + point_sing[2]; 
+	 
+	 if(ps==0) 
+	   type = HP_TRIG; 
+	 else if(point_sing[p[0]-1]  && !point_sing[p[1]-1] && !point_sing[p[2]-1])
+	   type = HP_TRIG_SINGCORNER;
+	 else if(point_sing[p[0]-1] && point_sing[p[1]-1] && !point_sing[p[2]-1]) 
+	   type = HP_TRIG_SINGCORNER12; 
+	 else if(point_sing[p[0]-1] && point_sing[p[1]-1] && point_sing[p[2]-1]) 
+	   { 
+	     if(dim==2) type = HP_TRIG_SINGCORNER123_2D; 
+	     else type = HP_TRIG_SINGCORNER123; 
+	   } 
+       } 
+     else
+       if (edge_sing[2] && !edge_sing[0] && !edge_sing[1]) //E[2]=(1,2) 
+      { 
+	int code = 0; 
+	if(point_sing[p[0]-1] > edge_sing[2]) code+=1; 
+	if(point_sing[p[1]-1] > edge_sing[2]) code+=2; 
+	if(point_sing[p[2]-1]) code+=4; 
+	
+	HPREF_ELEMENT_TYPE types[] =
+	  {
+	    HP_TRIG_SINGEDGE, 
+	    HP_TRIG_SINGEDGECORNER1, 
+	    HP_TRIG_SINGEDGECORNER2,
+	    HP_TRIG_SINGEDGECORNER12, 
+	    HP_TRIG_SINGEDGECORNER3, 
+	    HP_TRIG_SINGEDGECORNER13, 
+	    HP_TRIG_SINGEDGECORNER23, 
+	    HP_TRIG_SINGEDGECORNER123, 
+	  };
+	type = types[code]; 
+	
+      }  // E[0] = [0,2], E[1] =[1,2], E[2] = [0,1]
+    else 
+      if(edge_sing[2] && !edge_sing[1] && edge_sing[0])
+	{
+	  if(point_sing[p[2]-1] <= edge_sing[0] ) 
+	    { 
+	      if(point_sing[p[1]-1]<= edge_sing[2]) type = HP_TRIG_SINGEDGES; 
+	      else type = HP_TRIG_SINGEDGES2; 
+	    } 
+	  else 
+	    {
+	      if(point_sing[p[1]-1]<= edge_sing[2]) 
+		type = HP_TRIG_SINGEDGES3; 
+	      else type = HP_TRIG_SINGEDGES23; 
+	    }
+	}
+      else if (edge_sing[2] && edge_sing[1] && edge_sing[0])
+	type = HP_TRIG_3SINGEDGES; 
+     
+     //  cout << " run for " <<  j << " gives type " << type << endl; 
+     //*testout << " run for " <<  j << " gives type " << type << endl; 
+     if(type!=HP_NONE) break;
+    }
+    
+  for(int k=0;k<3;k++) el[k] = pnums[k]; 
+  /*if(type != HP_NONE) 
+   {
+     
+      cout << " TRIG with pnums " << pnums[0] << "\t"  << 
+	pnums[1] << "\t"  << pnums[2] << endl; 
+      cout << " type "  << type << endl; 
+      }
+  */
+  return(type);
+}
+#ifdef HPREF_OLD 
+HPREF_ELEMENT_TYPE ClassifyTrig(HPRefElement & el, INDEX_2_HASHTABLE<int> & edges, INDEX_2_HASHTABLE<int> & edgepoint_dom, 
+				BitArray & cornerpoint, BitArray & edgepoint, INDEX_3_HASHTABLE<int> & faces, INDEX_2_HASHTABLE<int> & face_edges, 
+				INDEX_2_HASHTABLE<int> & surf_edges, ARRAY<int, PointIndex::BASE> & facepoint, int dim, const FaceDescriptor & fd)
+{
+  HPREF_ELEMENT_TYPE type = HP_NONE; 
+  
+  int pnums[3]; 
+	      
+  INDEX_3 i3 (el.pnums[0], el.pnums[1], el.pnums[2]);
+  i3.Sort();
+  bool sing_face = faces.Used (i3);
+   
+  
+  for (int j = 1; j <= 3; j++)
+    {
+      int ep1 = edgepoint.Test (el.PNumMod (j));
+      int ep2 = edgepoint.Test (el.PNumMod (j+1));
+      int ep3 = edgepoint.Test (el.PNumMod (j+2));
+      
+      if (dim == 2)
+	{
+	  // JS, Dec 11
+	  ep1 = edgepoint_dom.Used (INDEX_2 (fd.SurfNr(), el.PNumMod(j))) ||
+	    edgepoint_dom.Used (INDEX_2 (-1, el.PNumMod(j)));
+	  ep2 = edgepoint_dom.Used (INDEX_2 (fd.SurfNr(), el.PNumMod(j+1))) ||
+	    edgepoint_dom.Used (INDEX_2 (-1, el.PNumMod(j+1)));
+	  ep3 = edgepoint_dom.Used (INDEX_2 (fd.SurfNr(), el.PNumMod(j+2))) ||
+	    edgepoint_dom.Used (INDEX_2 (-1, el.PNumMod(j+2)));
+	  /*
+	  ep1 = edgepoint_dom.Used (INDEX_2 (el.index, el.PNumMod(j)));
+	  ep2 = edgepoint_dom.Used (INDEX_2 (el.index, el.PNumMod(j+1)));
+	  ep3 = edgepoint_dom.Used (INDEX_2 (el.index, el.PNumMod(j+2)));
+	  */
+	  // ep3 = edgepoint_dom.Used (INDEX_2 (mesh.SurfaceElement(i).GetIndex(), el.PNumMod(j+2)));
+	}
+      
+      
+      
+      int cp1 = cornerpoint.Test (el.PNumMod (j));
+      int cp2 = cornerpoint.Test (el.PNumMod (j+1));
+      int cp3 = cornerpoint.Test (el.PNumMod (j+2));
+      
+      ep1 |= cp1;
+      ep2 |= cp2;
+      ep3 |= cp3;
+      
+      
+      // (*testout) << "cp = " << cp1 << cp2 << cp3 << ", ep = " << ep1 << ep2 << ep3 << endl;
+
+      int p[3] = { el.PNumMod (j), el.PNumMod (j+1), el.PNumMod (j+2)};
+      if(ep1)
+	{
+	  INDEX_2 i2a=INDEX_2::Sort(p[0], p[1]); 
+	  INDEX_2 i2b=INDEX_2::Sort(p[0], p[2]); 
+	  if(!edges.Used(i2a) && !edges.Used(i2b)) 
+	    cp1 = 1; 
+	}
+      if(ep2)
+	{
+	  INDEX_2 i2a=INDEX_2::Sort(p[1], p[0]); 
+	  INDEX_2 i2b=INDEX_2::Sort(p[1], p[2]); 
+	  if(!edges.Used(i2a) && !edges.Used(i2b)) 
+	    cp2 = 1; 
+	}
+      if(ep3)
+	{
+	  INDEX_2 i2a=INDEX_2::Sort(p[2], p[0]); 
+	  INDEX_2 i2b=INDEX_2::Sort(p[2], p[1]); 
+	  if(!edges.Used(i2a) && !edges.Used(i2b)) 
+	    cp3= 1; 
+	}		      
+      
+      
+      int isedge1=0, isedge2=0, isedge3=0; 
+      if(dim == 3 )
+	{
+	  INDEX_2 i2;
+	  i2 = INDEX_2(el.PNumMod (j), el.PNumMod (j+1));
+	  isedge1 = edges.Used (i2);
+	  i2.Sort();
+	  if(surf_edges.Used(i2) &&  surf_edges.Get(i2)   != fd.SurfNr()+1 && 
+	     (face_edges.Get(i2) == -1 || face_edges.Get(i2) == fd.DomainIn() || face_edges.Get(i2) == fd.DomainOut()) ) 
+	    {
+	      isedge1=1;
+	      ep1 = 1; ep2=1;
+	    }
+	  
+	  i2 = INDEX_2(el.PNumMod (j+1), el.PNumMod (j+2));
+	  isedge2 = edges.Used (i2);
+	  i2.Sort();
+	  if(surf_edges.Used(i2) &&  surf_edges.Get(i2)   != fd.SurfNr()+1 &&
+	     (face_edges.Get(i2) == -1 || face_edges.Get(i2) == fd.DomainIn() || face_edges.Get(i2) == fd.DomainOut()) ) 
+	    {
+	      isedge2=1;
+	      ep2 = 1; ep3=1;
+	    }
+	  i2 = INDEX_2(el.PNumMod (j+2), el.PNumMod (j+3));
+	  isedge3 = edges.Used (i2);
+	  i2.Sort();
+	  if(surf_edges.Used(i2) &&  surf_edges.Get(i2)   != fd.SurfNr()+1 && 
+	     (face_edges.Get(i2) == -1 || face_edges.Get(i2) == fd.DomainIn() || face_edges.Get(i2) == fd.DomainOut()) ) 
+	    {
+	      isedge3=1;
+	      ep1 = 1; ep3=1;
+	    }
+	  
+	  // cout << " isedge " << isedge1 << " \t " << isedge2 << " \t " << isedge3 << endl;  
+	
+	  if (!sing_face)
+	{
+	  /*
+	    if (!isedge1)  { cp1 |= ep1; cp2 |= ep2; }
+	    if (!isedge2)  { cp2 |= ep2; cp3 |= ep3; }
+	    if (!isedge3)  { cp3 |= ep3; cp1 |= ep1; }
+	  */
+	  ep1 |= facepoint [el.PNumMod(j)] != 0;
+	  ep2 |= facepoint [el.PNumMod(j+1)] != 0;
+	  ep3 |= facepoint [el.PNumMod(j+2)] != 0;
+	  
+	  
+	  isedge1 |= face_edges.Used (INDEX_2::Sort (el.PNumMod(j), el.PNumMod(j+1)));
+	  isedge2 |= face_edges.Used (INDEX_2::Sort (el.PNumMod(j+1), el.PNumMod(j+2)));
+	  isedge3 |= face_edges.Used (INDEX_2::Sort (el.PNumMod(j+2), el.PNumMod(j+3)));
+	}
+	}
+      
+      if(dim ==2) 
+	{ 
+	  INDEX_2 i2;
+	  i2 = INDEX_2(el.PNumMod (j), el.PNumMod (j+1));
+	  i2.Sort();
+	  isedge1 = edges.Used (i2);
+	  if(isedge1)
+	    {
+	      ep1 = 1; ep2=1;
+	    }
+	  
+	  i2 = INDEX_2(el.PNumMod (j+1), el.PNumMod (j+2));
+	  i2.Sort();
+	  isedge2 = edges.Used (i2);
+	  if(isedge2)
+	    {
+	      ep2 = 1; ep3=1;
+	    }
+	  i2 = INDEX_2(el.PNumMod (j+2), el.PNumMod (j+3));
+	  i2.Sort();
+	  isedge3 = edges.Used (i2);
+	  if(isedge3)
+	    {
+	      ep1 = 1; ep3=1;
+	    }
+	  
+	  
+	}
+      
+		  
+		  /*
+		  cout << " used " << face_edges.Used (INDEX_2::Sort (el.PNumMod(j), el.PNumMod(j+1))) << endl; 
+
+		  cout << " isedge " << isedge1 << " \t " << isedge2 << " \t " << isedge3 << endl; 
+		  cout << " ep " << ep1 << "\t" << ep2 << " \t " << ep3 << endl; 
+		  cout << " cp " << cp1 << "\t" << cp2 << " \t " << cp3 << endl; 
+		  */
+		  
+
+      
+      if (isedge1 + isedge2 + isedge3 == 0)
+	{
+	  if (!ep1 && !ep2 && !ep3)
+	    type = HP_TRIG;
+	  
+	  if (ep1 && !ep2 && !ep3)
+	    type = HP_TRIG_SINGCORNER;
+	  
+	  if (ep1 && ep2 && !ep3)
+	    type = HP_TRIG_SINGCORNER12;
+	  
+	  if (ep1 && ep2 && ep3)
+	    {
+	      if (dim == 2)
+			    type = HP_TRIG_SINGCORNER123_2D;
+	      else
+		type = HP_TRIG_SINGCORNER123;
+	    }
+	  
+	  if (type != HP_NONE)
+	    {
+	      pnums[0] = el.PNumMod (j);
+	      pnums[1] = el.PNumMod (j+1);
+	      pnums[2] = el.PNumMod (j+2);
+	      break;
+	    }
+	}
+      
+      if (isedge1 && !isedge2 && !isedge3)
+	{
+	  int code = 0;
+	  if (cp1) code += 1;
+	  if (cp2) code += 2;
+	  if (ep3) code += 4;
+	  
+	  HPREF_ELEMENT_TYPE types[] =
+	    {
+	      HP_TRIG_SINGEDGE, 
+	      HP_TRIG_SINGEDGECORNER1, 
+	      HP_TRIG_SINGEDGECORNER2,
+	      HP_TRIG_SINGEDGECORNER12, 
+	      HP_TRIG_SINGEDGECORNER3, 
+	      HP_TRIG_SINGEDGECORNER13, 
+	      HP_TRIG_SINGEDGECORNER23, 
+	      HP_TRIG_SINGEDGECORNER123, 
+	    };
+	  type = types[code];
+	  pnums[0] = el.PNumMod (j);
+	  pnums[1] = el.PNumMod (j+1);
+	  pnums[2] = el.PNumMod (j+2);
+	  break;
+	}
+      
+      
+      if (isedge1 && !isedge2 && isedge3)
+	{
+	  if (!cp3)
+	    {
+	      if (!cp2) type = HP_TRIG_SINGEDGES;
+	      else      type = HP_TRIG_SINGEDGES2;
+	    }
+	  else
+	    { 
+	      if (!cp2) type = HP_TRIG_SINGEDGES3;
+	      else      type = HP_TRIG_SINGEDGES23;
+	    }
+	  
+	  pnums[0] = el.PNumMod (j);
+	  pnums[1] = el.PNumMod (j+1);
+	  pnums[2] = el.PNumMod (j+2);
+	  break;
+	}
+       
+      if (isedge1 && isedge2 && isedge3)
+	{
+	  type = HP_TRIG_3SINGEDGES;
+	  pnums[0] = el.PNumMod (j);
+	  pnums[1] = el.PNumMod (j+1);
+	  pnums[2] = el.PNumMod (j+2);
+	  break;
+	}
+    }
+  
+  for(int k=0;k<3;k++) el[k] = pnums[k]; 
+  /*if(type != HP_NONE) 
+   {
+     
+      cout << " TRIG with pnums " << pnums[0] << "\t"  << 
+	pnums[1] << "\t"  << pnums[2] << endl; 
+      cout << " type "  << type << endl; 
+      }
+  */
+  return(type);
+}
+#endif
+HPREF_ELEMENT_TYPE ClassifyQuad(HPRefElement & el, INDEX_2_HASHTABLE<int> & edges, INDEX_2_HASHTABLE<int> & edgepoint_dom, 
+		 BitArray & cornerpoint, BitArray & edgepoint, INDEX_3_HASHTABLE<int> & faces, INDEX_2_HASHTABLE<int>  & face_edges, 
+				INDEX_2_HASHTABLE<int> & surf_edges, ARRAY<int, PointIndex::BASE> & facepoint, int dim, const FaceDescriptor & fd)
+{
+  HPREF_ELEMENT_TYPE type = HP_NONE; 
+  
+  int ep1(-1), ep2(-1), ep3(-1), ep4(-1), cp1(-1), cp2(-1), cp3(-1), cp4(-1);
+	      int isedge1, isedge2, isedge3, isedge4;
+
+	      for (int j = 1; j <= 4; j++)
+		{
+		  ep1 = edgepoint.Test (el.PNumMod (j));
+		  ep2 = edgepoint.Test (el.PNumMod (j+1));
+		  ep3 = edgepoint.Test (el.PNumMod (j+2));
+		  ep4 = edgepoint.Test (el.PNumMod (j+3));
+
+		  if (dim == 2)
+		    {
+		      ep1 = edgepoint_dom.Used (INDEX_2 (el.GetIndex(), el.PNumMod(j)));
+		      ep2 = edgepoint_dom.Used (INDEX_2 (el.GetIndex(), el.PNumMod(j+1)));
+		      ep3 = edgepoint_dom.Used (INDEX_2 (el.GetIndex(), el.PNumMod(j+2)));
+		      ep4 = edgepoint_dom.Used (INDEX_2 (el.GetIndex(), el.PNumMod(j+3)));
+		    }
+
+		  cp1 = cornerpoint.Test (el.PNumMod (j));
+		  cp2 = cornerpoint.Test (el.PNumMod (j+1));
+		  cp3 = cornerpoint.Test (el.PNumMod (j+2));
+		  cp4 = cornerpoint.Test (el.PNumMod (j+3));
+
+		  ep1 |= cp1;
+		  ep2 |= cp2;
+		  ep3 |= cp3;
+		  ep4 |= cp4;
+		
+		  int p[4] = { el.PNumMod (j), el.PNumMod (j+1), el.PNumMod (j+2), el.PNumMod(j+4)};
+		  //int epp[4] = { ep1, ep2, ep3, ep4}; 
+		  int cpp[4] = { cp1, cp2, cp3, cp4};
+		  for(int k=0;k<0;k++)
+		    {
+		      INDEX_2 i2a=INDEX_2::Sort(p[k], p[(k+1)%4]); 
+		      INDEX_2 i2b=INDEX_2::Sort(p[k], p[(k-1)%4]); 
+		      if(!edges.Used(i2a) && !edges.Used(i2b)) 
+			cpp[k] = 1; 
+		    }
+		  cp1= cpp[0]; cp2=cpp[1]; cp3=cpp[2]; cp4=cpp[3];
+		  
+
+		  if(dim ==3) 
+		    { 
+		      INDEX_2 i2;
+		      i2 = INDEX_2(el.PNumMod (j), el.PNumMod (j+1));
+		      // i2.Sort();
+		      isedge1 = edges.Used (i2);
+		      i2.Sort();
+		      if(surf_edges.Used(i2)  &&  surf_edges.Get(i2)   != fd.SurfNr()+1 && 
+			 (face_edges.Get(i2) == -1 || face_edges.Get(i2) == fd.DomainIn() || face_edges.Get(i2) == fd.DomainOut()) ) 
+			{
+			  isedge1=1;
+			  ep1 = 1; ep2=1;
+			}
+		      i2 = INDEX_2(el.PNumMod (j+1), el.PNumMod (j+2));
+		      // i2.Sort();
+		      isedge2 = edges.Used (i2);
+		      i2.Sort();
+		      if(surf_edges.Used(i2)  &&  surf_edges.Get(i2)   != fd.SurfNr()+1 && 
+			 (face_edges.Get(i2) == -1 || face_edges.Get(i2) == fd.DomainIn() || face_edges.Get(i2) == fd.DomainOut()) ) 
+			{  
+			  isedge2=1;
+			  ep2=1; ep3=1;
+			}
+		      i2 = INDEX_2(el.PNumMod (j+2), el.PNumMod (j+3));
+		      // i2.Sort();
+		      isedge3 = edges.Used (i2); 
+		      i2.Sort();
+		      if(surf_edges.Used(i2)   &&  surf_edges.Get(i2)   != fd.SurfNr()+1 && (face_edges.Get(i2) == -1 || face_edges.Get(i2) == fd.DomainIn() || face_edges.Get(i2) == fd.DomainOut()) ) 
+			{
+			  isedge3=1;
+			  ep3=1; ep4=1;
+			}
+		      i2 = INDEX_2(el.PNumMod (j+3), el.PNumMod (j+4));
+		      // i2.Sort();
+		      isedge4 = edges.Used (i2);
+		      i2.Sort();
+		      if(surf_edges.Used(i2)  &&  surf_edges.Get(i2)   != fd.SurfNr()+1 && 
+			 (face_edges.Get(i2) == -1 || face_edges.Get(i2) == fd.DomainIn() || face_edges.Get(i2) == fd.DomainOut()) ) 
+			{ 
+			  isedge4=1;
+			  ep4=1; ep1=1;
+			} 
+		    
+
+//MH***********************************************************************************************************
+		      if(ep1)
+			if(edgepoint.Test(p[0]))
+			{
+			  INDEX_2 i2a=INDEX_2::Sort(p[0], p[1]); 
+	  		  INDEX_2 i2b=INDEX_2::Sort(p[0], p[3]); 
+	  		  if(!edges.Used(i2a) && !edges.Used(i2b)) 
+	    		    cp1 = 1; 
+			}
+		      if(ep2)
+			if(edgepoint.Test(p[1]))
+			{
+			  INDEX_2 i2a=INDEX_2::Sort(p[0], p[1]); 
+	  		  INDEX_2 i2b=INDEX_2::Sort(p[1], p[2]); 
+	  		  if(!edges.Used(i2a) && !edges.Used(i2b)) 
+	    		    cp2 = 1; 
+			}
+		      if(ep3)
+			if(edgepoint.Test(p[2]))
+			{
+			  INDEX_2 i2a=INDEX_2::Sort(p[2], p[1]); 
+	  		  INDEX_2 i2b=INDEX_2::Sort(p[3], p[2]); 
+	  		  if(!edges.Used(i2a) && !edges.Used(i2b)) 
+	    		    cp3 = 1; 
+			}
+		      if(ep4)
+			if(edgepoint.Test(p[3]))
+			{
+			  INDEX_2 i2a=INDEX_2::Sort(p[0], p[3]); 
+	  		  INDEX_2 i2b=INDEX_2::Sort(p[3], p[2]); 
+	  		  if(!edges.Used(i2a) && !edges.Used(i2b)) 
+	    		    cp4 = 1; 
+			}
+//MH*****************************************************************************************************************************
+		}
+		  else
+		    { 
+		      INDEX_2 i2;
+		      i2 = INDEX_2(el.PNumMod (j), el.PNumMod (j+1));
+		      i2.Sort();
+		      isedge1 = edges.Used (i2);
+		      if(isedge1)
+			{
+			  ep1 = 1; ep2=1;
+			}
+		      i2 = INDEX_2(el.PNumMod (j+1), el.PNumMod (j+2));
+		      i2.Sort();
+		      isedge2 = edges.Used (i2);
+		      if(isedge2)
+			{  
+			  ep2=1; ep3=1;
+			}
+		      i2 = INDEX_2(el.PNumMod (j+2), el.PNumMod (j+3));
+		      i2.Sort();
+		      isedge3 = edges.Used (i2); 
+		      
+		      if(isedge3)
+			{
+			  ep3=1; ep4=1;
+			}
+		      i2 = INDEX_2(el.PNumMod (j+3), el.PNumMod (j+4));
+		      i2.Sort();
+		      isedge4 = edges.Used (i2);
+		      if(isedge4)
+			{ 
+			  ep4=1; ep1=1;
+			} 
+		    }
+
+		  int sumcp = cp1 + cp2 + cp3 + cp4;
+		  int sumep = ep1 + ep2 + ep3 + ep4;
+		  int sumedge = isedge1 + isedge2 + isedge3 + isedge4;
+
+		  switch (sumedge)
+		    {
+		    case 0:
+		      {
+			switch (sumep)
+			  {
+			  case 0: 
+			    type = HP_QUAD; 
+			    break;
+			  case 1: 
+			    if (ep1) type = HP_QUAD_SINGCORNER;
+			    break; 
+			  case 2:
+			    {
+			      if (ep1 && ep2) type = HP_QUAD_0E_2VA;
+			      if (ep1 && ep3) type = HP_QUAD_0E_2VB;
+			      break;
+			    }
+			  case 3: 
+			    if (!ep4) type = HP_QUAD_0E_3V; 
+			    break; 
+			  case 4: 
+			    type = HP_QUAD_0E_4V; 
+			    break; 
+			  }
+			break;
+		      }
+		    case 1:
+		      {
+			if (isedge1)
+			  {
+			    switch (cp1+cp2+ep3+ep4)
+			      {
+			      case 0: 
+				type = HP_QUAD_SINGEDGE; 
+				break;
+			      case 1:
+				{
+				  if (cp1) type = HP_QUAD_1E_1VA;
+				  if (cp2) type = HP_QUAD_1E_1VB;
+				  if (ep3) type = HP_QUAD_1E_1VC;
+				  if (ep4) type = HP_QUAD_1E_1VD; 
+				  break; 
+				}
+			      case 2:
+				{
+				  if (cp1 && cp2) type = HP_QUAD_1E_2VA; 
+				  if (cp1 && ep3) type = HP_QUAD_1E_2VB; 
+				  if (cp1 && ep4) type = HP_QUAD_1E_2VC; 
+				  if (cp2 && ep3) type = HP_QUAD_1E_2VD; 
+				  if (cp2 && ep4) type = HP_QUAD_1E_2VE; 
+				  if (ep3 && ep4) type = HP_QUAD_1E_2VF; 
+				  break; 
+				}
+			      case 3:
+				{
+				  if (cp1 && cp2 && ep3) type = HP_QUAD_1E_3VA;
+				  if (cp1 && cp2 && ep4) type = HP_QUAD_1E_3VB;
+				  if (cp1 && ep3 && ep4) type = HP_QUAD_1E_3VC;
+				  if (cp2 && ep3 && ep4) type = HP_QUAD_1E_3VD;
+				  break;
+				}
+			      case 4:
+				{
+				  type = HP_QUAD_1E_4V; 
+				  break;
+				}
+			      }
+			  }
+			break;
+		      }
+		    case 2:
+		      {
+			if (isedge1 && isedge4)
+			  {
+			    if (!cp2 && !ep3 && !cp4)
+			      type = HP_QUAD_2E;
+			  
+			    if (cp2 && !ep3 && !cp4)
+			      type = HP_QUAD_2E_1VA;
+			    if (!cp2 && ep3 && !cp4)
+			      type = HP_QUAD_2E_1VB;
+			    if (!cp2 && !ep3 && cp4)
+			      type = HP_QUAD_2E_1VC;
+
+			    if (cp2 && ep3 && !cp4)
+			      type = HP_QUAD_2E_2VA;
+			    if (cp2 && !ep3 && cp4)
+			      type = HP_QUAD_2E_2VB;
+			    if (!cp2 && ep3 && cp4)
+			      type = HP_QUAD_2E_2VC;
+
+			    if (cp2 && ep3 && cp4)
+			      type = HP_QUAD_2E_3V;
+			  }
+			if (isedge1 && isedge3)
+			  {
+			    switch (sumcp)
+			      {
+			      case 0: 
+				type = HP_QUAD_2EB_0V; break;
+			      case 1:
+				{
+				  if (cp1) type = HP_QUAD_2EB_1VA; 
+				  if (cp2) type = HP_QUAD_2EB_1VB; 
+				  break;
+				}
+			      case 2:
+				{
+				  if (cp1 && cp2) { type = HP_QUAD_2EB_2VA; }
+				  if (cp1 && cp3) { type = HP_QUAD_2EB_2VB; }
+				  if (cp1 && cp4) { type = HP_QUAD_2EB_2VC; }
+				  if (cp2 && cp4) { type = HP_QUAD_2EB_2VD; }
+				  break;
+				}
+			      case 3:
+				{
+				  if (cp1 && cp2 && cp3) { type = HP_QUAD_2EB_3VA; }
+				  if (cp1 && cp2 && cp4) { type = HP_QUAD_2EB_3VB; }
+				  break;
+				}
+			      case 4:
+				{
+				  type = HP_QUAD_2EB_4V; break;
+				}
+			      }
+			  }
+			break;
+		      }
+
+		    case 3:
+		      {
+			if (isedge1 && isedge2 && isedge4)
+			  {
+			    if (!cp3 && !cp4) type = HP_QUAD_3E;
+			    if (cp3 && !cp4) type = HP_QUAD_3E_3VA;
+			    if (!cp3 && cp4) type = HP_QUAD_3E_3VB;
+			    if (cp3 && cp4) type = HP_QUAD_3E_4V;
+			  }
+			break;
+		      }
+
+		    case 4:
+		      {
+			type = HP_QUAD_4E;
+			break;
+		      }
+		    }
+
+		  if (type != HP_NONE)
+		    {
+		      int pnums[4]; 
+		      pnums[0] = el.PNumMod (j); 
+		      pnums[1] = el.PNumMod (j+1);
+		      pnums[2] = el.PNumMod (j+2); 
+		      pnums[3] = el.PNumMod (j+3);
+		      for (int k=0;k<4;k++) el[k] = pnums[k]; 
+	
+		      /*  cout << " QUAD with pnums " << pnums[0] << "\t"  << 
+			pnums[1] << "\t"  << pnums[2] << "\t"  << pnums[3] 
+			<< endl << " of type " << type << endl; */
+		   		      
+		      break;
+		    }
+		}
+	      if (type == HP_NONE)
+		{
+		  (*testout) << "undefined element" << endl
+			     << "cp = " << cp1 << cp2 << cp3 << cp4 << endl
+			     << "ep = " << ep1 << ep2 << ep3 << ep4 << endl
+			     << "isedge = " << isedge1 << isedge2 << isedge3 
+			     << isedge4 << endl;
+		}
+	    
+
+	      return(type);  
+}	    
+
+
+HPREF_ELEMENT_TYPE ClassifyHex(HPRefElement & el, INDEX_2_HASHTABLE<int> & edges, INDEX_2_HASHTABLE<int> & edgepoint_dom, 
+		 BitArray & cornerpoint, BitArray & edgepoint, INDEX_3_HASHTABLE<int> & faces, INDEX_2_HASHTABLE<int> & face_edges, 
+		 INDEX_2_HASHTABLE<int> & surf_edges, ARRAY<int, PointIndex::BASE> & facepoint)
+{
+  HPREF_ELEMENT_TYPE type = HP_NONE;
+  
+  // implementation only for HP_HEX_1F_0E_0V
+  //                         HP_HEX_1FA_1FB_0E_0V
+  //                         HP_HEX 
+  // up to now other cases are refine dummies 
+  
+  // indices of bot,top-faces combinations
+  int index[6][2] = {{0,1},{1,0},{2,4},{4,2},{3,5},{5,3}}; 
+  int p[8]; 
+  const ELEMENT_FACE * elfaces  = MeshTopology::GetFaces (HEX);
+  const ELEMENT_EDGE * eledges = MeshTopology::GetEdges (HEX);
+  
+  for(int m=0;m<6 && type == HP_NONE;m++) 
+    for(int j=0;j<4 && type == HP_NONE;j++) 
+      { 
+	int point_sing[8]={0,0,0,0,0,0,0,0}; 
+	int face_sing[6] = {0,0,0,0,0,0};
+	int edge_sing[12] = {0,0,0,0,0,0,0,0,0,0,0,0};
+	int spoint=0, sface=0, sedge=0; 
+	for(int l=0;l<4;l++) 
+	  {
+	    p[l] = elfaces[index[m][0]][(4-j-l)%4]; 
+	    p[l+4] = elfaces[index[m][1]][(j+l)%4];
+	  }
+	
+	for(int l=0;l<8;l++) 
+	  if(cornerpoint.Test(el.PNum(p[l])))  
+	    { 
+	      point_sing[p[l]-1]=3;
+	      spoint++; 
+	    }
+	  else if(edgepoint.Test(el.PNum(p[l]))) point_sing[p[l]-1]=2;
+	  else if (facepoint[el.PNum(p[l])] == -1 || facepoint[el.PNum(p[l])] == el.GetIndex())
+	    point_sing[p[l]-1] = 1;   
+	
+	for(int k=0;k<12;k++)
+	{
+	  INDEX_2 i2 = INDEX_2 :: Sort(el.PNum(p[eledges[k][0]-1]),el.PNum(p[eledges[k][1]-1])); 
+	  if (edges.Used(i2)) 
+	    { 
+	      edge_sing[k] = 2;
+	      sedge++; 
+	    }
+	  else edge_sing[k] = face_edges.Used(i2);
+	}
+	
+	for (int k=0;k<6;k++)
+	{
+	  INDEX_3 i3; 
+	  
+	
+	  INDEX_4  i4 = INDEX_4(el.pnums[p[elfaces[k][0]-1]-1], el.pnums[p[elfaces[k][1]-1]-1], el.pnums[p[elfaces[k][2]-1]-1],el.pnums[p[elfaces[k][3]-1]-1]); 
+	  i4.Sort();
+	  i3 = INDEX_3(i4.I1(), i4.I2(), i4.I3()); 
+	  
+	  if (faces.Used (i3))
+	    {
+	      
+	      int domnr = faces.Get(i3); 
+	      if (domnr == -1 || domnr == el.GetIndex())
+		{
+		  face_sing[k] = 1;
+		  sface++;
+		}
+	      
+	    } 
+	} 
+	
+	if(!sface && !sedge && !spoint) type = HP_HEX; 
+	if(!sedge && !spoint) 
+	  {
+	    if(face_sing[0] && face_sing[2] && sface==2) 
+	      type = HP_HEX_1FA_1FB_0E_0V; 
+	    if (face_sing[0] && sface==1)  
+	      type = HP_HEX_1F_0E_0V; 
+	  }
+	
+	el.type=type; 
+
+	if(type != HP_NONE) 
+	  {
+	    int pnums[8]; 
+	    for(int l=0;l<8;l++) pnums[l] = el[p[l]-1];
+	    for(int l=0;l<8;l++) el[l] = pnums[l];
+	    /* cout << " HEX with pnums " << pnums[0] << "\t"  << 
+	      pnums[1] << "\t"  << pnums[2] << "\t"  << pnums[3] << "\t"  << 
+	      pnums[4] << "\t"  <<  pnums[5] << endl << " of type " << type << endl; */
+	    break; 
+	  }
+      }
+  
+  return (type); 
+
+}
+
+HPREF_ELEMENT_TYPE ClassifySegm(HPRefElement & hpel, INDEX_2_HASHTABLE<int> & edges, INDEX_2_HASHTABLE<int> & edgepoint_dom, 
+		 BitArray & cornerpoint, BitArray & edgepoint, INDEX_3_HASHTABLE<int> & faces, INDEX_2_HASHTABLE<int> & face_edges, 
+		 INDEX_2_HASHTABLE<int> & surf_edges, ARRAY<int, PointIndex::BASE> & facepoint)
+{
+  
+  int cp1 = cornerpoint.Test (hpel[0]);
+  int cp2 = cornerpoint.Test (hpel[1]);
+  
+  INDEX_2 i2;
+  i2 = INDEX_2(hpel[0], hpel[1]);
+  i2.Sort();
+  if (!edges.Used (i2))
+    {
+      cp1 = edgepoint.Test (hpel[0]);
+      cp2 = edgepoint.Test (hpel[1]);
+    }
+  
+  if(!edges.Used(i2) && !face_edges.Used(i2))
+    {
+      if(facepoint[hpel[0]]!=0) cp1=1; 
+      if(facepoint[hpel[1]]!=0) cp2=1; 
+    }
+  
+  if(edges.Used(i2) && !face_edges.Used(i2))
+    {
+      if(facepoint[hpel[0]]) cp1 = 1; 
+	    if(facepoint[hpel[1]]) cp2 = 1; 
+    }
+  
+  if (!cp1 && !cp2)
+    hpel.type = HP_SEGM;
+  else if (cp1 && !cp2)
+    hpel.type = HP_SEGM_SINGCORNERL;
+  else if (!cp1 && cp2)
+    hpel.type = HP_SEGM_SINGCORNERR;
+  else
+    hpel.type = HP_SEGM_SINGCORNERS;
+  
+  // cout << " SEGM found with " << hpel[0] << " \t" << hpel[1] << endl << " of type " << hpel.type << endl; 
+  return(hpel.type) ; 
+} 
+
+
+HPREF_ELEMENT_TYPE ClassifyPyramid(HPRefElement & el, INDEX_2_HASHTABLE<int> & edges, INDEX_2_HASHTABLE<int> & edgepoint_dom, 
+		 BitArray & cornerpoint, BitArray & edgepoint, INDEX_3_HASHTABLE<int> & faces, INDEX_2_HASHTABLE<int> & face_edges, 
+		 INDEX_2_HASHTABLE<int> & surf_edges, ARRAY<int, PointIndex::BASE> & facepoint)
+{
+  HPREF_ELEMENT_TYPE type = HP_NONE;
+  
+  // implementation only for HP_PYRAMID
+  //                         HP_PYRAMID_0E_1V
+  //                         HP_PYRAMID_EDGES
+  //                         HP_PYRAMID_1FB_0E_1VA
+  // up to now other cases are refine dummies 
+  
+  // indices of bot,top-faces combinations
+  // int index[6][2] = {{0,1},{1,0},{2,4},{4,2},{3,5},{5,3}}; 
+
+  const ELEMENT_FACE * elfaces  = MeshTopology::GetFaces (PYRAMID);
+  const ELEMENT_EDGE * eledges = MeshTopology::GetEdges (PYRAMID);
+  
+  int point_sing[5]={0,0,0,0,0}; 
+  int face_sing[5] = {0,0,0,0,0};
+  int edge_sing[8] = {0,0,0,0,0,0,0,0};
+  
+  int spoint=0, sedge=0, sface=0; 
+   
+  for(int m=0;m<4 && type == HP_NONE;m++) 
+    {
+      int p[5] = {m%4, m%4+1, m%4+2, m%4+3, 4}; 
+
+      for(int l=0;l<5;l++) 
+	{
+	  if(cornerpoint.Test(el.pnums[p[l]]))  
+	    point_sing[l]=3;
+	  
+	     else if(edgepoint.Test(el.pnums[p[l]]))
+	    point_sing[l]=2;
+	  
+	  else if (facepoint[el.pnums[p[l]]] == -1 || facepoint[el.pnums[p[l]]] == el.GetIndex())
+	    point_sing[l] = 1;   
+	  
+	  spoint += point_sing[l]; 
+	}
+      
+      for(int k=0;k<8;k++)
+	{
+	  INDEX_2 i2 = INDEX_2 :: Sort(el.pnums[p[eledges[k][0]-1]],
+				       el.pnums[p[eledges[k][1]-1]]); 
+	  if (edges.Used(i2)) 
+	    edge_sing[k] = 2;
+	  else 
+	    edge_sing[k] = face_edges.Used(i2);
+	  
+	  sedge += edge_sing[k]; 
+	}
+  
+      for (int k=0;k<5;k++)
+	{
+	  INDEX_3 i3; 
+	  INDEX_4  i4 = INDEX_4(el.pnums[p[elfaces[k][0]-1]], el.pnums[p[elfaces[k][1]-1]], el.pnums[p[elfaces[k][2]-1]],
+				el.pnums[p[elfaces[k][3]-1]]); 
+	  i4.Sort();
+	  i3 = INDEX_3(i4.I1(), i4.I2(), i4.I3()); 
+	  
+	  if (faces.Used (i3))
+	    {
+	      
+	      int domnr = faces.Get(i3); 
+	      if (domnr == -1 || domnr == el.GetIndex())
+		face_sing[k] = 1;
+	    } 
+	  sface +=face_sing[k]; 
+	} 
+  
+      if(!sface && !spoint && !sedge) return(HP_PYRAMID); 
+      
+      if(!sface && !sedge && point_sing[p[0]] == spoint) 
+	type = HP_PYRAMID_0E_1V; 
+      
+      if(!sface && edge_sing[0] + edge_sing[2] == sedge && 
+	 spoint == point_sing[0] + point_sing[1] + point_sing[3]) 
+	type = HP_PYRAMID_EDGES; 
+      
+      if(sface && sface == face_sing[0] && spoint == point_sing[4] + 2)
+	type = HP_PYRAMID_1FB_0E_1VA; 
+      
+      
+      if(type != HP_NONE) 
+	{ 
+	  int pnums[8]; 
+	  for(int l=0;l<5;l++) pnums[l] = el[p[l]];
+	  for(int l=0;l<5;l++) el[l] = pnums[l];
+	  el.type=type; 
+	  break; 
+	} 
+    }
+  
+  return (type); 
+  
+}
diff --git a/contrib/Netgen/libsrc/meshing/clusters.cpp b/contrib/Netgen/libsrc/meshing/clusters.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..da6c66fe3512b2531d0400db12c4753f3eb310fa
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/clusters.cpp
@@ -0,0 +1,267 @@
+#include <mystdlib.h>
+
+#include "meshing.hpp"
+
+namespace netgen
+{
+
+AnisotropicClusters ::  AnisotropicClusters (const Mesh & amesh)
+  : mesh(amesh)
+{
+  ;
+}
+
+AnisotropicClusters ::  ~AnisotropicClusters ()
+{
+  ;
+}
+
+void AnisotropicClusters ::  Update()
+{
+  int i, j, k;
+
+  const MeshTopology & top = mesh.GetTopology();
+
+  bool hasedges = top.HasEdges();
+  bool hasfaces = top.HasFaces();
+
+  if (!hasedges || !hasfaces) return;
+
+
+  PrintMessage (3, "Update Clusters");
+
+  nv = mesh.GetNV();
+  ned = top.GetNEdges();
+  nfa = top.GetNFaces();
+  ne = mesh.GetNE();
+  int nse = mesh.GetNSE();
+
+  cluster_reps.SetSize (nv+ned+nfa+ne);
+  
+  ARRAY<int> nnums, ednums, fanums;
+  int changed;
+
+  for (i = 1; i <= cluster_reps.Size(); i++)
+    cluster_reps.Elem(i) = -1;
+
+  
+  for (i = 1; i <= ne; i++)
+    {
+      const Element & el = mesh.VolumeElement(i);
+      ELEMENT_TYPE typ = el.GetType();
+      
+      top.GetElementEdges (i, ednums);
+      top.GetElementFaces (i, fanums);
+      
+      int elnv = top.GetNVertices (typ);
+      int elned = ednums.Size();
+      int elnfa = fanums.Size();
+	  
+      nnums.SetSize(elnv+elned+elnfa+1);
+      for (j = 1; j <= elnv; j++)
+	nnums.Elem(j) = el.PNum(j);
+      for (j = 1; j <= elned; j++)
+	nnums.Elem(elnv+j) = nv+ednums.Elem(j);
+      for (j = 1; j <= elnfa; j++)
+	nnums.Elem(elnv+elned+j) = nv+ned+fanums.Elem(j);
+      nnums.Elem(elnv+elned+elnfa+1) = nv+ned+nfa+i;
+
+      for (j = 0; j < nnums.Size(); j++)
+	cluster_reps.Elem(nnums[j]) = nnums[j];
+    }
+
+  
+
+  for (i = 1; i <= nse; i++)
+    {
+      const Element2d & el = mesh.SurfaceElement(i);
+      ELEMENT_TYPE typ = el.GetType();
+      
+      top.GetSurfaceElementEdges (i, ednums);
+      int fanum = top.GetSurfaceElementFace (i);
+      
+      int elnv = top.GetNVertices (typ);
+      int elned = ednums.Size();
+	  
+      nnums.SetSize(elnv+elned+1);
+      for (j = 1; j <= elnv; j++)
+	nnums.Elem(j) = el.PNum(j);
+      for (j = 1; j <= elned; j++)
+	nnums.Elem(elnv+j) = nv+ednums.Elem(j);
+      nnums.Elem(elnv+elned+1) = fanum;
+
+      for (j = 0; j < nnums.Size(); j++)
+	cluster_reps.Elem(nnums[j]) = nnums[j];
+    }
+
+  static const int hex_cluster[] =
+    { 
+      1, 2, 3, 4, 1, 2, 3, 4, 
+      5, 6, 7, 8, 5, 6, 7, 8, 1, 2, 3, 4, 
+      9, 9, 5, 8, 6, 7, 
+      9
+    };
+
+  static const int prism_cluster[] =
+    { 
+      1, 2, 3, 1, 2, 3,
+      4, 5, 6, 4, 5, 6, 3, 1, 2,
+      7, 7, 4, 5, 6, 
+      7
+    };
+
+  static const int pyramid_cluster[] =
+    { 
+      1, 2, 2, 1, 3,
+      4, 2, 1, 4, 6, 5, 5, 6,
+      7, 5, 7, 6, 4, 
+      7
+    };
+  static const int tet_cluster14[] =
+    { 1, 2, 3, 1,   1, 4, 5, 4, 5, 6,   7, 5, 4, 7, 7 };
+  
+  static const int tet_cluster12[] =
+    { 1, 1, 2, 3,   4, 4, 5, 1, 6, 6,   7, 7, 4, 6, 7 };
+
+  static const int tet_cluster13[] =
+    { 1, 2, 1, 3,   4, 6, 4, 5, 1, 5,   7, 4, 7, 5, 7 };
+
+  static const int tet_cluster23[] =
+    { 2, 1, 1, 3, 6, 5, 5, 4, 4, 1, 5, 7, 7, 4, 7 };
+
+  static const int tet_cluster24[] =
+    { 2, 1, 3, 1, 4, 1, 5, 4, 6, 5, 5, 7, 4, 7, 7 };
+
+  static const int tet_cluster34[] =
+    { 2, 3, 1, 1, 4, 5, 1, 6, 4, 5, 5, 4, 7, 7, 7 };
+
+  int cnt = 0;
+
+  do
+    {
+
+      cnt++;
+      changed = 0;
+      
+      for (i = 1; i <= ne; i++)
+	{
+	  const Element & el = mesh.VolumeElement(i);
+	  ELEMENT_TYPE typ = el.GetType();
+	  
+	  top.GetElementEdges (i, ednums);
+	  top.GetElementFaces (i, fanums);
+	  
+	  int elnv = top.GetNVertices (typ);
+	  int elned = ednums.Size();
+	  int elnfa = fanums.Size();
+	  
+	  nnums.SetSize(elnv+elned+elnfa+1);
+	  for (j = 1; j <= elnv; j++)
+	    nnums.Elem(j) = el.PNum(j);
+	  for (j = 1; j <= elned; j++)
+	    nnums.Elem(elnv+j) = nv+ednums.Elem(j);
+	  for (j = 1; j <= elnfa; j++)
+	    nnums.Elem(elnv+elned+j) = nv+ned+fanums.Elem(j);
+	  nnums.Elem(elnv+elned+elnfa+1) = nv+ned+nfa+i;
+
+	  
+	  const int * clustertab = NULL;
+	  switch (typ)
+	    {
+	    case PRISM:
+	    case PRISM12:
+	      clustertab = prism_cluster;
+	      break;
+	    case HEX: 
+	      clustertab = hex_cluster; 
+	      break; 
+	    case PYRAMID:
+	      clustertab = pyramid_cluster;
+	      break;
+	    case TET:
+	    case TET10:
+	      if (cluster_reps.Get(el.PNum(1)) == 
+		  cluster_reps.Get(el.PNum(2)))
+		clustertab = tet_cluster12;
+	      else if (cluster_reps.Get(el.PNum(1)) == 
+		       cluster_reps.Get(el.PNum(3)))
+		clustertab = tet_cluster13;
+	      else if (cluster_reps.Get(el.PNum(1)) == 
+		       cluster_reps.Get(el.PNum(4)))
+		clustertab = tet_cluster14;
+	      else if (cluster_reps.Get(el.PNum(2)) == 
+		       cluster_reps.Get(el.PNum(3)))
+		clustertab = tet_cluster23;
+	      else if (cluster_reps.Get(el.PNum(2)) == 
+		       cluster_reps.Get(el.PNum(4)))
+		clustertab = tet_cluster24;
+	      else if (cluster_reps.Get(el.PNum(3)) == 
+		       cluster_reps.Get(el.PNum(4)))
+		clustertab = tet_cluster34;
+
+	      else
+		clustertab = NULL;
+	      break;
+	    default:
+	      clustertab = NULL;
+	    }
+	  
+	  if (clustertab)
+	    for (j = 0; j < nnums.Size(); j++)
+	      for (k = 0; k < j; k++)
+		if (clustertab[j] == clustertab[k])
+		  {
+		    int jj = nnums[j];
+		    int kk = nnums[k];
+		    if (cluster_reps.Get(jj) < cluster_reps.Get(kk))
+		      {
+			cluster_reps.Elem(kk) = cluster_reps.Get(jj);
+			changed = 1;
+		      }
+		    else if (cluster_reps.Get(kk) < cluster_reps.Get(jj))
+		      {
+			cluster_reps.Elem(jj) = cluster_reps.Get(kk);
+			changed = 1;
+		      }
+		  }
+
+	  /*
+	  if (clustertab)
+	    {
+	      if (typ == PYRAMID)
+		(*testout) << "pyramid";
+	      else if (typ == PRISM || typ == PRISM12)
+		(*testout) << "prism";
+	      else if (typ == TET || typ == TET10)
+		(*testout) << "tet";
+	      else
+		(*testout) << "unknown type" << endl;
+		
+	      (*testout) << ", nnums  = ";
+	      for (j = 0; j < nnums.Size(); j++)
+		(*testout) << "node " << j << " = " << nnums[j] << ", rep = "
+			   << cluster_reps.Get(nnums[j]) << endl;
+	    }
+	  */
+	}
+    }
+  while (changed);
+
+  /*
+    (*testout) << "cluster reps:" << endl;
+    for (i = 1; i <= cluster_reps.Size(); i++)
+    {
+    (*testout) << i << ": ";
+    if (i <= nv)
+    (*testout) << "v" << i << " ";
+    else if (i <= nv+ned)
+    (*testout) << "e" << i-nv << " ";
+    else if (i <= nv+ned+nfa)
+    (*testout) << "f" << i-nv-ned << " ";
+    else
+    (*testout) << "c" << i-nv-ned-nfa << " ";
+    (*testout) << cluster_reps.Get(i) << endl;
+    }
+  */
+}
+}
diff --git a/contrib/Netgen/libsrc/meshing/clusters.hpp b/contrib/Netgen/libsrc/meshing/clusters.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..b0eea1b5e02b06a43fe4f9332029fe20574dea7e
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/clusters.hpp
@@ -0,0 +1,42 @@
+#ifndef CLUSTERS
+#define CLUSTERS
+
+/**************************************************************************/
+/* File:   clusers.hh                                                     */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   28. Apr. 01                                                    */
+/**************************************************************************/
+
+/*
+  Anisotropic clusters
+
+  nodes, edges, faces, elements
+*/
+
+
+class AnisotropicClusters
+{
+  const Mesh & mesh;
+
+  int nv, ned, nfa, ne;
+
+  // connected nodes, nodes = vertices, edges, faces, elements
+  ARRAY<int> cluster_reps;
+
+public:
+  AnisotropicClusters (const Mesh & amesh);
+  ~AnisotropicClusters();
+
+  void Update();
+
+  int GetVertexRepresentant (int vnr) const
+  { return cluster_reps.Get(vnr); }
+  int GetEdgeRepresentant (int ednr) const
+  { return cluster_reps.Get(nv+ednr); }
+  int GetFaceRepresentant (int fnr) const
+  { return cluster_reps.Get(nv+ned+fnr); }
+  int GetElementRepresentant (int enr) const
+  { return cluster_reps.Get(nv+ned+nfa+enr); }
+};
+
+#endif
diff --git a/contrib/Netgen/libsrc/meshing/curvedelems.cpp b/contrib/Netgen/libsrc/meshing/curvedelems.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..6db15893ae44b8d8299aabae40e42cdda4a5f7d3
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/curvedelems.cpp
@@ -0,0 +1,2899 @@
+#include <mystdlib.h>
+
+#include "meshing.hpp"
+#ifndef CURVEDELEMS_NEW
+
+namespace netgen
+{
+    
+    
+  // computes Gaussean integration formula on (0,1) with n points
+  // in: Numerical algs in C (or, was it the Fortran book ?)
+  void ComputeGaussRule (int n, ARRAY<double> & xi, ARRAY<double> & wi)
+  {
+    xi.SetSize (n);
+    wi.SetSize (n);
+	
+    int m = (n+1)/2;
+    double p1, p2, p3;
+    double pp, z, z1;
+    for (int i = 1; i <= m; i++)
+      {
+	z = cos ( M_PI * (i - 0.25) / (n + 0.5));
+	while(1)
+	  {
+	    p1 = 1; p2 = 0;
+	    for (int j = 1; j <= n; j++)
+	      {
+		p3 = p2; p2 = p1;
+		p1 = ((2 * j - 1) * z * p2 - (j - 1) * p3) / j;
+	      }
+	    // p1 is legendre polynomial
+
+	    pp = n * (z*p1-p2) / (z*z - 1);
+	    z1 = z;
+	    z = z1-p1/pp;
+
+	    if (fabs (z - z1) < 1e-14) break;
+	  }
+
+	xi[i-1] = 0.5 * (1 - z);
+	xi[n-i] = 0.5 * (1 + z);
+	wi[i-1] = wi[n-i] = 1.0 / ( (1  - z * z) * pp * pp);
+      }
+  }
+
+
+
+  // ----------------------------------------------------------------------------
+  //      PolynomialBasis
+  // ----------------------------------------------------------------------------
+
+
+  void PolynomialBasis :: CalcLegendrePolynomials (double x)
+  {
+    double p1 = 1.0, p2 = 0.0, p3;
+
+    lp[0] = 1.0;
+
+    for (int j=1; j<=order; j++)
+      {
+	p3=p2; p2=p1;
+	p1=((2.0*j-1.0)*(2*x-1)*p2-(j-1.0)*p3)/j;
+	lp[j] = p1;
+      }
+  }
+
+
+  void PolynomialBasis :: CalcScaledLegendrePolynomials (double x, double t)
+  {
+    double p1 = 1.0, p2 = 0.0, p3;
+
+    lp[0] = 1.0;
+	
+    double x2mt = 2*x-t;
+    double t2 = t*t;
+
+    for (int j=1; j<=order; j++)
+      {
+	p3=p2; p2=p1;
+	p1=((2.0*j-1.0)*x2mt*p2-t2*(j-1.0)*p3)/j;
+	lp[j] = p1;
+      }
+  }
+
+
+  void PolynomialBasis :: CalcDLegendrePolynomials (double x)
+  {
+    double p1 = 0., p2 = 0., p3;
+
+    dlp[0] = 0.;
+
+    for (int j = 1; j <= order-1; j++)
+      {
+	p3=p2; p2=p1;
+	p1=((2.*j-1.)*(2*lp[j-1]+(2*x-1)*p2)-(j-1.)*p3)/j;
+	dlp[j] = p1;
+      }
+  }
+
+
+  void PolynomialBasis :: CalcF (double x)
+  {
+    CalcLegendrePolynomials (x);
+
+    for (int j = 0; j<=order-2; j++)
+      f[j] = (lp[j+2]-lp[j])/(2.0*(j+1)+1)/2.0;
+  }
+
+
+  void PolynomialBasis :: CalcDf (double x)
+  {
+    CalcLegendrePolynomials (x);
+
+    for (int j = 0; j <= order-2; j++)
+      df[j] = lp[j+1];
+  }
+
+
+  void PolynomialBasis :: CalcFDf (double x)
+  {
+    CalcLegendrePolynomials (x);
+
+    for (int j = 0; j<=order-2; j++)
+      {
+	f[j] = (lp[j+2]-lp[j])/(2.0*(j+1)+1)/2.0;
+	df[j] = lp[j+1];
+      }
+  }
+
+
+  void PolynomialBasis :: CalcDDf (double x)
+  {
+    CalcLegendrePolynomials (x);
+    CalcDLegendrePolynomials (x);
+
+    for (int j = 0; j <= order-2; j++) ddf[j] = dlp[j+1];
+  }
+
+
+  void PolynomialBasis :: CalcFScaled (double x, double t)
+  {
+    double tt = t*t;
+    double x2mt = 2*x-t;
+
+
+      
+
+    double p1 = 0.5*x2mt, p2 = -0.5, p3 = 0.0;
+    for (int j=2; j<=order; j++)
+      {
+	p3=p2; p2=p1;
+	p1=((2.0*j-3.0) * x2mt * p2 - tt*(j-3.0)*p3)/j;
+	f[j-2] = p1;
+      }
+
+    /*
+      CalcF (x/t);
+      double fac = t*t;
+      for (int j = 0; j<=order-2; j++, fac*=t) 
+      f[j] *= fac;
+    */
+  }
+
+  void PolynomialBasis :: CalcFScaled (int p, double x, double t, double * values)
+  {
+    double tt = t*t;
+    double x2mt = 2*x-t;
+    
+    double p1 = 0.5*x2mt, p2 = -0.5, p3 = 0.0;
+    for (int j=2; j<=p; j++)
+      {
+	p3=p2; p2=p1;
+	p1=((2.0*j-3.0) * x2mt * p2 - tt*(j-3.0)*p3)/j;
+	values[j-2] = p1;
+      }
+    
+    /*
+      CalcF (x/t);
+      double fac = t*t;
+      for (int j = 0; j<=order-2; j++, fac*=t) 
+      f[j] *= fac;
+    */
+  }
+
+
+
+
+  // ----------------------------------------------------------------------------
+  //      BaseFiniteElement1D
+  // ----------------------------------------------------------------------------
+
+
+  void BaseFiniteElement1D :: CalcVertexShapes ()
+  {
+    vshape[0] = xi(0);
+    vshape[1] = 1-xi(0);
+
+    vdshape[0] = 1;
+    vdshape[1] = -1;
+
+    /*
+      if (edgeorient == -1)
+      {
+      Swap (vshape[0], vshape[1]);
+      Swap (vdshape[0], vdshape[1]);
+      }
+    */
+	
+  }
+
+
+  void BaseFiniteElement1D :: CalcEdgeShapes ()
+  {
+    b.SetOrder (edgeorder);
+    if (edgeorient == 1)
+      b.CalcFDf( 1-xi(0) );
+    else
+      b.CalcFDf( xi(0) );
+
+    for (int k = 2; k <= edgeorder; k++)
+      {
+	eshape[k-2] = b.GetF(k);
+	edshape[k-2] = -b.GetDf(k);
+      }
+  }
+
+
+  void BaseFiniteElement1D :: CalcEdgeLaplaceShapes ()
+  {
+    b.SetOrder (edgeorder);
+    if (edgeorient == 1)
+      b.CalcDDf( 1-xi(0) );
+    else
+      b.CalcDDf( xi(0) );
+
+    for (int k = 2; k <= edgeorder; k++)
+      eddshape[k-2] = b.GetDDf(k);
+  }
+
+
+
+
+  // ----------------------------------------------------------------------------
+  //      BaseFiniteElement2D
+  // ----------------------------------------------------------------------------
+
+
+  void BaseFiniteElement2D :: SetElementNumber (int aelnr)
+  {
+    int locmaxedgeorder = -1;
+	
+    BaseFiniteElement<2> :: SetElementNumber (aelnr);
+    const Element2d & elem = mesh[(SurfaceElementIndex) (elnr-1)]; 
+    top.GetSurfaceElementEdges (elnr, &(edgenr[0]), &(edgeorient[0]));
+    facenr = top.GetSurfaceElementFace (elnr);
+    faceorient = top.GetSurfaceElementFaceOrientation (elnr);
+	
+    for (int v = 0; v < nvertices; v++)
+      vertexnr[v] = elem[v];
+	
+    for (int e = 0; e < nedges; e++)
+      {
+	edgeorder[e] = curv.GetEdgeOrder (edgenr[e]-1); // 1-based
+	locmaxedgeorder = max2 (edgeorder[e], locmaxedgeorder);
+      }
+	
+    faceorder = curv.GetFaceOrder (facenr-1); // 1-based
+    CalcNFaceShapes ();
+	
+    if (locmaxedgeorder > maxedgeorder)
+      {
+	maxedgeorder = locmaxedgeorder;
+	eshape.SetSize(nedges * (maxedgeorder-1));
+	edshape.SetSize(nedges * (maxedgeorder-1));
+      }
+	
+    if (faceorder > maxfaceorder)
+      {
+	maxfaceorder = faceorder;
+	fshape.SetSize( nfaceshapes ); // number of face shape functions
+	fdshape.SetSize( nfaceshapes );
+	fddshape.SetSize ( nfaceshapes );
+      }
+  };
+    
+
+  // ----------------------------------------------------------------------------
+  //      BaseFiniteElement3D
+  // ----------------------------------------------------------------------------
+
+
+  void BaseFiniteElement3D :: SetElementNumber (int aelnr)
+  {
+    int locmaxedgeorder = -1;
+    int locmaxfaceorder = -1;
+    int v, f, e;
+
+    BaseFiniteElement<3> :: SetElementNumber (aelnr);
+    Element elem = mesh[(ElementIndex) (elnr-1)];
+    top.GetElementEdges (elnr, &(edgenr[0]), &(edgeorient[0]));
+    top.GetElementFaces (elnr, &(facenr[0]), &(faceorient[0]));
+	
+    for (v = 0; v < nvertices; v++)
+      vertexnr[v] = elem[v];
+	
+    for (f = 0; f < nfaces; f++)
+      {
+	surfacenr[f] = top.GetFace2SurfaceElement (facenr[f]);
+	// surfaceorient[f] = top.GetSurfaceElementFaceOrientation (surfacenr[f]);
+      }
+	
+    for (e = 0; e < nedges; e++)
+      {
+	edgeorder[e] = curv.GetEdgeOrder (edgenr[e]-1); // 1-based
+	locmaxedgeorder = max (edgeorder[e], locmaxedgeorder);
+      }
+	
+    for (f = 0; f < nfaces; f++)
+      {
+	faceorder[f] = curv.GetFaceOrder (facenr[f]-1); // 1-based
+	locmaxfaceorder = max (faceorder[f], locmaxfaceorder);
+      }
+	
+    CalcNFaceShapes ();
+	
+    if (locmaxedgeorder > maxedgeorder)
+      {
+	maxedgeorder = locmaxedgeorder;
+	eshape.SetSize(nedges * (maxedgeorder-1));
+	edshape.SetSize(nedges * (maxedgeorder-1));
+      }
+	
+    if (locmaxfaceorder > maxfaceorder)
+      {
+	maxfaceorder = locmaxfaceorder;
+	fshape.SetSize( nfaces * (maxfaceorder-1) * (maxfaceorder-1)); // number of face shape functions
+	fdshape.SetSize( nfaces * (maxfaceorder-1) * (maxfaceorder-1));
+      }
+  };
+    
+    
+
+
+  // ----------------------------------------------------------------------------
+  //      FETrig
+  // ----------------------------------------------------------------------------
+
+
+  void FETrig :: SetReferencePoint (Point<2> axi)
+  {
+    BaseFiniteElement2D :: SetReferencePoint (axi);
+    lambda(0) = xi(0);
+    lambda(1) = xi(1);
+    lambda(2) = 1-xi(0)-xi(1);
+
+    dlambda(0,0) =  1; dlambda(0,1) =  0;
+    dlambda(1,0) =  0; dlambda(1,1) =  1;
+    dlambda(2,0) = -1; dlambda(2,1) = -1;
+  }
+
+
+  void FETrig :: SetVertexSingularity (int v, int exponent)
+  {
+    int i;
+    if (1-lambda(v) < EPSILON) return;
+
+    Point<3> lamold = lambda;
+
+    Vec<2> dfac;
+
+    double fac = pow(1-lambda(v),exponent-1);
+
+    for (i = 0; i < 2; i++)
+      {
+	dfac(i) = -(exponent-1)*pow(1-lambda(v),exponent-2)*dlambda(v,i);
+	dlambda(v,i) *= exponent * pow(1-lambda(v),exponent-1);
+      }
+
+    lambda(v) = 1-pow(1-lambda(v),exponent);
+
+    for (i = 0; i < nvertices; i++)
+      {
+	if (i == v) continue;
+	for (int j = 0; j < 2; j++)
+	  dlambda(i,j) = dlambda(i,j) * fac + lamold(i) * dfac(j);
+
+	lambda(i) *= fac;
+      }
+  }
+
+
+
+  void FETrig :: CalcVertexShapes ()
+  {
+    for (int v = 0; v < nvertices; v++)
+      {
+	vshape[v] = lambda(v);
+	vdshape[v](0) = dlambda(v,0);
+	vdshape[v](1) = dlambda(v,1);
+      }
+  }
+
+
+  void FETrig :: CalcEdgeShapes ()
+  {
+    int index = 0;
+    for (int e = 0; e < nedges; e++)
+      {
+	if (edgeorder[e] <= 1) continue;
+
+	int i0 = eledge[e][0]-1;
+	int i1 = eledge[e][1]-1;
+
+	double arg = lambda(i0) + lambda(i1); // = 1-lambda[i2];
+
+	if (fabs(arg) < EPSILON) // division by 0
+	  {
+	    for (int k = 2; k <= edgeorder[e]; k++)
+	      {
+		eshape[index] = 0;
+		edshape[index] = Vec<2>(0,0);
+		index++;
+	      }
+	    continue;
+	  }
+
+	if (edgeorient[e] == -1) Swap (i0, i1); // reverse orientation
+
+	double xi = lambda(i1)/arg;
+
+	b1.SetOrder (edgeorder[e]);
+	b1.CalcFDf (xi);
+
+	double decay = arg;
+	double ddecay;
+	    
+	double l0 = lambda(i0);
+	double l0x = dlambda(i0,0);
+	double l0y = dlambda(i0,1);
+
+	double l1 = lambda(i1);
+	double l1x = dlambda(i1,0);
+	double l1y = dlambda(i1,1);
+
+	for (int k = 2; k <= edgeorder[e]; k++)
+	  {        
+	    ddecay = k*decay;
+	    decay *= arg;
+		
+	    eshape[index] = b1.GetF (k) * decay;
+	    edshape[index] = Vec<2>
+	      (b1.GetDf(k) * (l1x*arg - l1*(l0x+l1x)) * 
+	       decay / (arg * arg) + b1.GetF(k) * ddecay * (l0x+l1x),
+	       b1.GetDf(k) * (l1y*arg - l1*(l0y+l1y)) *
+	       decay / (arg * arg) + b1.GetF(k) * ddecay * (l0y+l1y));
+	    index++;
+	  }
+      }
+    // (*testout) << "index = " << index << endl;
+    // (*testout) << "eshape = " << eshape << ", edshape = " << edshape << endl;
+
+
+    // eshape = 0.0;
+    //	edshape = 0.0;
+
+    /*
+      int index = 0;
+      for (int e = 0; e < nedges; e++)
+      {
+      if (edgeorder[e] <= 1) continue;
+
+      int i0 = eledge[e][0]-1;
+      int i1 = eledge[e][1]-1;
+
+      if (edgeorient[e] == -1) Swap (i0, i1); // reverse orientation
+	    
+      double x = lambda(i1)-lambda(i0);
+      double y = 1-lambda(i0)-lambda(i1);
+      double fy = (1-y)*(1-y);
+
+      // double p3 = 0, p3x = 0, p3y = 0;
+      // double p2 = -1, p2x = 0, p2y = 0;
+      // double p1 = x, p1x = 1, p1y = 0;
+
+      double p3 = 0, p3x = 0, p3y = 0;
+      double p2 = -0.5, p2x = 0, p2y = 0;
+      double p1 = 0.5*x, p1x = 0.5, p1y = 0;
+
+      for (int j=2; j<= edgeorder[e]; j++)
+      {
+      p3=p2; p3x = p2x; p3y = p2y;
+      p2=p1; p2x = p1x; p2y = p1y;
+      double c1 = (2.0*j-3) / j;
+      double c2 = (j-3.0) / j;
+		
+      p1  = c1 * x * p2 - c2 * fy * p3;
+      p1x = c1 * p2 + c1 * x * p2x - c2 * fy * p3x;
+      p1y = c1 * x * p2y - (c2 * 2 * (y-1) * p3 + c2 * fy * p3y);
+
+      eshape[index] = p1;
+      for (int k = 0; k < 2; k++)
+      edshape[index](k) = 
+      p1x * ( dlambda(i1,k) - dlambda(i0,k) ) + 
+      p1y * (-dlambda(i1,k) - dlambda(i0,k) );
+      index++;
+      }    
+
+      }
+      // (*testout) << "eshape = " << eshape << ", edshape = " << edshape << endl;
+      */
+  }
+
+
+  void FETrig :: CalcFaceShapes ()
+  {
+    int index = 0;
+
+    int i0 = elface[0][0]-1;
+    int i1 = elface[0][1]-1;
+    int i2 = elface[0][2]-1;
+
+    // sort lambda_i's by the corresponing vertex numbers
+
+    if (vertexnr[i1] < vertexnr[i0]) Swap (i0, i1);
+    if (vertexnr[i2] < vertexnr[i0]) Swap (i0, i2);
+    if (vertexnr[i2] < vertexnr[i1]) Swap (i1, i2);
+
+    double arg = lambda(i1) + lambda(i2);
+
+    if (fabs(arg) < EPSILON) // division by 0
+      {
+	for (int k = 0; k < nfaceshapes; k++)
+	  {
+	    fshape[index] = 0;
+	    fdshape[index] = Vec<2>(0,0);
+	    index++;
+	  }
+	return;
+      }
+
+    b1.SetOrder (faceorder);
+    b2.SetOrder (faceorder);
+
+    b1.CalcFDf (lambda(i0));
+    b2.CalcFDf (lambda(i2)/arg);
+
+    double decay = 1;
+    double ddecay;
+
+    double l0 = lambda(i0);
+    double l1 = lambda(i1);
+    double l2 = lambda(i2);
+    double dl0x = dlambda(i0,0);
+    double dl0y = dlambda(i0,1);
+    double dl1x = dlambda(i1,0);
+    double dl1y = dlambda(i1,1);
+    double dl2x = dlambda(i2,0);
+    double dl2y = dlambda(i2,1);
+
+    double dargx = dl1x + dl2x;
+    double dargy = dl1y + dl2y;
+
+    for (int n1 = 2; n1 < faceorder; n1++)
+      {
+	ddecay = (n1-1)*decay;
+	decay *= arg;
+	    
+	for (int n0 = 2; n0 < faceorder-n1+2; n0++)
+	  {
+	    fshape[index] = b1.GetF(n0) * b2.GetF(n1) * decay;
+	    fdshape[index] = Vec<2>
+	      (b1.GetDf(n0) * dl0x * b2.GetF(n1) * decay +
+	       b1.GetF(n0) * b2.GetDf(n1) * (dl2x * arg - l2 * dargx)/(arg*arg) * decay +
+	       b1.GetF(n0) * b2.GetF(n1) * ddecay * dargx,
+	       b1.GetDf(n0) * dl0y * b2.GetF(n1) * decay +
+	       b1.GetF(n0) * b2.GetDf(n1) * (dl2y * arg - l2 * dargy)/(arg*arg) * decay +
+	       b1.GetF(n0) * b2.GetF(n1) * ddecay * dargy);
+	    index++;
+	  }
+      }
+  }
+
+
+
+  void FETrig :: CalcFaceLaplaceShapes ()
+  {
+    int index = 0;
+
+    int i0 = elface[0][0]-1;
+    int i1 = elface[0][1]-1;
+    int i2 = elface[0][2]-1;
+
+    if (vertexnr[i1] < vertexnr[i0]) Swap (i0, i1);
+    if (vertexnr[i2] < vertexnr[i0]) Swap (i0, i2);
+    if (vertexnr[i2] < vertexnr[i1]) Swap (i1, i2);
+
+    double arg = lambda(i1) + lambda(i2);
+
+    if (fabs(arg) < EPSILON) // division by 0
+      {
+	for (int k = 0; k < nfaceshapes; k++)
+	  fddshape[k] = 0;
+	return;
+      }
+
+    b1.SetOrder (faceorder);
+    b2.SetOrder (faceorder);
+
+    b1.CalcFDf (lambda(i0));
+    b1.CalcDDf (lambda(i0));
+    b2.CalcFDf (lambda(i2)/arg);
+    b2.CalcDDf (lambda(i2)/arg);
+
+    double decay = 1;
+    double ddecay = 0;
+    double dddecay;
+
+    double l0 = lambda(i0);
+    double l1 = lambda(i1);
+    double l2 = lambda(i2);
+    double dl0x = dlambda(i0,0);
+    double dl0y = dlambda(i0,1);
+    double dl1x = dlambda(i1,0);
+    double dl1y = dlambda(i1,1);
+    double dl2x = dlambda(i2,0);
+    double dl2y = dlambda(i2,1);
+
+    double dargx = dl1x + dl2x;
+    double dargy = dl1y + dl2y;
+
+    for (int n1 = 2; n1 < faceorder; n1++)
+      {
+	dddecay = (n1-1)*ddecay;
+	ddecay = (n1-1)*decay;
+	decay *= arg;
+	    
+	for (int n0 = 2; n0 < faceorder-n1+2; n0++)
+	  {
+	    fddshape[index] = 
+
+	      //  b1.GetDf(n0) * dl0x * b2.GetF(n1) * decay .... derived
+
+	      b1.GetDDf(n0) * dl0x * dl0x * b2.GetF(n1) * decay +
+	      b1.GetDf(n0) * dl0x * b2.GetDf(n1) * (dl2x * arg - l2 * dargx)/(arg*arg) * decay +
+	      b1.GetDf(n0) * dl0x * b2.GetF(n1) * ddecay * dargx +
+
+		    
+	      //  b1.GetF(n0) * b2.GetDf(n1) * (dl2x * arg - l2 * dargx)/(arg*arg) * decay ... derived
+
+	      b1.GetDf(n0) * dl0x * b2.GetDf(n1) * (dl2x * arg - l2 * dargx)/(arg*arg) * decay +
+	      b1.GetF(n0) * b2.GetDDf(n1) * pow((dl2x * arg - l2 * dargx)/(arg*arg),2) * decay +
+	      b1.GetF(n0) * b2.GetDf(n1) * (-2*dargx/arg) * (dl2x * arg - l2 * dargx)/(arg*arg) * decay +
+	      b1.GetF(n0) * b2.GetDf(n1) * (dl2x * arg - l2 * dargx)/(arg*arg) * ddecay * dargx +
+
+		    
+	      //  b1.GetF(n0) * b2.GetF(n1) * ddecay * dargx ... derived
+
+	      b1.GetDf(n0) * dl0x * b2.GetF(n1) * ddecay * dargx +
+	      b1.GetF(n0) * b2.GetDf(n1) * (dl2x * arg - l2 * dargx)/(arg*arg) * ddecay * dargx +
+	      b1.GetF(n0) * b2.GetF(n1) * dddecay * dargx * dargx +
+
+		    
+	      //  b1.GetDf(n0) * dl0y * b2.GetF(n1) * decay ... derived
+
+	      b1.GetDDf(n0) * dl0y * dl0y * b2.GetF(n1) * decay +
+	      b1.GetDf(n0) * dl0y * b2.GetDf(n1) * (dl2y * arg - l2 * dargy)/(arg*arg) * decay +
+	      b1.GetDf(n0) * dl0y * b2.GetF(n1) * ddecay * dargy +
+		    
+
+	      //  b1.GetF(n0) * b2.GetDf(n1) * (dl2y * arg - l2 * dargy)/(arg*arg) * decay ... derived
+
+	      b1.GetDf(n0) * dl0y * b2.GetDf(n1) * (dl2y * arg - l2 * dargy)/(arg*arg) * decay +
+	      b1.GetF(n0) * b2.GetDDf(n1) * pow((dl2y * arg - l2 * dargy)/(arg*arg),2) * decay +
+	      b1.GetF(n0) * b2.GetDf(n1) * (-2*dargy/arg) * (dl2y * arg - l2 * dargy)/(arg*arg) * decay +
+	      b1.GetF(n0) * b2.GetDf(n1) * (dl2y * arg - l2 * dargy)/(arg*arg) * ddecay * dargy +
+		    
+
+	      //  b1.GetF(n0) * b2.GetF(n1) * ddecay * dargy ... derived
+
+	      b1.GetDf(n0) * dl0y * b2.GetF(n1) * ddecay * dargy +
+	      b1.GetF(n0) * b2.GetDf(n1) * (dl2y * arg - l2 * dargy)/(arg*arg) * ddecay * dargy +
+	      b1.GetF(n0) * b2.GetF(n1) * dddecay * dargy * dargy;
+
+	    index++;
+	  }
+      }
+  }
+
+
+
+  // ----------------------------------------------------------------------------
+  //      FEQuad
+  // ----------------------------------------------------------------------------
+
+
+  void FEQuad :: CalcVertexShapes ()
+  {
+    vshape[0] = (1-xi(0)) * (1-xi(1));
+    vshape[1] = (  xi(0)) * (1-xi(1));
+    vshape[2] = (  xi(0)) * (  xi(1));
+    vshape[3] = (1-xi(0)) * (  xi(1));
+
+    vdshape[0] = Vec<2> ( -(1-xi(1)), -(1-xi(0)) );
+    vdshape[1] = Vec<2> (  (1-xi(1)), -(  xi(0)) );
+    vdshape[2] = Vec<2> (  (  xi(1)),  (  xi(0)) );
+    vdshape[3] = Vec<2> ( -(  xi(1)),  (1-xi(0)) );
+  }
+
+
+  void FEQuad :: CalcEdgeShapes ()
+  {
+    int index = 0;
+
+    double arg0[4] = { xi(0), 1-xi(0), 1-xi(1), xi(1) };
+    double arg1[4] = { 1-xi(1), xi(1), 1-xi(0), xi(0) };
+    double darg0[4] = {  1, -1, -1,  1 };
+    double darg1[4] = { -1,  1, -1,  1 };
+	
+    for (int e = 0; e < nedges; e++)
+      {
+	b1.SetOrder (edgeorder[e]);
+	b1.CalcFDf (edgeorient[e] == 1 ? arg0[e] : 1-arg0[e]);
+
+	double decay = arg1[e];
+	double ddecay;
+
+	for (int k = 2; k <= edgeorder[e]; k++, index++)
+	  {
+	    ddecay = k*decay;
+	    decay *= arg1[e];
+	    // linear decay
+	    eshape[index] = b1.GetF(k) * arg1[e];
+
+	    if (e < 2)
+	      edshape[index] = Vec<2>
+		(darg0[e] * edgeorient[e] * b1.GetDf(k) * arg1[e],
+		 b1.GetF(k) * darg1[e]);
+	    else
+	      edshape[index] = Vec<2>
+		(b1.GetF(k) * darg1[e],
+		 darg0[e] * edgeorient[e] * b1.GetDf(k) * arg1[e]);
+
+	    // exponential decay
+	    /*		eshape[index] = b1.GetF(k) * decay;
+
+	    if (e < 2)
+	    edshape[index] = Vec<2>
+	    (darg0[e] * edgeorient[e] * b1.GetDf(k) * decay,
+	    b1.GetF(k) * ddecay * darg1[e]);
+	    else
+	    edshape[index] = Vec<2>
+	    (b1.GetF(k) * ddecay * darg1[e],
+	    darg0[e] * edgeorient[e] * b1.GetDf(k) * decay);
+	    */
+	  }
+      }
+  }
+
+
+  void FEQuad :: CalcFaceShapes ()
+  {
+    int index = 0;
+
+    // find index of point with smallest number
+
+    int i0 = 0;
+    for (int i = 1; i < 4; i++)
+      if (vertexnr[elface[0][i]-1] < vertexnr[elface[0][i0]-1]) i0 = i;
+
+    double x;
+    double y;
+    double dxx;
+    double dxy;
+    double dyx;
+    double dyy;
+
+    switch (i0)
+      {
+      case 0:
+	x = xi(0); y = xi(1);
+	dxx = 1; dxy = 0;
+	dyx = 0; dyy = 1;
+	break;
+      case 1:
+	x = xi(1); y = 1-xi(0);
+	dxx = 0; dxy = 1;
+	dyx = -1; dyy = 0;
+	break;
+      case 2: 
+	x = 1-xi(0); y = 1-xi(1);
+	dxx = -1; dxy = 0;
+	dyx = 0; dyy = -1;
+	break;
+      case 3:
+	x = 1-xi(1); y = xi(0);
+	dxx = 0; dxy =-1;
+	dyx = 1; dyy = 0;
+	break;
+      }
+
+    if (vertexnr[elface[0][(i0+1) % 4]-1] > vertexnr[elface[0][(i0+3) % 4]-1]) 
+      {
+	Swap (x,y);
+	Swap (dxx, dyx);
+	Swap (dxy, dyy);
+      }
+
+    b1.SetOrder (faceorder);
+    b2.SetOrder (faceorder);
+
+    b1.CalcFDf (x);
+    b2.CalcFDf (y);
+
+    for (int n0 = 2; n0 <= faceorder; n0++)
+      for (int n1 = 2; n1 <= faceorder; n1++)
+	{
+	  fshape[index] = b1.GetF(n0) * b2.GetF(n1);
+	  fdshape[index] = Vec<2> (b1.GetDf(n0) * dxx * b2.GetF(n1) + b1.GetF(n0) * b2.GetDf(n1) * dyx,
+				   b1.GetDf(n0) * dxy * b2.GetF(n1) + b1.GetF(n0) * b2.GetDf(n1) * dyy);
+	  index++;
+	}
+  }
+
+
+  void FEQuad :: CalcFaceLaplaceShapes ()
+  {
+    int index = 0;
+
+    // find index of point with smallest number
+
+    int i0 = 0;
+    for (int i = 1; i < 4; i++)
+      if (vertexnr[elface[0][i]-1] < vertexnr[elface[0][i0]-1]) i0 = i;
+
+    double x;
+    double y;
+    double dxx;
+    double dxy;
+    double dyx;
+    double dyy;
+
+    switch (i0)
+      {
+      case 0:
+	x = xi(0); y = xi(1);
+	dxx = 1; dxy = 0;
+	dyx = 0; dyy = 1;
+	break;
+      case 1:
+	x = xi(1); y = 1-xi(0);
+	dxx = 0; dxy = 1;
+	dyx = -1; dyy = 0;
+	break;
+      case 2: 
+	x = 1-xi(0); y = 1-xi(1);
+	dxx = -1; dxy = 0;
+	dyx = 0; dyy = -1;
+	break;
+      case 3:
+	x = 1-xi(1); y = xi(0);
+	dxx = 0; dxy =-1;
+	dyx = 1; dyy = 0;
+	break;
+      }
+
+    if (vertexnr[elface[0][(i0+1) % 4]-1] > vertexnr[elface[0][(i0+3) % 4]-1]) 
+      {
+	Swap (x,y);
+	Swap (dxx, dyx);
+	Swap (dxy, dyy);
+      }
+
+    b1.SetOrder (faceorder);
+    b2.SetOrder (faceorder);
+
+    b1.CalcFDf (x);
+    b1.CalcDDf (x);
+    b2.CalcFDf (y);
+    b2.CalcDDf (y);
+
+    for (int n0 = 2; n0 <= faceorder; n0++)
+      for (int n1 = 2; n1 <= faceorder; n1++)
+	{
+	  fddshape[index] =
+	    b1.GetDDf(n0) * dxx * dxx * b2.GetF(n1) +
+	    2*  b1.GetDf(n0) * dxx * b2.GetDf(n1) * dyx +
+	    b1.GetF(n0) * b2.GetDDf(n1) * dyx * dyx +
+
+	    b1.GetDDf(n0) * dxy * dxy * b2.GetF(n1) +
+	    2*  b1.GetDf(n0) * dxy * b2.GetDf(n1) * dyy +
+	    b1.GetF(n0) * b2.GetDDf(n1) * dyy * dyy;
+
+	  index++;
+	}
+  }
+
+
+
+  // ----------------------------------------------------------------------------
+  //      FETet
+  // ----------------------------------------------------------------------------
+
+
+  void FETet :: SetReferencePoint (Point<3> axi)
+  {
+    BaseFiniteElement3D :: SetReferencePoint (axi);
+	
+    lambda(0) = xi(0);
+    lambda(1) = xi(1);
+    lambda(2) = xi(2);
+    lambda(3) = 1-xi(0)-xi(1)-xi(2);
+
+    dlambda(0,0) =  1; dlambda(0,1) =  0; dlambda(0,2) =   0;
+    dlambda(1,0) =  0; dlambda(1,1) =  1; dlambda(1,2) =   0;
+    dlambda(2,0) =  0; dlambda(2,1) =  0; dlambda(2,2) =   1;
+    dlambda(3,0) = -1; dlambda(3,1) = -1; dlambda(3,2) =  -1;
+  }
+
+
+  void FETet :: CalcVertexShapes ()
+  {
+    for (int v = 0; v < nvertices; v++)
+      {
+	vshape[v] = lambda(v);
+	vdshape[v](0) = dlambda(v,0);
+	vdshape[v](1) = dlambda(v,1);
+	vdshape[v](2) = dlambda(v,2);
+      }
+  }
+
+  void FETet :: CalcVertexShapesOnly ()
+  {
+    for (int v = 0; v < nvertices; v++)
+      vshape[v] = lambda(v);
+  }
+
+
+  void FETet :: CalcEdgeShapes ()
+  {
+    int index = 0;
+
+    for (int e = 0; e < nedges; e++)
+      {
+	int i0 = eledge[e][0]-1;
+	int i1 = eledge[e][1]-1;
+
+	double arg = lambda(i0)+lambda(i1);
+
+	if (fabs(arg) < EPSILON) // division by 0
+	  {
+	    for (int k = 2; k <= edgeorder[e]; k++)
+	      {
+		eshape[index] = 0;
+		edshape[index] = Vec<3>(0,0,0);
+		index++;
+	      }
+	    continue;
+	  }
+
+	if (edgeorient[e] == -1) Swap (i0, i1);
+
+	double xi = lambda[i1]/arg;
+
+	b1.SetOrder (edgeorder[e]);
+	b1.CalcFDf (xi);
+
+	double decay = arg;
+	double ddecay;
+	    
+	double l0 = lambda(i0);
+	double dl0x = dlambda(i0,0);
+	double dl0y = dlambda(i0,1);
+	double dl0z = dlambda(i0,2);
+
+	double l1 = lambda(i1);
+	double dl1x = dlambda(i1,0);
+	double dl1y = dlambda(i1,1);
+	double dl1z = dlambda(i1,2);
+
+	double dargx = dl0x + dl1x;
+	double dargy = dl0y + dl1y;
+	double dargz = dl0z + dl1z;
+                           
+	for (int k = 2; k <= edgeorder[e]; k++)
+	  {        
+	    ddecay = k*decay;
+	    decay *= arg;
+
+	    eshape[index] = b1.GetF (k) * decay;
+	    edshape[index] = Vec<3>
+	      (b1.GetDf(k) * (dl1x*arg - l1*dargx) * 
+	       decay / (arg * arg) + b1.GetF(k) * ddecay * dargx,
+	       b1.GetDf(k) * (dl1y*arg - l1*dargy) * 
+	       decay / (arg * arg) + b1.GetF(k) * ddecay * dargy,
+	       b1.GetDf(k) * (dl1z*arg - l1*dargz) * 
+	       decay / (arg * arg) + b1.GetF(k) * ddecay * dargz);
+
+	    index++;
+	  }
+      }
+
+
+
+    /*
+      int index = 0;
+      for (int e = 0; e < nedges; e++)
+      {
+      if (edgeorder[e] <= 1) continue;
+
+      int i0 = eledge[e][0]-1;
+      int i1 = eledge[e][1]-1;
+
+      if (edgeorient[e] == -1) Swap (i0, i1); // reverse orientation
+	    
+      double x = lambda(i1)-lambda(i0);
+      double y = 1-lambda(i0)-lambda(i1);
+      double fy = (1-y)*(1-y);
+
+      // double p3 = 0, p3x = 0, p3y = 0;
+      // double p2 = -1, p2x = 0, p2y = 0;
+      // double p1 = x, p1x = 1, p1y = 0;
+
+      double p3 = 0, p3x = 0, p3y = 0;
+      double p2 = -0.5, p2x = 0, p2y = 0;
+      double p1 = 0.5*x, p1x = 0.5, p1y = 0;
+
+      for (int j=2; j<= edgeorder[e]; j++)
+      {
+      p3=p2; p3x = p2x; p3y = p2y;
+      p2=p1; p2x = p1x; p2y = p1y;
+      double c1 = (2.0*j-3) / j;
+      double c2 = (j-3.0) / j;
+		
+      p1  = c1 * x * p2 - c2 * fy * p3;
+      p1x = c1 * p2 + c1 * x * p2x - c2 * fy * p3x;
+      p1y = c1 * x * p2y - (c2 * 2 * (y-1) * p3 + c2 * fy * p3y);
+
+      eshape[index] = p1;
+      for (int k = 0; k < 3; k++)
+      edshape[index](k) = 
+      p1x * ( dlambda(i1,k) - dlambda(i0,k) ) + 
+      p1y * (-dlambda(i1,k) - dlambda(i0,k) );
+      index++;
+      }    
+
+      }
+
+    */
+
+
+
+
+  }
+
+
+
+
+  void FETet :: CalcEdgeShapesOnly ()
+  {
+    int index = 0;
+
+    for (int e = 0; e < nedges; e++)
+      {
+	int i0 = eledge[e][0]-1;
+	int i1 = eledge[e][1]-1;
+
+	if (edgeorient[e] == -1) Swap (i0, i1);
+
+	double arg = lambda(i0)+lambda(i1);
+	double xi = lambda[i1];
+
+	/*
+	  b1.SetOrder (edgeorder[e]);
+	  b1.CalcFScaled (xi, arg);
+	    
+	  for (int k = 2; k <= edgeorder[e]; k++, index++)
+	  eshape[index] = b1.GetF (k); 
+	*/
+	b1.CalcFScaled (edgeorder[e], xi, arg, &eshape[index]);
+	index += edgeorder[e]-1;
+      }
+  }
+
+
+
+
+
+
+  void FETet :: CalcFaceShapes ()
+  {
+    int index = 0;
+
+    for (int f = 0; f < nfaces; f++)
+      {
+	if (faceorder[f] <= 2) continue;
+
+	int i0 = elface[f][0]-1;
+	int i1 = elface[f][1]-1;
+	int i2 = elface[f][2]-1;
+
+	if (vertexnr[i1] < vertexnr[i0]) Swap (i0, i1);
+	if (vertexnr[i2] < vertexnr[i0]) Swap (i0, i2);
+	if (vertexnr[i2] < vertexnr[i1]) Swap (i1, i2);
+
+	double arg = lambda(i1) + lambda(i2);
+	double arg2 = lambda(i0) + lambda(i1) + lambda(i2);
+
+	if (fabs(arg) < EPSILON || fabs(arg2) < EPSILON) // division by 0
+	  {
+	    for (int k = 0; k < nfaceshapes[f]; k++)
+	      {
+		fshape[index] = 0;
+		fdshape[index] = Vec<3>(0,0,0);
+		index++;
+	      }
+	    continue;
+	  }
+
+	b1.SetOrder (faceorder[f]);
+	b2.SetOrder (faceorder[f]);
+	    
+	b1.CalcFDf (lambda(i0)/arg2);
+	b2.CalcFDf (lambda(i2)/arg);
+	    
+	double decay = 1;
+	double ddecay;
+	    
+	double l0 = lambda(i0);
+	double l1 = lambda(i1);
+	double l2 = lambda(i2);
+	double dl0x = dlambda(i0,0);
+	double dl0y = dlambda(i0,1);
+	double dl0z = dlambda(i0,2);
+	double dl1x = dlambda(i1,0);
+	double dl1y = dlambda(i1,1);
+	double dl1z = dlambda(i1,2);
+	double dl2x = dlambda(i2,0);
+	double dl2y = dlambda(i2,1);
+	double dl2z = dlambda(i2,2);
+	    
+	double dargx = dl1x + dl2x;
+	double dargy = dl1y + dl2y;
+	double dargz = dl1z + dl2z;
+	double darg2x = dl0x + dl1x + dl2x;
+	double darg2y = dl0y + dl1y + dl2y;
+	double darg2z = dl0z + dl1z + dl2z;
+
+	for (int n1 = 2; n1 < faceorder[f]; n1++)
+	  {
+	    ddecay = (n1-1)*decay;
+	    decay *= arg;
+		
+	    double decay2 = arg2;
+	    double ddecay2;
+
+	    for (int n0 = 2; n0 < faceorder[f]-n1+2; n0++)
+	      {
+		ddecay2 = n0*decay2;
+		decay2 *= arg2;
+
+		fshape[index] = b1.GetF(n0) * b2.GetF(n1) * decay * decay2;
+		fdshape[index] = Vec<3>
+		  (b1.GetDf(n0) * (dl0x * arg2 - l0 * darg2x)/(arg2*arg2) * b2.GetF(n1) * decay * decay2 +
+		   b1.GetF(n0) * b2.GetDf(n1) * (dl2x * arg - l2 * dargx)/(arg*arg) * decay * decay2 +
+		   b1.GetF(n0) * b2.GetF(n1) * ddecay * dargx * decay2 +
+		   b1.GetF(n0) * b2.GetF(n1) * decay * ddecay2 * darg2x,
+			
+		   b1.GetDf(n0) * (dl0y * arg2 - l0 * darg2y)/(arg2*arg2) * b2.GetF(n1) * decay * decay2 +
+		   b1.GetF(n0) * b2.GetDf(n1) * (dl2y * arg - l2 * dargy)/(arg*arg) * decay * decay2 +
+		   b1.GetF(n0) * b2.GetF(n1) * ddecay * dargy * decay2 +
+		   b1.GetF(n0) * b2.GetF(n1) * decay * ddecay2 * darg2y,
+
+		   b1.GetDf(n0) * (dl0z * arg2 - l0 * darg2z)/(arg2*arg2) * b2.GetF(n1) * decay * decay2 +
+		   b1.GetF(n0) * b2.GetDf(n1) * (dl2z * arg - l2 * dargz)/(arg*arg) * decay * decay2 +
+		   b1.GetF(n0) * b2.GetF(n1) * ddecay * dargz * decay2 +
+		   b1.GetF(n0) * b2.GetF(n1) * decay * ddecay2 * darg2z);
+
+		index++;
+	      }
+	  }
+      }
+  }
+
+
+
+
+  // ----------------------------------------------------------------------------
+  //      FEPrism
+  // ----------------------------------------------------------------------------
+
+
+  void FEPrism :: SetReferencePoint (Point<3> axi)
+  {
+    BaseFiniteElement3D :: SetReferencePoint (axi);
+	
+    lambda(0) = xi(0);
+    lambda(1) = xi(1);
+    lambda(2) = 1-xi(0)-xi(1);
+    lambda(3) = xi(2);
+
+    dlambda(0,0) =  1; dlambda(0,1) =  0; dlambda(0,2) =   0;
+    dlambda(1,0) =  0; dlambda(1,1) =  1; dlambda(1,2) =   0;
+    dlambda(2,0) = -1; dlambda(2,1) = -1; dlambda(2,2) =   0;
+    dlambda(3,0) =  0; dlambda(3,1) =  0; dlambda(3,2) =   1;
+  }
+
+
+  void FEPrism :: CalcVertexShapes ()
+  {
+    double zcomp = 1-lambda(3);
+
+    for (int v = 0; v < nvertices; v++)
+      {
+	if (v == 3) zcomp = 1-zcomp;
+
+	vshape[v] = lambda(v % 3) * zcomp;
+	vdshape[v](0) = dlambda(v % 3,0) * zcomp;
+	vdshape[v](1) = dlambda(v % 3,1) * zcomp;
+	vdshape[v](2) = lambda(v % 3) * (-dlambda(3,2));
+
+	if (v >= 3) vdshape[v](2) *= -1;
+      }
+  }
+
+
+  void FEPrism :: CalcEdgeShapes ()
+  {
+    int index = 0;
+    int e;
+    // triangle edge shapes
+	
+    for (e = 0; e < 6; e++)
+      {
+	int i0 = (eledge[e][0]-1) % 3;
+	int i1 = (eledge[e][1]-1) % 3;
+
+	double arg = lambda[i0]+lambda[i1];
+
+	if (fabs(arg) < EPSILON) // division by 0
+	  {
+	    for (int k = 2; k <= edgeorder[e]; k++)
+	      {
+		eshape[index] = 0;
+		edshape[index] = Vec<3>(0,0,0);
+		index++;
+	      }
+	    continue;
+	  }
+
+	if (edgeorient[e] == -1) Swap (i0, i1);
+
+	double xi = lambda[i1]/arg;
+
+	b1.SetOrder (edgeorder[e]);
+	b1.CalcFDf (xi);
+
+	double decay = arg;
+	double ddecay;
+
+	double zarg = e < 3 ? (1-lambda(3)) : lambda(3);
+	double zcomp = zarg;
+	double dzcomp;
+	    
+	double l0 = lambda(i0);
+	double dl0x = dlambda(i0,0);
+	double dl0y = dlambda(i0,1);
+
+	double l1 = lambda(i1);
+	double dl1x = dlambda(i1,0);
+	double dl1y = dlambda(i1,1);
+
+	double dargx = dl0x + dl1x;
+	double dargy = dl0y + dl1y;
+                           
+
+	/*
+
+	for (int k = 2; k <= edgeorder[e]; k++)
+	{        
+	ddecay = k*decay;
+	decay *= arg;
+
+	dzcomp = k*zcomp;
+	zcomp *= zarg;
+
+	eshape[index] = b1.GetF (k) * decay * zcomp;
+	edshape[index] = Vec<3>
+	((b1.GetDf(k) * (dl1x*arg - l1*dargx) * 
+	decay / (arg * arg) + b1.GetF(k) * ddecay * dargx) * zcomp,
+	(b1.GetDf(k) * (dl1y*arg - l1*dargy) * 
+	decay / (arg * arg) + b1.GetF(k) * ddecay * dargy) * zcomp,
+	b1.GetF(k) * decay * dzcomp * (e < 3 ? -1 : 1));
+	index++;
+	}
+	*/
+
+	// JS linear in z-direction (for thin plates !)
+	for (int k = 2; k <= edgeorder[e]; k++)
+	  {        
+	    ddecay = k*decay;
+	    decay *= arg;
+
+	    // dzcomp = k*zcomp;
+	    // zcomp *= zarg;
+	    dzcomp = 1;
+	    zcomp = zarg;
+
+	    eshape[index] = b1.GetF (k) * decay * zcomp;
+	    edshape[index] = Vec<3>
+	      ((b1.GetDf(k) * (dl1x*arg - l1*dargx) * 
+		decay / (arg * arg) + b1.GetF(k) * ddecay * dargx) * zcomp,
+	       (b1.GetDf(k) * (dl1y*arg - l1*dargy) * 
+		decay / (arg * arg) + b1.GetF(k) * ddecay * dargy) * zcomp,
+	       b1.GetF(k) * decay * dzcomp * (e < 3 ? -1 : 1));
+	    index++;
+	  }
+
+
+
+      }
+
+    // rectangle edge shapes
+	
+    for (e = 6; e < nedges; e++)
+      {
+	int i0 = eledge[e][0]-1;
+
+	double arg = lambda[i0]; 
+
+	if (fabs(arg) < EPSILON) // division by 0
+	  {
+	    for (int k = 2; k <= edgeorder[e]; k++)
+	      {
+		eshape[index] = 0.;
+		edshape[index] = Vec<3>(0.,0.,0.);
+		index++;
+	      }
+	    continue;
+	  }
+
+	double xi = lambda[3];
+
+	if (edgeorient[e] == -1) xi = 1-xi;
+
+	b1.SetOrder (edgeorder[e]);
+	b1.CalcFDf (xi);
+
+	double decay = arg;
+	double ddecay;
+	    
+	double l0 = lambda(i0);
+	double l0x = dlambda(i0,0);
+	double l0y = dlambda(i0,1);
+
+	for (int k = 2; k <= edgeorder[e]; k++)
+	  {        
+	    ddecay = k*decay;
+	    decay *= arg;
+		
+	    eshape[index] = b1.GetF (k) * decay;
+	    edshape[index] = Vec<3>
+	      (b1.GetF(k) * ddecay * l0x,
+	       b1.GetF(k) * ddecay * l0y,
+	       b1.GetDf(k) * edgeorient[e] * decay);
+	    index++;
+	  }
+      }
+  }
+
+
+  void FEPrism :: CalcFaceShapes ()
+  {
+    int index = 0;
+    int f;
+
+    // triangle face parts
+
+    for (f = 0; f < 2; f++)
+      {
+	int i0 = elface[f][0]-1;
+	int i1 = elface[f][1]-1;
+	int i2 = elface[f][2]-1;
+
+	if (vertexnr[i1] < vertexnr[i0]) Swap (i0, i1);
+	if (vertexnr[i2] < vertexnr[i0]) Swap (i0, i2);
+	if (vertexnr[i2] < vertexnr[i1]) Swap (i1, i2);
+
+	i0 = i0 % 3;
+	i1 = i1 % 3;
+	i2 = i2 % 3;
+
+	double arg = lambda(i1) + lambda(i2);
+
+	if (fabs(arg) < EPSILON) // division by 0
+	  {
+	    for (int k = 0; k < nfaceshapes[f]; k++)
+	      {
+		fshape[index] = 0;
+		fdshape[index] = Vec<3>(0,0,0);
+		index++;
+	      }
+	    continue;
+	  }
+
+	b1.SetOrder (faceorder[f]);
+	b2.SetOrder (faceorder[f]);
+	    
+	b1.CalcFDf (lambda(i0));
+	b2.CalcFDf (lambda(i2)/arg);
+	    
+	double decay = 1;
+	double ddecay;
+	    
+	double l0 = lambda(i0);
+	double l1 = lambda(i1);
+	double l2 = lambda(i2);
+	double dl0x = dlambda(i0,0);
+	double dl0y = dlambda(i0,1);
+	double dl0z = dlambda(i0,2);
+	double dl1x = dlambda(i1,0);
+	double dl1y = dlambda(i1,1);
+	double dl1z = dlambda(i1,2);
+	double dl2x = dlambda(i2,0);
+	double dl2y = dlambda(i2,1);
+	double dl2z = dlambda(i2,2);
+	    
+	double dargx = dl1x + dl2x;
+	double dargy = dl1y + dl2y;
+	double dargz = dl1z + dl2z;
+
+	double arg2 = f == 0 ? 1-xi(2) : xi(2);
+	double darg2z = f == 0 ? -1 : 1;
+	    
+	for (int n1 = 2; n1 < faceorder[f]; n1++)
+	  {
+	    ddecay = (n1-1)*decay;
+	    decay *= arg;
+		
+	    double decay2 = arg2;
+	    double ddecay2;
+
+	    for (int n0 = 2; n0 < faceorder[f]-n1+2; n0++)
+	      {
+		ddecay2 = n0*decay2;
+		decay2 *= arg2;
+
+		fshape[index] = b1.GetF(n0) * b2.GetF(n1) * decay * decay2;
+		fdshape[index] = Vec<3>
+		  (b1.GetDf(n0) * dl0x * b2.GetF(n1) * decay * decay2 +
+		   b1.GetF(n0) * b2.GetDf(n1) * (dl2x * arg - l2 * dargx)/(arg*arg) * decay * decay2 +
+		   b1.GetF(n0) * b2.GetF(n1) * ddecay * dargx * decay2,
+			
+		   b1.GetDf(n0) * dl0y * b2.GetF(n1) * decay * decay2 +
+		   b1.GetF(n0) * b2.GetDf(n1) * (dl2y * arg - l2 * dargy)/(arg*arg) * decay * decay2 +
+		   b1.GetF(n0) * b2.GetF(n1) * ddecay * dargy * decay2,
+
+		   b1.GetDf(n0) * dl0z * b2.GetF(n1) * decay * decay2 +
+		   b1.GetF(n0) * b2.GetDf(n1) * (dl2z * arg - l2 * dargz)/(arg*arg) * decay * decay2 +
+		   b1.GetF(n0) * b2.GetF(n1) * ddecay * dargz * decay2 +
+		   b1.GetF(n0) * b2.GetF(n1) * decay * ddecay2 * darg2z);
+
+		index++;
+	      }
+	  }
+      }
+
+
+    // quad parts
+
+    for (f = 2; f < nfaces; f++)
+      {
+	// find index of point with smallest number
+	  
+	int i, i0 = 0;
+	for (i = 1; i < 4; i++)
+	  if (vertexnr[elface[f][i]-1] < vertexnr[elface[f][i0]-1]) i0 = i;
+	    
+	double arg = 0;
+	double dargx = 0;
+	double dargy = 0;
+	double dargz = 0;
+	for (i = 0; i < 4; i++)
+	  {
+	    arg += lambda((elface[f][i]-1) % 3)/2.0;
+	    dargx += dlambda((elface[f][i]-1) % 3,0)/2.0;
+	    dargy += dlambda((elface[f][i]-1) % 3,1)/2.0;
+	    dargz += dlambda((elface[f][i]-1) % 3,2)/2.0;
+	  }
+	    
+	if (fabs(arg) < EPSILON) // division by 0
+	  {
+	    for (int k = 0; k < nfaceshapes[f]; k++)
+	      {
+		fshape[index] = 0;
+		fdshape[index] = Vec<3>(0,0,0);
+		index++;
+	      }
+	    continue;
+	  }
+
+	int i1 = (i0+3) % 4;
+	int j = (elface[f][i0]-1) % 3;
+
+	double lam = lambda(j)/arg;
+	double dlamx = (dlambda(j,0)*arg-lambda(j)*dargx)/(arg*arg);
+	double dlamy = (dlambda(j,1)*arg-lambda(j)*dargy)/(arg*arg);
+	double dlamz = (dlambda(j,2)*arg-lambda(j)*dargz)/(arg*arg);
+			    
+	double x;
+	double z;
+	double dxx;
+	double dxy;
+	double dxz;
+	double dzx;
+	double dzy;
+	double dzz;
+
+	int ratvar;
+	/*
+	  switch (i0)
+	  {
+	  case 0:
+	  x = xi(2); z = lam;
+
+	  dxx = 0;     dxy = 0;     dxz = 1;
+	  dzx = dlamx; dzy = dlamy; dzz = dlamz;
+	  ratvar = 1;
+	  break;
+	  case 1:
+	  x = 1-lam; z = xi(2);
+	  dxx = -dlamx; dxy = -dlamy; dxz = -dlamz;
+	  dzx = 0;      dzy = 0;      dzz = 1;
+	  ratvar = 0;
+	  break;
+	  case 2: 
+	  x = 1-xi(2); z = 1-lam;
+	  dxx = 0;      dxy = 0;      dxz = -1;
+	  dzx = -dlamx; dzy = -dlamy; dzz = -dlamz;
+	  ratvar = 1;
+	  break;
+	  case 3:
+	  x = lam; z = 1-xi(2);
+	  dxx = dlamx; dxy = dlamy; dxz = dlamz;
+	  dzx = 0;     dzy = 0;     dzz = -1;
+	  ratvar = 0;
+	  break;
+	  }
+	*/
+
+	ratvar = 0;
+	x = 1-lam;
+	dxx = -dlamx; dxy = -dlamy; dxz = -dlamz;
+	if (i0 == 0 || i0 == 1)
+	  {
+	    z = xi(2);
+	    dzx = 0; dzy = 0; dzz = 1;
+	  }
+	else
+	  {
+	    z = 1-xi(2);
+	    dzx = 0; dzy = 0; dzz = -1;
+	  }
+
+	int ix = i0 ^ 1;
+	int iz = 3-i0;
+
+	if (vertexnr[elface[f][ix]-1] > vertexnr[elface[f][iz]-1])
+	  {
+	    Swap (x,z);
+	    Swap (dxx, dzx);
+	    Swap (dxy, dzy);
+	    Swap (dxz, dzz);
+	    ratvar = 1-ratvar;
+	  }
+
+	b1.SetOrder (faceorder[f]);
+	b2.SetOrder (faceorder[f]);
+	    
+	b1.CalcFDf (x);
+	b2.CalcFDf (z);
+	    
+	double decay = arg;
+	double ddecay;
+	    
+	for (int n0 = 2; n0 <= faceorder[f]; n0++)
+	  {
+	    ddecay = n0*decay;
+	    decay *= arg;
+		
+	    if (ratvar == 1) decay = arg;
+
+	    for (int n1 = 2; n1 <= faceorder[f]; n1++)
+	      {
+		if (ratvar == 1)
+		  {
+		    ddecay = n1*decay;
+		    decay *= arg;
+		  }
+
+		fshape[index] = b1.GetF(n0) * b2.GetF(n1) * decay;
+		fdshape[index] = Vec<3>
+		  (b1.GetDf(n0) * dxx * b2.GetF(n1) * decay +
+		   b1.GetF(n0) * b2.GetDf(n1) * dzx * decay +
+		   b1.GetF(n0) * b2.GetF(n1) * ddecay * dargx,
+
+		   b1.GetDf(n0) * dxy * b2.GetF(n1) * decay +
+		   b1.GetF(n0) * b2.GetDf(n1) * dzy * decay +
+		   b1.GetF(n0) * b2.GetF(n1) * ddecay * dargy,
+			
+		   b1.GetDf(n0) * dxz * b2.GetF(n1) * decay +
+		   b1.GetF(n0) * b2.GetDf(n1) * dzz * decay +
+		   b1.GetF(n0) * b2.GetF(n1) * ddecay * dargz);
+
+		index++;
+	      }
+	  }
+      }
+  }
+    
+
+
+  // ----------------------------------------------------------------------------
+  //      FEPyramid
+  // ----------------------------------------------------------------------------
+
+
+  void FEPyramid :: SetReferencePoint (Point<3> axi)
+  {
+    BaseFiniteElement3D :: SetReferencePoint (axi);
+  }
+
+
+  void FEPyramid :: CalcVertexShapes ()
+  {
+    double x = xi(0);
+    double y = xi(1);
+    double z = xi(2);
+
+    if (z == 1.) z = 1-1e-10;
+    vshape[0] = (1-z-x)*(1-z-y) / (1-z);
+    vshape[1] = x*(1-z-y) / (1-z);
+    vshape[2] = x*y / (1-z);
+    vshape[3] = (1-z-x)*y / (1-z);
+    vshape[4] = z;
+
+    double z1 = 1-z;
+    double z2 = z1*z1;
+
+    vdshape[0] = Vec<3>( -(z1-y)/z1, -(z1-x)/z1, ((x+y+2*z-2)*z1+(z1-y)*(z1-x))/z2 );
+    vdshape[1] = Vec<3>( (z1-y)/z1,  -x/z1,      (-x*z1+x*(z1-y))/z2 );
+    vdshape[2] = Vec<3>( y/z1,       x/z1,       x*y/z2 );
+    vdshape[3] = Vec<3>( -y/z1,      (z1-x)/z1,  (-y*z1+y*(z1-x))/z2 );
+    vdshape[4] = Vec<3>( 0, 0, 1 );
+  }
+
+
+  void FEPyramid :: CalcEdgeShapes ()
+  {
+    int index = 0;
+
+    for (int e = 0; e < GetNEdges(); e++)
+      {
+	for (int k = 2; k <= edgeorder[e]; k++)
+	  {        
+	    eshape[index] = 0;
+	    edshape[index] = Vec<3>(0,0,0);
+	    index++;
+	  }
+      }
+  }
+
+
+  void FEPyramid :: CalcFaceShapes ()
+  {
+    int index = 0;
+
+    for (int f = 0; f < GetNFaces(); f++)
+      {
+	for (int k = 0; k < nfaceshapes[f]; k++)
+	  {
+	    fshape[index] = 0;
+	    fdshape[index] = Vec<3>(0,0,0);
+	    index++;
+	  }
+      }
+  }
+    
+
+
+
+
+  // ----------------------------------------------------------------------------
+  //      FEHex
+  // ----------------------------------------------------------------------------
+
+
+  void FEHex :: SetReferencePoint (Point<3> axi)
+  {
+    BaseFiniteElement3D :: SetReferencePoint (axi);
+  }
+
+
+  void FEHex :: CalcVertexShapes ()
+  {
+    double x = xi(0);
+    double y = xi(1);
+    double z = xi(2);
+
+    vshape[0] = (1-x)*(1-y)*(1-z);
+    vshape[1] =    x *(1-y)*(1-z); 
+    vshape[2] =    x *   y *(1-z);
+    vshape[3] = (1-x)*   y *(1-z);
+    vshape[4] = (1-x)*(1-y)* z;
+    vshape[5] =    x *(1-y)* z;
+    vshape[6] =    x *   y * z;
+    vshape[7] = (1-x)*   y * z;
+
+    vdshape[0] = Vec<3>(-(1-y)*(1-z), -(1-x)*(1-z), -(1-x)*(1-y));
+    vdshape[1] = Vec<3>( (1-y)*(1-z),    -x *(1-z),    -x *(1-y));
+    vdshape[2] = Vec<3>(    y *(1-z),     x *(1-z),    -x * y);
+    vdshape[3] = Vec<3>(   -y *(1-z),  (1-x)*(1-z), -(1-x)*y);
+    vdshape[4] = Vec<3>(-(1-y)*   z, -(1-x)* z,  (1-x)*(1-y));
+    vdshape[5] = Vec<3>( (1-y)*   z,    -x * z,     x *(1-y));
+    vdshape[6] = Vec<3>(    y *   z,     x * z,     x * y);
+    vdshape[7] = Vec<3>(   -y *   z,  (1-x)* z,  (1-x)*y);
+
+  }
+
+
+  void FEHex :: CalcEdgeShapes ()
+  {
+    int index = 0;
+
+    for (int e = 0; e < GetNEdges(); e++)
+      {
+	for (int k = 2; k <= edgeorder[e]; k++)
+	  {        
+	    eshape[index] = 0;
+	    edshape[index] = Vec<3>(0,0,0);
+	    index++;
+	  }
+      }
+  }
+
+
+  void FEHex :: CalcFaceShapes ()
+  {
+    int index = 0;
+
+    for (int f = 0; f < GetNFaces(); f++)
+      {
+	for (int k = 0; k < nfaceshapes[f]; k++)
+	  {
+	    fshape[index] = 0;
+	    fdshape[index] = Vec<3>(0,0,0);
+	    index++;
+	  }
+      }
+  }
+    
+
+
+
+
+
+
+
+
+  int CurvedElements :: IsSurfaceElementCurved (int elnr) const
+  {
+    if (mesh.coarsemesh)
+      {
+	const HPRefElement & hpref_el =
+	  (*mesh.hpelements) [ mesh[(SurfaceElementIndex) elnr].hp_elnr];
+
+	return mesh.coarsemesh->GetCurvedElements().IsSurfaceElementCurved (hpref_el.coarse_elnr);
+      }
+
+
+
+
+    Element2d elem = mesh[(SurfaceElementIndex) elnr];
+
+    switch (elem.GetType())
+      {
+      case TRIG:
+	{
+	  FETrig fe2d(*this);
+	  fe2d.SetElementNumber (elnr+1);
+	  return (fe2d.IsCurved());
+	  break;
+	}
+
+      case QUAD:
+	{
+	  FEQuad fe2d(*this);
+	  fe2d.SetElementNumber (elnr+1);
+	  return (fe2d.IsCurved());
+	  break;
+	}
+
+      }
+    return 0;
+  }
+
+
+
+  int CurvedElements :: IsElementCurved (int elnr) const
+  {
+    if (mesh.coarsemesh)
+      {
+	const HPRefElement & hpref_el =
+	  (*mesh.hpelements) [ mesh[(ElementIndex) elnr].hp_elnr];
+
+	return mesh.coarsemesh->GetCurvedElements().IsElementCurved (hpref_el.coarse_elnr);
+      }
+
+
+
+    Element elem = mesh[(ElementIndex) elnr];
+
+    switch (elem.GetType())
+      {
+      case TET:
+	{
+	  FETet fe3d(*this);
+	  fe3d.SetElementNumber (elnr+1);
+	  return (fe3d.IsCurved());
+	  break;
+	}
+
+      case PRISM:
+	{
+	  FEPrism fe3d(*this);
+	  fe3d.SetElementNumber (elnr+1);
+	  return (fe3d.IsCurved());
+	  break;
+	}
+
+      case PYRAMID:
+	{
+	  FEPyramid fe3d(*this);
+	  fe3d.SetElementNumber (elnr+1);
+	  return (fe3d.IsCurved());
+	  break;
+	}
+
+      case HEX:
+	{
+	  FEHex fe3d(*this);
+	  fe3d.SetElementNumber (elnr+1);
+	  return (fe3d.IsCurved());
+	  break;
+	}
+
+      }
+
+    return 0;
+  }
+
+
+  void CurvedElements :: CalcSegmentTransformation (double xi, int segnr,
+						    Point<3> * x, Vec<3> * dxdxi)
+  {
+    if (mesh.coarsemesh)
+      {
+	const HPRefElement & hpref_el =
+	  (*mesh.hpelements) [ mesh[(SegmentIndex) segnr].hp_elnr];
+	  
+	// xi umrechnen
+	double lami[2];
+	lami[0] = xi;
+	lami[1] = 1-xi;
+
+	double coarse_xi = 0;
+	for (int i = 0; i < 2; i++)
+	  coarse_xi += hpref_el.param[i][0] * lami[i];
+
+	mesh.coarsemesh->GetCurvedElements().CalcSegmentTransformation (coarse_xi, hpref_el.coarse_elnr, x, dxdxi);
+	return;
+      }
+
+
+    // xi = 1-xi;  // or, this way  ????? JS
+    FESegm segm (*this);
+    segm.SetElementNumber (segnr+1);
+    segm.SetReferencePoint (Point<1>(xi));
+
+    //	segm.CalcVertexShapes (x != NULL, dxdxi != NULL);
+    segm.CalcVertexShapes ();
+
+    if (x)
+      {
+	(*x) = Point<3>(0,0,0);
+	for (int v = 0; v < 2; v++)
+	  (*x) = (*x) + segm.GetVertexShape(v) * mesh.Point(segm.GetVertexNr(v));
+      }
+	
+    if (dxdxi)
+      {
+	(*dxdxi) = Vec<3>(0,0,0);
+	for (int v = 0; v < 2; v++)
+	  (*dxdxi) = (*dxdxi) + segm.GetVertexDShape(v) * mesh.Point(segm.GetVertexNr(v));
+      }
+	
+    if (segm.GetEdgeOrder() > 1)
+      {
+	//	    segm.CalcEdgeShapes (x != NULL, dxdxi != NULL);
+	segm.CalcEdgeShapes ();
+	    
+	if (x)
+	  {
+	    int gindex = edgecoeffsindex[segm.GetEdgeNr()-1];
+	    for (int k = 2; k <= segm.GetEdgeOrder(); k++, gindex++)
+	      (*x) = (*x) + segm.GetEdgeShape(k-2) * edgecoeffs[gindex];
+	  }
+	    
+	if (dxdxi)
+	  {
+	    int gindex = edgecoeffsindex[segm.GetEdgeNr()-1];
+	    for (int k = 2; k <= segm.GetEdgeOrder(); k++, gindex++)
+	      (*dxdxi) = (*dxdxi) + segm.GetEdgeDShape(k-2) * edgecoeffs[gindex];
+	  }
+      }
+  }
+  
+
+
+  void CurvedElements :: CalcMultiPointSegmentTransformation (ARRAY<double> * xi, int segnr,
+							      ARRAY<Point<3> > * x,
+							      ARRAY<Vec<3> > * dxdxi)
+  {
+    int size = xi->Size();
+
+    if (mesh.coarsemesh)
+      {
+	const HPRefElement & hpref_el =
+	  (*mesh.hpelements) [ mesh[(SegmentIndex) segnr].hp_elnr];
+	  
+	// xi umrechnen
+	ARRAY< Point<2> > lami;
+	lami.SetSize (size);
+	for (int i = 0; i<size; i++)
+	  {
+	    lami[i](0) = (*xi)[i];
+	    lami[i](1) = 1-(*xi)[i];
+	  }
+
+	ARRAY<double> coarse_xi;
+	coarse_xi.SetSize (size);
+	coarse_xi = 0;
+
+	  
+	for (int j = 0; j < 2; j++)
+	  for (int i = 0; i<size; i++)
+	    coarse_xi[i] += hpref_el.param[j][0] * lami[i](j);
+
+	mesh.coarsemesh->GetCurvedElements().CalcMultiPointSegmentTransformation
+	  (&coarse_xi, hpref_el.coarse_elnr, x, dxdxi);
+	return;
+      }
+
+
+
+    FESegm segm (*this);
+    segm.SetElementNumber (segnr+1);
+    x->SetSize (size);
+    dxdxi->SetSize (size);
+
+    for (int i = 0; i < size; i++)
+      {
+	segm.SetReferencePoint (Point<1>((*xi)[i]));
+
+	//	segm.CalcVertexShapes (x != NULL, dxdxi != NULL);
+	segm.CalcVertexShapes ();
+
+	(*x)[i] = Point<3>(0,0,0);
+	(*dxdxi)[i] = Vec<3>(0,0,0);
+
+	for (int v = 0; v < 2; v++)
+	  {
+	    (*x)[i] = (*x)[i] + segm.GetVertexShape(v) * mesh.Point(segm.GetVertexNr(v));
+	    (*dxdxi)[i] = (*dxdxi)[i] + segm.GetVertexDShape(v) * mesh.Point(segm.GetVertexNr(v));
+	  }
+
+	if (segm.GetEdgeOrder() > 1)
+	  {
+	    //	    segm.CalcEdgeShapes (x != NULL, dxdxi != NULL);
+	    segm.CalcEdgeShapes ();
+
+	    int gindex = edgecoeffsindex[segm.GetEdgeNr()-1];
+	    for (int k = 2; k <= segm.GetEdgeOrder(); k++, gindex++)
+	      {
+		(*x)[i] = (*x)[i] + segm.GetEdgeShape(k-2) * edgecoeffs[gindex];
+		(*dxdxi)[i] = (*dxdxi)[i] + segm.GetEdgeDShape(k-2) * edgecoeffs[gindex];
+	      }
+	  }
+      }
+  }
+
+
+
+
+
+  void CurvedElements :: CalcSurfaceTransformation (Point<2> xi, int elnr,
+						    Point<3> * x, Mat<3,2> * dxdxi)
+  {
+    if (mesh.coarsemesh)
+      {
+	const HPRefElement & hpref_el =
+	  (*mesh.hpelements) [ mesh[(SurfaceElementIndex) elnr].hp_elnr];
+	  
+	// xi umrechnen
+	double lami[4];
+	FlatVector vlami(4, lami);
+	vlami = 0;
+	mesh[(SurfaceElementIndex) elnr] . GetShapeNew (xi, vlami);
+
+	Mat<2,2> trans;
+	Mat<3,2> dxdxic;
+	if (dxdxi)
+	  {
+	    MatrixFixWidth<2> dlami(4);
+	    dlami = 0;
+	    mesh[(SurfaceElementIndex) elnr] . GetDShapeNew (xi, dlami);	  
+	      
+	    trans = 0;
+	    for (int k = 0; k < 2; k++)
+	      for (int l = 0; l < 2; l++)
+		{
+		  double sum = 0;
+		  for (int i = 0; i < 4; i++)
+		    sum += hpref_el.param[i][l] * dlami(i, k);
+		  trans(l,k) = sum;
+		}
+	  }
+
+	Point<2> coarse_xi(0,0);
+	for (int i = 0; i < 4; i++)
+	  {
+	    coarse_xi(0) += hpref_el.param[i][0] * lami[i];
+	    coarse_xi(1) += hpref_el.param[i][1] * lami[i];
+	  }
+	mesh.coarsemesh->GetCurvedElements().CalcSurfaceTransformation (coarse_xi, hpref_el.coarse_elnr, x, &dxdxic);
+
+	if (dxdxi)
+	  *dxdxi = dxdxic * trans;
+
+	return;
+      }
+
+
+
+
+    const Element2d & elem = mesh[(SurfaceElementIndex) elnr];
+
+    BaseFiniteElement2D * fe2d;
+
+    // char locmem[max2(sizeof(FEQuad), sizeof(FETrig))];
+    char locmemtrig[sizeof(FETrig)];
+    char locmemquad[sizeof(FEQuad)];
+    switch (elem.GetType())
+      {
+      case TRIG: fe2d = new (locmemtrig) FETrig (*this); break;
+      case QUAD: fe2d = new (locmemquad) FEQuad (*this); break;
+      }
+
+    //	fe2d->SetElementNumber (elnr+1);
+    fe2d->SetReferencePoint (xi);
+    fe2d->CalcVertexShapes ();
+
+    if (x)
+      {
+	(*x) = Point<3>(0,0,0);
+	for (int v = 0; v < fe2d->GetNVertices(); v++)
+	  (*x) = (*x) + fe2d->GetVertexShape(v) * mesh.Point(elem[v]);
+	// (*x) = (*x) + fe2d->GetVertexShape(v) * mesh.Point(fe2d->GetVertexNr(v));
+      }
+
+    if (dxdxi)
+      {
+	for (int i = 0; i < 3; i++)
+	  for (int j = 0; j < 2; j++)
+	    (*dxdxi)(i,j) = 0;
+                  
+	for (int v = 0; v < elem.GetNV(); v++)
+	  for (int i = 0; i < 3; i++)
+	    for (int j = 0; j < 2; j++)
+	      (*dxdxi)(i,j) += fe2d->GetVertexDShape(v)(j) * mesh.Point(elem[v]).X(i+1);
+	// (*dxdxi)(i,j) += fe2d->GetVertexDShape(v)(j) * mesh.Point(fe2d->GetVertexNr(v)).X(i+1);
+      }
+
+    if (IsHighOrder())
+      {
+	fe2d->SetElementNumber (elnr+1);
+
+	//	    fe2d->CalcEdgeShapes (x != NULL, dxdxi != NULL);
+	fe2d->CalcEdgeShapes ();
+	if (x)
+	  {
+	    int index = 0;
+	    for (int e = 0; e < fe2d->GetNEdges(); e++)
+	      {
+		int gindex = edgecoeffsindex[fe2d->GetEdgeNr(e)-1];
+
+		for (int k = 2; k <= fe2d->GetEdgeOrder(e); k++, index++, gindex++)
+		  (*x) = (*x) + fe2d->GetEdgeShape(index) * edgecoeffs[gindex];
+	      }
+	  }
+
+	if (dxdxi)
+	  {
+	    int index = 0;
+	    for (int e = 0; e < fe2d->GetNEdges(); e++)
+	      {
+		int gindex = edgecoeffsindex[fe2d->GetEdgeNr(e)-1];
+		for (int k = 2; k <= fe2d->GetEdgeOrder(e); k++, index++, gindex++)
+		  for (int i = 0; i < 3; i++)
+		    for (int j = 0; j < 2; j++)
+		      (*dxdxi)(i,j) += fe2d->GetEdgeDShape(index)(j) * edgecoeffs[gindex](i);
+	      }
+	  }
+
+	if (mesh.GetDimension() == 3)
+	  {
+	    //		fe2d->CalcFaceShapes (x != NULL, dxdxi != NULL);
+	    fe2d->CalcFaceShapes ();
+
+	    if (x)
+	      {
+		int gindex = facecoeffsindex[fe2d->GetFaceNr()-1];
+		for (int index = 0; index < fe2d->GetNFaceShapes(); index++, gindex++)
+		  {
+		    (*x) = (*x) + fe2d->GetFaceShape(index) * facecoeffs[gindex];
+		  }
+	      }
+
+	    if (dxdxi)
+	      {
+		int gindex = facecoeffsindex[fe2d->GetFaceNr()-1];
+		for (int index = 0; index < fe2d->GetNFaceShapes(); index++, gindex++)
+		  for (int i = 0; i < 3; i++)
+		    for (int j = 0; j < 2; j++)
+		      (*dxdxi)(i,j) += fe2d->GetFaceDShape(index)(j) * facecoeffs[gindex](i);
+	      }
+	  }
+      } 
+
+    fe2d -> ~BaseFiniteElement2D();
+  }	
+
+
+
+
+
+
+
+
+  void CurvedElements :: CalcMultiPointSurfaceTransformation (ARRAY< Point<2> > * xi, int elnr,
+							      ARRAY< Point<3> > * x,
+							      ARRAY< Mat<3,2> > * dxdxi)
+  {
+
+    int size = xi->Size();
+      
+    if (mesh.coarsemesh)
+      {
+	const HPRefElement & hpref_el =
+	  (*mesh.hpelements) [ mesh[(SurfaceElementIndex) elnr].hp_elnr];
+	  
+	// xi umrechnen
+	ARRAY< Point<2> > coarse_xi;
+	ARRAY< Mat<2,2> > trans;
+	ARRAY< Mat<3,2> > dxdxic;
+
+	coarse_xi.SetSize (size);
+	coarse_xi = 0;
+	trans.SetSize (size);
+	dxdxic.SetSize (size);
+
+	for (int mp = 0; mp<size; mp++)
+	  {
+	    double lami[4];
+	    FlatVector vlami(4, lami);
+	    vlami = 0;
+	    mesh[(SurfaceElementIndex) elnr] . GetShapeNew ((*xi)[mp], vlami);
+	      
+	    MatrixFixWidth<2> dlami(4);
+	    dlami = 0;
+	    mesh[(SurfaceElementIndex) elnr] . GetDShapeNew ((*xi)[mp], dlami);	  
+	      
+	    trans[mp] = 0;
+	    for (int k = 0; k < 2; k++)
+	      for (int l = 0; l < 2; l++)
+		{
+		  double sum = 0;
+		  for (int i = 0; i < 4; i++)
+		    sum += hpref_el.param[i][l] * dlami(i, k);
+		  trans[mp](l,k) = sum;
+		}
+	      
+	    for (int i = 0; i < 4; i++)
+	      {
+		coarse_xi[mp](0) += hpref_el.param[i][0] * lami[i];
+		coarse_xi[mp](1) += hpref_el.param[i][1] * lami[i];
+	      }
+	  }
+	  
+	mesh.coarsemesh->GetCurvedElements().CalcMultiPointSurfaceTransformation (&coarse_xi, hpref_el.coarse_elnr, x, &dxdxic);
+	  
+	for (int mp = 0; mp < size; mp++)
+	  {
+	    (*dxdxi)[mp] = dxdxic[mp] * trans[mp];
+	  }
+	  
+	return;
+      }
+    
+
+    x->SetSize (size);
+    dxdxi->SetSize (size);
+
+    const Element2d & elem = mesh[(SurfaceElementIndex) elnr];
+
+    BaseFiniteElement2D * fe2d;
+
+    // char locmem[max2(sizeof(FEQuad), sizeof(FETrig))];
+    char locmemtrig[sizeof(FETrig)];
+    char locmemquad[sizeof(FEQuad)];
+    switch (elem.GetType())
+      {
+      case TRIG: fe2d = new (locmemtrig) FETrig (*this); break;
+      case QUAD: fe2d = new (locmemquad) FEQuad (*this); break;
+      }
+      
+    fe2d->SetElementNumber (elnr+1);
+
+    for (int mp = 0; mp < size; mp++)
+      {
+	fe2d->SetReferencePoint ((*xi)[mp]);
+	fe2d->CalcVertexShapes ();
+      
+	(*x)[mp] = Point<3>(0,0,0);
+      
+	for (int i = 0; i < 3; i++)
+	  for (int j = 0; j < 2; j++)
+	    (*dxdxi)[mp](i,j) = 0;
+      
+	for (int v = 0; v < fe2d->GetNVertices(); v++)
+	  {
+	    (*x)[mp] = (*x)[mp] + fe2d->GetVertexShape(v) * mesh.Point(fe2d->GetVertexNr(v));
+	    for (int i = 0; i < 3; i++)
+	      for (int j = 0; j < 2; j++)
+		(*dxdxi)[mp](i,j) += fe2d->GetVertexDShape(v)(j) * mesh.Point(fe2d->GetVertexNr(v)).X(i+1);
+	  }
+	  
+	if (IsHighOrder())
+	  {
+	    //	    fe2d->CalcEdgeShapes (x != NULL, dxdxi != NULL);
+	    fe2d->CalcEdgeShapes ();
+
+	    int index = 0;
+	    for (int e = 0; e < fe2d->GetNEdges(); e++)
+	      {
+		int gindex = edgecoeffsindex[fe2d->GetEdgeNr(e)-1];
+
+		for (int k = 2; k <= fe2d->GetEdgeOrder(e); k++, index++, gindex++)
+		  {
+		    (*x)[mp] = (*x)[mp] + fe2d->GetEdgeShape(index) * edgecoeffs[gindex];
+		    for (int i = 0; i < 3; i++)
+		      for (int j = 0; j < 2; j++)
+			(*dxdxi)[mp](i,j) += fe2d->GetEdgeDShape(index)(j) * edgecoeffs[gindex](i);	    
+		  }
+	      }
+
+
+	    if (mesh.GetDimension() == 3)
+	      {
+		//		fe2d->CalcFaceShapes (x != NULL, dxdxi != NULL);
+		fe2d->CalcFaceShapes ();
+
+		int gindex = facecoeffsindex[fe2d->GetFaceNr()-1];
+		for (int index = 0; index < fe2d->GetNFaceShapes(); index++, gindex++)
+		  {
+		    (*x)[mp] = (*x)[mp] + fe2d->GetFaceShape(index) * facecoeffs[gindex];
+		    for (int i = 0; i < 3; i++)
+		      for (int j = 0; j < 2; j++)
+			(*dxdxi)[mp](i,j) += fe2d->GetFaceDShape(index)(j) * facecoeffs[gindex](i);
+		  }
+	      }
+	  } 
+      }
+      
+    fe2d -> ~BaseFiniteElement2D();
+  }	
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+  void CurvedElements :: CalcElementTransformation (Point<3> xi, int elnr,
+						    Point<3> * x, Mat<3,3> * dxdxi)
+  {
+
+    if (mesh.coarsemesh)
+      {
+	const HPRefElement & hpref_el =
+	  (*mesh.hpelements) [ mesh[(ElementIndex) elnr].hp_elnr];
+	
+
+	/*
+	 *testout << " Curved Element " << elnr << endl; 
+	 *testout << " hpref_el.coarse_elnr " << hpref_el.coarse_elnr << endl; 
+	 *testout << " hpref_el.param = " << endl; 
+	 for(int j=0;j< hpref_el.np; j++) 
+	 { 
+	 for(int k=0;k<3;k++)
+	 *testout << hpref_el.param[j][k] << "\t"; 
+	 *testout << endl; 
+	 } 
+	*/
+
+	double lami[8];
+	FlatVector vlami(8, lami);
+	vlami = 0;
+	mesh[(ElementIndex) elnr] . GetShapeNew (xi, vlami);
+	
+	Point<3> coarse_xi(0,0,0);
+	for (int i = 0; i < hpref_el.np; i++)
+	  for (int l = 0; l < 3; l++)
+	    coarse_xi(l) += hpref_el.param[i][l] * lami[i];
+	  
+	Mat<3,3> trans, dxdxic;
+	if (dxdxi)
+	  {
+	    MatrixFixWidth<3> dlami(8);
+	    dlami = 0;
+	    mesh[(ElementIndex) elnr] . GetDShapeNew (xi, dlami);	  
+	      
+	    trans = 0;
+	    for (int k = 0; k < 3; k++)
+	      for (int l = 0; l < 3; l++)
+		{
+		  double sum = 0;
+		  for (int i = 0; i < hpref_el.np; i++)
+		    sum += hpref_el.param[i][l] * dlami(i, k);
+		  trans(l,k) = sum;
+		}
+	  }
+	/*	  
+	 *testout << " x " << x << endl;
+	 // << "\t" << x.X(2) << "\t" << x.X(3) << endl;  
+	 *testout << " Element Trafo " << coarse_xi(0) << " \t " << coarse_xi(1) << " \t " << coarse_xi(2) << endl;
+	 */
+	 
+
+
+	mesh.coarsemesh->GetCurvedElements().CalcElementTransformation (coarse_xi, hpref_el.coarse_elnr, x, &dxdxic);
+
+	if (dxdxi)
+	  *dxdxi = dxdxic * trans;
+	return;
+      }
+
+
+
+
+
+
+
+
+
+    Element elem = mesh[(ElementIndex) elnr];
+    BaseFiniteElement3D * fe3d;
+
+    // char locmem[max2(sizeof(FETet), sizeof(FEPrism))];
+    char locmemtet[sizeof(FETet)];
+    char locmemprism[sizeof(FEPrism)];
+    char locmempyramid[sizeof(FEPyramid)];
+    char locmemhex[sizeof(FEHex)];
+    switch (elem.GetType())
+      {
+      case TET: fe3d = new (locmemtet) FETet (*this); break;
+      case PRISM: fe3d = new (locmemprism) FEPrism (*this); break;
+      case PYRAMID: fe3d = new (locmempyramid) FEPyramid (*this); break;
+      case HEX: fe3d = new (locmemhex) FEHex (*this); break;
+      }
+	
+    // fe3d->SetElementNumber (elnr+1);
+    fe3d->SetReferencePoint (xi);
+
+    fe3d->CalcVertexShapes ();
+    //	fe3d->CalcVertexShapes (x != NULL, dxdxi != NULL);
+
+	
+    if (x)
+      {
+	(*x) = Point<3>(0,0,0);
+	for (int v = 0; v < fe3d->GetNVertices(); v++)
+	  (*x) += fe3d->GetVertexShape(v) * Vec<3> (mesh.Point(elem[v]));
+      }
+
+    if (dxdxi)
+      {
+	for (int i = 0; i < 3; i++)
+	  for (int j = 0; j < 3; j++)
+	    (*dxdxi)(i,j) = 0;
+	    
+	for (int v = 0; v < fe3d->GetNVertices(); v++)
+	  for (int i = 0; i < 3; i++)
+	    for (int j = 0; j < 3; j++)
+	      (*dxdxi)(i,j) += fe3d->GetVertexDShape(v)(j) * mesh.Point(elem[v]).X(i+1);
+      }
+
+    if (IsHighOrder())
+      {
+	fe3d->SetElementNumber (elnr+1);
+	//	    fe3d->CalcEdgeShapes (x != NULL, dxdxi != NULL);
+	fe3d->CalcEdgeShapes ();
+
+
+	if (x)
+	  {
+	    int index = 0;
+	    for (int e = 0; e < fe3d->GetNEdges(); e++)
+	      {
+		int gindex = edgecoeffsindex[fe3d->GetEdgeNr(e)-1];
+		for (int k = 2; k <= fe3d->GetEdgeOrder(e); k++, index++, gindex++)
+		  (*x) += fe3d->GetEdgeShape(index) * edgecoeffs[gindex];
+	      }
+	  }
+
+	if (dxdxi)
+	  {
+	    int index = 0;
+	    for (int e = 0; e < fe3d->GetNEdges(); e++)   
+	      {
+		int gindex = edgecoeffsindex[fe3d->GetEdgeNr(e)-1];
+		for (int k = 2; k <= fe3d->GetEdgeOrder(e); k++, index++, gindex++)
+		  for (int i = 0; i < 3; i++)
+		    for (int j = 0; j < 3; j++)
+		      (*dxdxi)(i,j) += fe3d->GetEdgeDShape(index)(j) * edgecoeffs[gindex](i);
+	      }
+	  }
+
+
+	// cout << "switched off face mapping" << endl;
+	if (mesh.GetDimension() == 3)   // JS
+	  {
+	    fe3d->CalcFaceShapes ();
+	    //		fe3d->CalcFaceShapes (x != NULL, dxdxi != NULL);
+
+	    if (x)
+	      {
+		int index = 0;
+		for (int f = 0; f < fe3d->GetNFaces(); f++)
+		  {
+		    int gindex = facecoeffsindex[fe3d->GetFaceNr(f)-1];
+		    for (int k = 0; k < fe3d->GetNFaceShapes(f); k++, index++, gindex++)
+		      (*x) += fe3d->GetFaceShape(index) * facecoeffs[gindex];
+		  }
+	      }
+
+	    if (dxdxi)
+	      {
+		int index = 0;
+		for (int f = 0; f < fe3d->GetNFaces(); f++)
+		  {
+		    int gindex = facecoeffsindex[fe3d->GetFaceNr(f)-1];
+		    for (int k = 0; k < fe3d->GetNFaceShapes(f); k++, index++, gindex++)
+		      for (int i = 0; i < 3; i++)
+			for (int j = 0; j < 3; j++)
+			  (*dxdxi)(i,j) += fe3d->GetFaceDShape(index)(j) * facecoeffs[gindex](i);
+		  }
+	      }
+	  } 
+      }
+	
+    fe3d -> ~BaseFiniteElement3D();
+  }
+
+
+
+
+
+
+
+
+
+#ifdef ROBERT
+
+  void CurvedElements :: CalcMultiPointElementTransformation (ARRAY< Point<3> > * xi, int elnr,
+							      ARRAY< Point<3> > * x,
+							      ARRAY< Mat<3,3> > * dxdxi)
+  {
+    int size = (*xi).Size();
+    x->SetSize (size);
+
+    if (dxdxi) dxdxi->SetSize (size);
+
+    if (mesh.coarsemesh)
+      {
+	const HPRefElement & hpref_el =
+	  (*mesh.hpelements) [ mesh[(ElementIndex) elnr].hp_elnr];
+	
+	ARRAY< Mat<3,3> > trans, dxdxic;
+	if (dxdxi)
+	  {
+	    trans.SetSize (size);
+	    dxdxic.SetSize (size);
+	  }
+
+	ARRAY<Point<3> > coarse_xi(size);
+
+	double lami[8];
+	FlatVector vlami(8, lami);
+	const Element & el = mesh[(ElementIndex) elnr];
+	int el_np = el.GetNP();
+
+	for (int mp = 0; mp < size; mp++)
+	  {
+	    el.GetShapeNew ((*xi)[mp], vlami);
+	    
+	    Point<3> pc(0,0,0);
+	    for (int i = 0; i < el_np; i++)
+	      for (int l = 0; l < 3; l++)
+		pc(l) += hpref_el.param[i][l] * lami[i];
+	
+	    coarse_xi[mp] = pc;
+
+	    if (dxdxi)
+	      {
+		MatrixFixWidth<3> dlami(8);
+		dlami = 0;
+		mesh[(ElementIndex) elnr] . GetDShapeNew ((*xi)[mp], dlami);	  
+		
+		trans[mp] = 0;
+		for (int k = 0; k < 3; k++)
+		  for (int l = 0; l < 3; l++)
+		    {
+		      double sum = 0;
+		      for (int i = 0; i < 8; i++)
+			sum += hpref_el.param[i][l] * dlami(i, k);
+		      trans[mp](l,k) = sum;
+		    }
+	      }
+	  }
+
+	if (dxdxi)
+	  mesh.coarsemesh->GetCurvedElements().CalcMultiPointElementTransformation (&coarse_xi, hpref_el.coarse_elnr, x, &dxdxic);
+	else
+	  mesh.coarsemesh->GetCurvedElements().CalcMultiPointElementTransformation (&coarse_xi, hpref_el.coarse_elnr, x, 0);
+	
+	if (dxdxi)
+	  for (int mp = 0; mp < size; mp++)
+	    (*dxdxi)[mp] = dxdxic[mp] * trans[mp];
+	
+	return;
+      }
+    
+
+
+
+
+
+
+
+
+    Element elem = mesh[(ElementIndex) elnr];
+    BaseFiniteElement3D * fe3d;
+    
+    // char locmem[max2(sizeof(FETet), sizeof(FEPrism))];
+    char locmemtet[sizeof(FETet)];
+    char locmemprism[sizeof(FEPrism)];
+    char locmempyramid[sizeof(FEPyramid)];
+    char locmemhex[sizeof(FEHex)];
+    switch (elem.GetType())
+      {
+      case TET: fe3d = new (locmemtet) FETet (*this); break;
+      case PRISM: fe3d = new (locmemprism) FEPrism (*this); break;
+      case PYRAMID: fe3d = new (locmempyramid) FEPyramid (*this); break;
+      case HEX: fe3d = new (locmemhex) FEHex (*this); break;
+      }
+    
+    fe3d->SetElementNumber (elnr+1);
+
+
+    for (int mp = 0; mp < size; mp++)
+      {
+	fe3d->SetReferencePoint ((*xi)[mp]);
+    
+	fe3d->CalcVertexShapes ();
+	//	fe3d->CalcVertexShapes (x != NULL, dxdxi != NULL);
+    
+	(*x)[mp] = Point<3>(0,0,0);
+	if (dxdxi)
+	  for (int i = 0; i < 3; i++)
+	    for (int j = 0; j < 3; j++)
+	      (*dxdxi)[mp](i,j) = 0;
+	
+	for (int v = 0; v < fe3d->GetNVertices(); v++)
+	  {
+	    (*x)[mp] += fe3d->GetVertexShape(v) * Vec<3> (mesh.Point(fe3d->GetVertexNr(v)));
+	    if (dxdxi)
+	      for (int i = 0; i < 3; i++)
+		for (int j = 0; j < 3; j++)
+		  (*dxdxi)[mp](i,j) += fe3d->GetVertexDShape(v)(j) * mesh.Point(fe3d->GetVertexNr(v)).X(i+1);
+	  }
+    
+
+	if (IsHighOrder())
+	  {
+	    //	    fe3d->CalcEdgeShapes (x != NULL, dxdxi != NULL);
+	    fe3d->CalcEdgeShapes ();
+	
+	    int index = 0;
+	    for (int e = 0; e < fe3d->GetNEdges(); e++)
+	      {
+		int gindex = edgecoeffsindex[fe3d->GetEdgeNr(e)-1];
+		for (int k = 2; k <= fe3d->GetEdgeOrder(e); k++, index++, gindex++)
+		  {
+		    (*x)[mp] += fe3d->GetEdgeShape(index) * edgecoeffs[gindex];
+		    if (dxdxi)
+		      for (int i = 0; i < 3; i++)
+			for (int j = 0; j < 3; j++)
+			  (*dxdxi)[mp](i,j) += fe3d->GetEdgeDShape(index)(j) * edgecoeffs[gindex](i);
+		  }
+	      }
+
+	    if (mesh.GetDimension() == 3)
+	      {
+		fe3d->CalcFaceShapes ();
+		//		fe3d->CalcFaceShapes (x != NULL, dxdxi != NULL);
+	    
+		int index = 0;
+		for (int f = 0; f < fe3d->GetNFaces(); f++)
+		  {
+		    int gindex = facecoeffsindex[fe3d->GetFaceNr(f)-1];
+		    for (int k = 0; k < fe3d->GetNFaceShapes(f); k++, index++, gindex++)
+		      {
+			(*x)[mp] += fe3d->GetFaceShape(index) * facecoeffs[gindex];
+			if (dxdxi)
+			  for (int i = 0; i < 3; i++)
+			    for (int j = 0; j < 3; j++)
+			      (*dxdxi)[mp](i,j) += fe3d->GetFaceDShape(index)(j) * facecoeffs[gindex](i);
+		      }
+		  }
+	      }
+	  }
+      }
+	
+    fe3d -> ~BaseFiniteElement3D();
+  }
+
+#endif
+
+
+
+
+
+
+  void CurvedElements :: CalcMultiPointElementTransformation (ARRAY< Point<3> > * xi, int elnr,
+							      ARRAY< Point<3> > * x,
+							      ARRAY< Mat<3,3> > * dxdxi)
+  {
+    int size = (*xi).Size();
+    x->SetSize (size);
+
+    if (dxdxi) dxdxi->SetSize (size);
+
+    if (mesh.coarsemesh)
+      {
+	const HPRefElement & hpref_el =
+	  (*mesh.hpelements) [ mesh[(ElementIndex) elnr].hp_elnr];
+	
+	ARRAY< Mat<3,3> > trans, dxdxic;
+	if (dxdxi)
+	  {
+	    trans.SetSize (size);
+	    dxdxic.SetSize (size);
+	  }
+
+	ARRAY<Point<3> > coarse_xi(size);
+
+	double lami[8];
+	FlatVector vlami(8, lami);
+	const Element & el = mesh[(ElementIndex) elnr];
+	int el_np = el.GetNP();
+
+	for (int mp = 0; mp < size; mp++)
+	  {
+	    el.GetShapeNew ((*xi)[mp], vlami);
+	    
+	    Point<3> pc(0,0,0);
+	    for (int i = 0; i < el_np; i++)
+	      for (int l = 0; l < 3; l++)
+		pc(l) += hpref_el.param[i][l] * lami[i];
+	
+	    coarse_xi[mp] = pc;
+
+	    if (dxdxi)
+	      {
+		MatrixFixWidth<3> dlami(8);
+		dlami = 0;
+		mesh[(ElementIndex) elnr] . GetDShapeNew ((*xi)[mp], dlami);	  
+		
+		trans[mp] = 0;
+		for (int k = 0; k < 3; k++)
+		  for (int l = 0; l < 3; l++)
+		    {
+		      double sum = 0;
+		      for (int i = 0; i < 8; i++)
+			sum += hpref_el.param[i][l] * dlami(i, k);
+		      trans[mp](l,k) = sum;
+		    }
+	      }
+	  }
+
+	if (dxdxi)
+	  mesh.coarsemesh->GetCurvedElements().CalcMultiPointElementTransformation (&coarse_xi, hpref_el.coarse_elnr, x, &dxdxic);
+	else
+	  mesh.coarsemesh->GetCurvedElements().CalcMultiPointElementTransformation (&coarse_xi, hpref_el.coarse_elnr, x, 0);
+	
+	if (dxdxi)
+	  for (int mp = 0; mp < size; mp++)
+	    (*dxdxi)[mp] = dxdxic[mp] * trans[mp];
+	
+	return;
+      }
+    
+
+
+
+
+
+
+
+
+    Element elem = mesh[(ElementIndex) elnr];
+    BaseFiniteElement3D * fe3d;
+    
+    // char locmem[max2(sizeof(FETet), sizeof(FEPrism))];
+    char locmemtet[sizeof(FETet)];
+    char locmemprism[sizeof(FEPrism)];
+    char locmempyramid[sizeof(FEPyramid)];
+    char locmemhex[sizeof(FEHex)];
+    switch (elem.GetType())
+      {
+      case TET: fe3d = new (locmemtet) FETet (*this); break;
+      case PRISM: fe3d = new (locmemprism) FEPrism (*this); break;
+      case PYRAMID: fe3d = new (locmempyramid) FEPyramid (*this); break;
+      case HEX: fe3d = new (locmemhex) FEHex (*this); break;
+      }
+    
+    fe3d->SetElementNumber (elnr+1);
+
+    if (dxdxi)
+      for (int mp = 0; mp < size; mp++)
+	(*dxdxi)[mp] = 0.0;
+    
+    Vec<3> vertices[8];
+    ArrayMem<Vec<3>, 100> loc_edgecoefs(0);
+    ArrayMem<Vec<3>, 100> loc_facecoefs(0);
+
+    for (int v = 0; v < fe3d->GetNVertices(); v++)
+      vertices[v] = Vec<3> (mesh.Point(fe3d->GetVertexNr(v)));
+
+    if (IsHighOrder())
+      {
+	for (int e = 0; e < fe3d->GetNEdges(); e++)
+	  {
+	    int gindex = edgecoeffsindex[fe3d->GetEdgeNr(e)-1];
+	    for (int k = 2; k <= fe3d->GetEdgeOrder(e); k++, gindex++)
+	      loc_edgecoefs.Append (edgecoeffs[gindex]);
+	  }    
+	
+	if (mesh.GetDimension() == 3)
+	  for (int f = 0; f < fe3d->GetNFaces(); f++)
+	    {
+	      int gindex = facecoeffsindex[fe3d->GetFaceNr(f)-1];
+	      for (int k = 0; k < fe3d->GetNFaceShapes(f); k++, gindex++)
+		loc_facecoefs.Append (facecoeffs[gindex]);
+	    }    
+      }
+
+
+
+    if (!dxdxi)
+
+      for (int mp = 0; mp < size; mp++)
+	{
+	  fe3d->SetReferencePoint ((*xi)[mp]);
+	  fe3d->CalcVertexShapesOnly ();
+	  
+	  if (IsHighOrder())
+	    {
+	      fe3d->CalcEdgeShapesOnly ();
+	      if (mesh.GetDimension() == 3)
+		fe3d->CalcFaceShapes ();
+	    }
+	  
+	  Point<3> hp (0,0,0);
+	  for (int v = 0; v < fe3d->GetNVertices(); v++)
+	    hp += fe3d->GetVertexShape(v) * vertices[v];
+	  for (int index = 0; index < loc_edgecoefs.Size(); index++)
+	    hp += fe3d->GetEdgeShape(index) * loc_edgecoefs[index]; 
+	  for (int index = 0; index < loc_facecoefs.Size(); index++)
+	    hp += fe3d->GetFaceShape(index) * loc_facecoefs[index]; // edgecoeffs[gindex];
+	  (*x)[mp] = hp;
+	}
+    
+    else
+      
+      for (int mp = 0; mp < size; mp++)
+	{
+	  fe3d->SetReferencePoint ((*xi)[mp]);
+	  fe3d->CalcVertexShapes ();
+	  
+	  if (IsHighOrder())
+	    {
+	      fe3d->CalcEdgeShapes ();
+	      if (mesh.GetDimension() == 3)
+		fe3d->CalcFaceShapes ();
+	    }
+	  
+	  Point<3> hp (0,0,0);
+	  for (int v = 0; v < fe3d->GetNVertices(); v++)
+	    hp += fe3d->GetVertexShape(v) * vertices[v];
+	  for (int index = 0; index < loc_edgecoefs.Size(); index++)
+	    hp += fe3d->GetEdgeShape(index) * loc_edgecoefs[index]; 
+	  for (int index = 0; index < loc_facecoefs.Size(); index++)
+	    hp += fe3d->GetFaceShape(index) * loc_facecoefs[index]; // edgecoeffs[gindex];
+	  (*x)[mp] = hp;
+	  
+
+	  for (int v = 0; v < fe3d->GetNVertices(); v++)
+	    for (int i = 0; i < 3; i++)
+	      for (int j = 0; j < 3; j++)
+		(*dxdxi)[mp](i,j) += fe3d->GetVertexDShape(v)(j) * vertices[v](i);
+	  
+	  for (int index = 0; index < loc_edgecoefs.Size(); index++)
+	    for (int i = 0; i < 3; i++)
+	      for (int j = 0; j < 3; j++)
+		(*dxdxi)[mp](i,j) += fe3d->GetEdgeDShape(index)(j) * loc_edgecoefs[index](i);
+	  
+	  for (int index = 0; index < loc_facecoefs.Size(); index++)
+	    for (int i = 0; i < 3; i++)
+	      for (int j = 0; j < 3; j++)
+		(*dxdxi)[mp](i,j) += fe3d->GetFaceDShape(index)(j) * loc_facecoefs[index](i);
+	}
+    
+    fe3d -> ~BaseFiniteElement3D();
+  }
+
+
+
+  /*
+    class Init
+    {
+    PolynomialBasis b;
+    public:
+    Init ();
+    };
+
+    Init :: Init()
+    {
+    ofstream edge("edge.out");
+    b.SetOrder(10);
+    for (double x = 0; x <= 1; x += 0.01)
+    {
+    b.CalcFScaled(x, 1);
+    edge << x;
+    for (int j = 2; j <= 5; j++)
+    edge << " " << b.GetF(j);
+    edge << endl;
+    }
+    }
+
+    Init in;
+  */
+
+} // namespace netgen
+
+
+#endif
diff --git a/contrib/Netgen/libsrc/meshing/curvedelems.hpp b/contrib/Netgen/libsrc/meshing/curvedelems.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..5e621f6d338eb56e3e157165b8dcc5f3ab01d7d5
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/curvedelems.hpp
@@ -0,0 +1,868 @@
+#ifndef CURVEDELEMS
+#define CURVEDELEMS
+
+/**************************************************************************/
+/* File:   curvedelems.hpp                                                */
+/* Author: Robert Gaisbauer                                               */
+/* Date:   27. Sep. 02 (second version: 30. Jan. 03)                      */
+/**************************************************************************/
+
+#include "bisect.hpp"
+#include <iostream>
+
+#define EPSILON 1e-20
+
+
+
+void ComputeGaussRule (int n, ARRAY<double> & xi, ARRAY<double> & wi);
+
+
+
+
+
+// ----------------------------------------------------------------------------
+//      CurvedElements
+// ----------------------------------------------------------------------------
+
+class CurvedElements
+{
+  const Mesh & mesh;
+  const MeshTopology & top;
+
+  bool isHighOrder;
+  int nvisualsubsecs;
+  int nIntegrationPoints;
+
+  ARRAY<int> edgeorder;
+  ARRAY<int> faceorder;
+
+  /*
+
+  ARRAY< Vec<3> > edgecoeffs;
+  ARRAY< Vec<3> > facecoeffs;
+
+  ARRAY<int> edgecoeffsindex;
+  ARRAY<int> facecoeffsindex;
+
+  */
+
+  inline Vec<3> GetEdgeCoeff (int edgenr, int k);
+  inline Vec<3> GetFaceCoeff (int facenr, int k);
+
+  
+  void CalcSegmentTransformation (double xi, int segnr,
+				  Point<3> * x = NULL, Vec<3> * dxdxi = NULL);
+
+  void CalcSurfaceTransformation (Point<2> xi, int elnr,
+				  Point<3> * x = NULL, Mat<3,2> * dxdxi = NULL);
+
+  void CalcElementTransformation (Point<3> xi, int elnr,
+				  Point<3> * x = NULL, Mat<3,3> * dxdxi = NULL);
+
+
+
+public:
+
+  Refinement * refinement;
+
+  ARRAY< Vec<3> > edgecoeffs;
+  ARRAY< Vec<3> > facecoeffs;
+
+  ARRAY<int> edgecoeffsindex;
+  ARRAY<int> facecoeffsindex;
+
+
+
+
+
+  CurvedElements (const Mesh & amesh);
+  ~CurvedElements();
+
+  bool IsHighOrder() const
+  { return isHighOrder; };
+  void SetHighOrder () { isHighOrder = 1; }
+
+
+  int GetNVisualSubsecs() const
+  { return nvisualsubsecs; };
+
+  const class Mesh & GetMesh() const
+  { return mesh; };
+
+  void BuildCurvedElements(Refinement * ref, int polydeg, bool rational=false);
+
+  int GetEdgeOrder (int edgenr) const
+  { return edgeorder[edgenr]; };
+
+  int GetFaceOrder (int facenr) const
+  { return faceorder[facenr]; };
+
+  int IsEdgeCurved (int edgenr) const;
+
+  int IsFaceCurved (int facenr) const;
+
+  int IsSurfaceElementCurved (int elnr) const;
+
+  int IsElementCurved (int elnr) const;
+
+
+  void CalcSegmentTransformation (double xi, int segnr,
+				  Point<3> & x)
+  { CalcSegmentTransformation (xi, segnr, &x, NULL); };
+
+  void CalcSegmentTransformation (double xi, int segnr,
+				  Vec<3> & dxdxi)
+  { CalcSegmentTransformation (xi, segnr, NULL, &dxdxi); };
+
+  void CalcSegmentTransformation (double xi, int segnr,
+				  Point<3> & x, Vec<3> & dxdxi)
+  { CalcSegmentTransformation (xi, segnr, &x, &dxdxi); };
+
+
+  void CalcSurfaceTransformation (const Point<2> & xi, int elnr,
+				  Point<3> & x)
+  { CalcSurfaceTransformation (xi, elnr, &x, NULL); };
+
+  void CalcSurfaceTransformation (const Point<2> & xi, int elnr,
+				  Mat<3,2> & dxdxi)
+  { CalcSurfaceTransformation (xi, elnr, NULL, &dxdxi); };
+
+  void CalcSurfaceTransformation (const Point<2> & xi, int elnr,
+				  Point<3> & x, Mat<3,2> & dxdxi)
+  { CalcSurfaceTransformation (xi, elnr, &x, &dxdxi); };
+
+
+  void CalcElementTransformation (const Point<3> & xi, int elnr,
+				  Point<3> & x)
+  { CalcElementTransformation (xi, elnr, &x, NULL); };
+
+  void CalcElementTransformation (const Point<3> & xi, int elnr,
+				  Mat<3,3> & dxdxi)
+  { CalcElementTransformation (xi, elnr, NULL, &dxdxi); };
+
+  void CalcElementTransformation (const Point<3> & xi, int elnr,
+				  Point<3> & x, Mat<3,3> & dxdxi)
+  { CalcElementTransformation (xi, elnr, &x, &dxdxi); };
+
+
+
+
+  void CalcMultiPointSegmentTransformation (ARRAY<double> * xi, int segnr,
+					    ARRAY<Point<3> > * x,
+					    ARRAY<Vec<3> > * dxdxi);
+
+  void CalcMultiPointSurfaceTransformation (ARRAY< Point<2> > * xi, int elnr,
+					    ARRAY< Point<3> > * x,
+					    ARRAY< Mat<3,2> > * dxdxi);
+
+  void CalcMultiPointElementTransformation (ARRAY< Point<3> > * xi, int elnr,
+					    ARRAY< Point<3> > * x,
+					    ARRAY< Mat<3,3> > * dxdxi);
+
+};
+
+
+
+// ----------------------------------------------------------------------------
+//      PolynomialBasis
+// ----------------------------------------------------------------------------
+
+class PolynomialBasis
+{
+  int order;
+  int maxorder;
+  ArrayMem<double,20> f;
+  ArrayMem<double,20> df;
+  ArrayMem<double,20> ddf;
+
+  ArrayMem<double,20> lp;
+  ArrayMem<double,20> dlp;
+
+  inline void CalcLegendrePolynomials (double x);
+  // P_i(x/t) t^i
+  inline void CalcScaledLegendrePolynomials (double x, double t);
+  inline void CalcDLegendrePolynomials (double x);
+
+public:
+
+  PolynomialBasis ()
+  { maxorder = -1; };
+
+  ~PolynomialBasis ()
+  {};
+
+  void SetOrder (int aorder)
+  {
+    order = aorder;
+    if (order > maxorder)
+      {
+	maxorder = order;
+	f.SetSize(order-1);
+	df.SetSize(order-1);
+	ddf.SetSize(order-1);
+	lp.SetSize(order+1);
+	dlp.SetSize(order);
+      };
+  };
+
+  inline void CalcF (double x);
+  inline void CalcDf (double x);
+  inline void CalcDDf (double x);
+
+  inline void CalcFDf (double x);
+
+  // compute F_i(x/t) t^i
+  inline void CalcFScaled (double x, double t);
+  static inline void CalcFScaled (int p, double x, double t, double * values);
+
+  double GetF (int p) { return f[p-2]; };
+  double GetDf (int p) { return df[p-2]; };
+  double GetDDf (int p) { return ddf[p-2]; };
+};
+
+
+
+// ----------------------------------------------------------------------------
+//      BaseFiniteElement
+// ----------------------------------------------------------------------------
+
+template <int DIM>
+class BaseFiniteElement
+{
+protected:
+
+  Point<DIM> xi;
+  int elnr;
+  const CurvedElements & curv;
+  const Mesh & mesh;
+  const MeshTopology & top;
+
+public:
+
+  BaseFiniteElement(const CurvedElements & acurv)
+    : curv(acurv), mesh(curv.GetMesh()), top(mesh.GetTopology())
+  {};
+
+  virtual ~BaseFiniteElement()
+  {};
+
+  void SetElementNumber (int aelnr)
+  { elnr = aelnr; }; // 1-based arrays in netgen
+
+  virtual void SetReferencePoint (Point<DIM> axi)
+  { xi = axi; };
+};
+
+
+
+// ----------------------------------------------------------------------------
+//      BaseFiniteElement1D
+// ----------------------------------------------------------------------------
+
+class BaseFiniteElement1D : public BaseFiniteElement<1>
+{
+protected:
+  PolynomialBasis b;
+
+  int vertexnr[2];
+  int edgenr;
+  int edgeorient;
+  int edgeorder;
+
+  int maxedgeorder;
+
+  double vshape[2];
+  double vdshape[2];
+  ArrayMem<double,20> eshape;
+  ArrayMem<double,20> edshape;
+  ArrayMem<double,20> eddshape;
+
+public:
+
+  BaseFiniteElement1D (const CurvedElements & acurv) : BaseFiniteElement<1>(acurv)
+  { maxedgeorder = 1; };
+
+  virtual ~BaseFiniteElement1D()
+  {};
+
+  int GetVertexNr (int v)
+  { return vertexnr[v]; };
+
+  int GetEdgeNr ()
+  { return edgenr; };
+
+  int GetEdgeOrder ()
+  { return edgeorder; };
+
+  int GetEdgeOrientation ()
+  { return edgeorient; };
+
+  void CalcVertexShapes();
+  void CalcEdgeShapes();
+  void CalcEdgeLaplaceShapes();
+
+  double GetVertexShape (int v)
+  { return vshape[v]; };
+
+  double GetEdgeShape (int index)
+  { return eshape[index]; };
+
+  double GetVertexDShape (int v)
+  { return vdshape[v]; };
+
+  double GetEdgeDShape (int index)
+  { return edshape[index]; };
+
+  double GetEdgeLaplaceShape (int index)
+  { return eddshape[index]; };
+
+};
+
+
+
+
+// ----------------------------------------------------------------------------
+//      FESegm
+// ----------------------------------------------------------------------------
+
+class FESegm : public BaseFiniteElement1D
+{
+
+public:
+
+  FESegm(const CurvedElements & acurv) : BaseFiniteElement1D(acurv)
+  {};
+
+  virtual ~FESegm()
+  {};
+
+  void SetElementNumber (int aelnr)
+  { 
+    BaseFiniteElement<1> :: SetElementNumber (aelnr);
+    Segment s = mesh.LineSegment(elnr);
+    vertexnr[0] = s.p1;
+    vertexnr[1] = s.p2;
+    edgenr = top.GetSegmentEdge(elnr);
+    edgeorient = top.GetSegmentEdgeOrientation(elnr);
+    edgeorder = curv.GetEdgeOrder(edgenr-1); // 1-based arrays in netgen
+
+    if (edgeorder > maxedgeorder)
+      {
+	maxedgeorder = edgeorder;
+	eshape.SetSize(maxedgeorder-1);
+	edshape.SetSize(maxedgeorder-1);
+	eddshape.SetSize(maxedgeorder-1);
+      }
+  };
+
+};
+
+
+
+// ----------------------------------------------------------------------------
+//      FEEdge
+// ----------------------------------------------------------------------------
+
+class FEEdge : public BaseFiniteElement1D
+{
+
+public:
+
+  FEEdge(const CurvedElements & acurv) : BaseFiniteElement1D(acurv)
+  {};
+
+  virtual ~FEEdge()
+  {};
+
+  void SetElementNumber (int aelnr)
+  { 
+    BaseFiniteElement<1> :: SetElementNumber (aelnr);
+    top.GetEdgeVertices (elnr, vertexnr[0], vertexnr[1]);
+    edgenr = elnr;
+    edgeorient = 1;
+    edgeorder = curv.GetEdgeOrder(edgenr-1); // 1-based arrays in netgen
+
+    if (edgeorder > maxedgeorder)
+      {
+	maxedgeorder = edgeorder;
+	eshape.SetSize(maxedgeorder-1);
+	edshape.SetSize(maxedgeorder-1);
+	eddshape.SetSize(maxedgeorder-1);
+      }
+  };
+    
+};
+
+
+
+// ----------------------------------------------------------------------------
+//      BaseFiniteElement2D
+// ----------------------------------------------------------------------------
+
+class BaseFiniteElement2D : public BaseFiniteElement<2>
+{
+protected:
+
+  int nvertices;
+  int nedges;
+
+  int vertexnr[4];
+  int edgenr[4];
+  int edgeorient[4];
+  int edgeorder[4];
+  int facenr;
+  int faceorient;
+  int faceorder;
+ 
+  int nfaceshapes;
+
+  int maxedgeorder;
+  int maxfaceorder;
+
+  PolynomialBasis b1, b2;
+
+  double vshape[4];
+  Vec<2> vdshape[4];
+  ArrayMem<double,80> eshape;
+  ArrayMem< Vec<2>,80> edshape;
+  ArrayMem<double,400> fshape;
+  ArrayMem<Vec<2>,400> fdshape;
+  ArrayMem<double,400> fddshape;
+
+  virtual void CalcNFaceShapes () = 0;
+
+public:
+
+  BaseFiniteElement2D (const CurvedElements & acurv) : BaseFiniteElement<2>(acurv)
+  { maxedgeorder = maxfaceorder = -1; };
+
+    virtual ~BaseFiniteElement2D()
+	{};
+
+  void SetElementNumber (int aelnr);
+
+  virtual void SetVertexSingularity (int v, int exponent) = 0;
+
+  int GetVertexNr (int v)
+  { return vertexnr[v]; };
+
+  int GetEdgeNr (int e)
+  { return edgenr[e]; };
+
+  int GetFaceNr ()
+  { return facenr; };
+
+  int GetEdgeOrder (int e)
+  { return edgeorder[e]; };
+
+  int GetFaceOrder ()
+  { return faceorder; }
+
+  int GetNVertices ()
+  { return nvertices; };
+
+  int GetNEdges ()
+  { return nedges; };
+
+  int GetNFaceShapes ()
+  { return nfaceshapes; };
+
+  int IsCurved ()
+  {
+    bool iscurved = 0;
+    int e;
+
+    for (e = 0; e < GetNEdges(); e++)
+      iscurved = iscurved || (GetEdgeOrder(e) > 1);
+
+    return iscurved || (GetFaceOrder() > 1);
+  }
+
+  virtual void CalcVertexShapes() = 0;
+  virtual void CalcEdgeShapes() = 0; 
+  virtual void CalcFaceShapes() = 0;
+
+  virtual void CalcFaceLaplaceShapes() = 0;
+
+  double GetVertexShape (int v)
+  { return vshape[v]; };
+
+  double GetEdgeShape (int index)
+  { return eshape[index]; };
+
+  double GetFaceShape (int index)
+  { return fshape[index]; };
+
+  Vec<2> GetVertexDShape (int v)
+  { return vdshape[v]; };
+
+  Vec<2> GetEdgeDShape (int index)
+  { return edshape[index]; };
+
+  Vec<2> GetFaceDShape (int index)
+  { return fdshape[index]; };
+
+  double GetFaceLaplaceShape (int index)
+  { return fddshape[index]; };
+};
+
+
+
+// ----------------------------------------------------------------------------
+//      FETrig
+// ----------------------------------------------------------------------------
+
+class FETrig : public BaseFiniteElement2D
+{
+  Point<3> lambda;
+  Mat<3,2> dlambda;
+
+  const ELEMENT_EDGE * eledge;
+  const ELEMENT_FACE * elface;
+
+  virtual void CalcNFaceShapes ()
+  { nfaceshapes = ((faceorder-1)*(faceorder-2))/2; };
+
+public:
+
+  FETrig (const CurvedElements & acurv) : BaseFiniteElement2D(acurv)
+  {
+    nvertices = 3;
+    nedges = 3;
+    eledge = MeshTopology :: GetEdges (TRIG);
+    elface = MeshTopology :: GetFaces (TRIG);
+  };
+
+    virtual ~FETrig()
+	{};
+
+  virtual void SetReferencePoint (Point<2> axi);
+
+  virtual void SetVertexSingularity (int v, int exponent);
+
+  virtual void CalcVertexShapes();
+  virtual void CalcEdgeShapes();
+  virtual void CalcFaceShapes();
+
+  virtual void CalcFaceLaplaceShapes();
+};
+
+
+
+// ----------------------------------------------------------------------------
+//      FEQuad
+// ----------------------------------------------------------------------------
+
+class FEQuad : public BaseFiniteElement2D
+{
+  const ELEMENT_FACE * elface;
+
+  virtual void CalcNFaceShapes ()
+  { nfaceshapes = (faceorder-1)*(faceorder-1); };
+
+public:
+
+  FEQuad (const CurvedElements & acurv) : BaseFiniteElement2D(acurv)
+  {
+    nvertices = 4;
+    nedges = 4;
+    elface = MeshTopology :: GetFaces (QUAD);
+  };
+
+    virtual ~FEQuad()
+	{};
+
+  virtual void SetVertexSingularity (int /* v */, int /* exponent */)
+	{};
+
+  virtual void CalcVertexShapes();
+  virtual void CalcEdgeShapes();
+  virtual void CalcFaceShapes();
+
+  virtual void CalcFaceLaplaceShapes();
+};
+
+
+
+
+// ----------------------------------------------------------------------------
+//      BaseFiniteElement3D
+// ----------------------------------------------------------------------------
+
+class BaseFiniteElement3D : public BaseFiniteElement<3>
+{
+protected:
+
+  int nvertices;
+  int nedges;
+  int nfaces;
+
+  int vertexnr[8];
+  int edgenr[12];
+  int edgeorient[12];
+  int edgeorder[12];
+  int facenr[6];
+  int faceorient[6];
+  int faceorder[6];
+  int surfacenr[6];
+  // int surfaceorient[6];
+
+  int nfaceshapes[6];
+
+  int maxedgeorder;
+  int maxfaceorder;
+
+  PolynomialBasis b1, b2;
+
+  double vshape[8];
+  Vec<3> vdshape[8];
+  ArrayMem<double,120> eshape;
+  ArrayMem<Vec<3>,120> edshape;
+  ArrayMem<double,300> fshape;
+  ArrayMem<Vec<3>,300> fdshape;
+
+  virtual void CalcNFaceShapes () = 0;
+
+public:
+
+  int locmaxedgeorder;
+  int locmaxfaceorder;
+
+  BaseFiniteElement3D (const CurvedElements & acurv) : BaseFiniteElement<3>(acurv)
+  { maxedgeorder = maxfaceorder = -1; };
+
+  void SetElementNumber (int aelnr);
+
+  int GetVertexNr (int v)
+  { return vertexnr[v]; };
+
+  int GetEdgeNr (int e)
+  { return edgenr[e]; };
+
+  int GetFaceNr (int f)
+  { return facenr[f]; };
+
+  int GetNFaceShapes (int f)
+  { return nfaceshapes[f]; };
+
+  int GetEdgeOrder (int e)
+  { return edgeorder[e]; };
+
+  int GetFaceOrder (int f)
+  { return faceorder[f]; };
+
+  int GetNVertices ()
+  { return nvertices; };
+
+  int GetNEdges ()
+  { return nedges; };
+
+  int GetNFaces ()
+  { return nfaces; };
+
+  int IsCurved ()
+  {
+    bool iscurved = 0;
+    int e, f;
+
+    for (e = 0; e < GetNEdges(); e++)
+      iscurved = iscurved || (GetEdgeOrder(e) > 1);
+
+    for (f = 0; f < GetNFaces(); f++)
+      iscurved = iscurved || (GetFaceOrder(f) > 1);
+
+    return iscurved;
+  }
+
+  virtual void CalcVertexShapes() = 0;
+  virtual void CalcVertexShapesOnly()
+  { CalcVertexShapes(); }
+
+  virtual void CalcEdgeShapes() = 0;
+  virtual void CalcEdgeShapesOnly() 
+    { CalcEdgeShapes(); }
+
+  virtual void CalcFaceShapes() = 0;
+
+  double GetVertexShape (int v)
+  { return vshape[v]; };
+
+  double GetEdgeShape (int index)
+  { return eshape[index]; };
+
+  double GetFaceShape (int index)
+  { return fshape[index]; };
+
+  Vec<3> GetVertexDShape (int v)
+  { return vdshape[v]; };
+
+  Vec<3> GetEdgeDShape (int index)
+  { return edshape[index]; };
+
+  Vec<3> GetFaceDShape (int index)
+  { return fdshape[index]; };
+};
+
+
+
+// ----------------------------------------------------------------------------
+//      FETet
+// ----------------------------------------------------------------------------
+
+class FETet : public BaseFiniteElement3D
+{
+  Point<4> lambda;
+  Mat<4,3> dlambda;
+
+  const ELEMENT_EDGE * eledge;
+  const ELEMENT_FACE * elface;
+
+  virtual void CalcNFaceShapes ()
+  {
+    for (int f = 0; f < nfaces; f++)
+      nfaceshapes[f] = ((faceorder[f]-1)*(faceorder[f]-2))/2;
+  };
+
+public:
+
+  FETet (const CurvedElements & acurv) : BaseFiniteElement3D(acurv)
+  {
+    nvertices = 4;
+    nedges = 6;
+    nfaces = 4;
+    eledge = MeshTopology :: GetEdges (TET);
+    elface = MeshTopology :: GetFaces (TET);
+  };
+
+  void SetReferencePoint (Point<3> axi);
+
+  virtual void CalcVertexShapes();
+  virtual void CalcVertexShapesOnly();
+  virtual void CalcEdgeShapes();
+  virtual void CalcEdgeShapesOnly();
+  virtual void CalcFaceShapes();
+};
+
+
+
+// ----------------------------------------------------------------------------
+//      FEPrism
+// ----------------------------------------------------------------------------
+
+class FEPrism : public BaseFiniteElement3D
+{
+  Point<4> lambda;   // mixed barycentric coordinates
+  Mat<4,3> dlambda;
+
+  const ELEMENT_EDGE * eledge;
+  const ELEMENT_FACE * elface;
+
+  virtual void CalcNFaceShapes ()
+  {
+    int f;
+    for (f = 0; f < 2; f++)
+      nfaceshapes[f] = ((faceorder[f]-1)*(faceorder[f]-2))/2;
+    for (f = 2; f < nfaces; f++)
+      nfaceshapes[f] = (faceorder[f]-1)*(faceorder[f]-1);
+  };
+
+public:
+
+  FEPrism (const CurvedElements & acurv) : BaseFiniteElement3D(acurv)
+  {
+    nvertices = 6;
+    nedges = 9;
+    nfaces = 5;
+    eledge = MeshTopology :: GetEdges (PRISM);
+    elface = MeshTopology :: GetFaces (PRISM);
+  };
+
+  void SetReferencePoint (Point<3> axi);
+
+  virtual void CalcVertexShapes();
+  virtual void CalcEdgeShapes();
+  virtual void CalcFaceShapes();
+};
+
+
+
+
+// ----------------------------------------------------------------------------
+//      FEPyramid
+// ----------------------------------------------------------------------------
+
+class FEPyramid : public BaseFiniteElement3D
+{
+
+  const ELEMENT_EDGE * eledge;
+  const ELEMENT_FACE * elface;
+
+  virtual void CalcNFaceShapes ()
+  {
+    int f;
+    for (f = 0; f < 4; f++)
+      nfaceshapes[f] = ((faceorder[f]-1)*(faceorder[f]-2))/2;
+    for (f = 4; f < nfaces; f++)
+      nfaceshapes[f] = (faceorder[f]-1)*(faceorder[f]-1);
+  };
+
+public:
+
+  FEPyramid (const CurvedElements & acurv) : BaseFiniteElement3D(acurv)
+  {
+    nvertices = 5;
+    nedges = 8;
+    nfaces = 5;
+    eledge = MeshTopology :: GetEdges (PYRAMID);
+    elface = MeshTopology :: GetFaces (PYRAMID);
+  };
+
+  void SetReferencePoint (Point<3> axi);
+
+  virtual void CalcVertexShapes();
+  virtual void CalcEdgeShapes();
+  virtual void CalcFaceShapes();
+};
+
+
+
+
+// ----------------------------------------------------------------------------
+//      FEHex
+// ----------------------------------------------------------------------------
+
+class FEHex : public BaseFiniteElement3D
+{
+
+  const ELEMENT_EDGE * eledge;
+  const ELEMENT_FACE * elface;
+
+  virtual void CalcNFaceShapes ()
+  {
+    int f;
+    for (f = 0; f < 6; f++)
+      nfaceshapes[f] = (faceorder[f]-1)*(faceorder[f]-1);
+  };
+
+public:
+
+  FEHex (const CurvedElements & acurv) : BaseFiniteElement3D(acurv)
+  {
+    nvertices = 8;
+    nedges = 12;
+    nfaces = 6;
+    eledge = MeshTopology :: GetEdges (HEX);
+    elface = MeshTopology :: GetFaces (HEX);
+  };
+
+  void SetReferencePoint (Point<3> axi);
+
+  virtual void CalcVertexShapes();
+  virtual void CalcEdgeShapes();
+  virtual void CalcFaceShapes();
+};
+
+
+
+
+#endif
diff --git a/contrib/Netgen/libsrc/meshing/curvedelems2.cpp b/contrib/Netgen/libsrc/meshing/curvedelems2.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..6b44b19e5f6c972b371d0ad675b21fd63cbcd5ff
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/curvedelems2.cpp
@@ -0,0 +1,758 @@
+
+#include <mystdlib.h>
+
+#include "meshing.hpp"
+#ifndef CURVEDELEMS_NEW
+
+namespace netgen
+{
+    
+
+// ----------------------------------------------------------------------------
+//      CurvedElements
+// ----------------------------------------------------------------------------
+
+    CurvedElements :: CurvedElements (const Mesh & amesh)
+	: mesh(amesh), top(mesh.GetTopology())
+    {
+	isHighOrder = 0;
+	nvisualsubsecs = 2;
+	nIntegrationPoints = 10;
+    }
+
+
+    CurvedElements :: ~CurvedElements ()
+    {
+      ;
+    }
+
+
+  void CurvedElements :: BuildCurvedElements(Refinement * ref, int polydeg, bool rational)
+    {
+      if (mesh.coarsemesh)
+	{
+	  mesh.coarsemesh->GetCurvedElements().BuildCurvedElements (ref, polydeg, rational);
+	  SetHighOrder();
+	  return;
+	}
+
+      PrintMessage (2, "Build curved elements, order = ", polydeg);
+
+      NgLock lock(const_cast<Mesh&>(mesh).Mutex(), 1);
+      isHighOrder = 0;
+      lock.UnLock();
+
+	const_cast<Mesh &>(mesh).UpdateTopology();
+
+	// set order of edges and faces
+
+	BaseFiniteElement2D * fe2d;
+
+	FEEdge edge (*this);
+	FESegm segm (*this);
+	FETrig trig (*this);
+	FEQuad quad (*this);
+
+	int i, k, e, f;
+
+	ARRAY<bool> edgedone;
+
+	edgedone.SetSize (top.GetNEdges());
+
+	edgeorder.SetSize (top.GetNEdges());
+	faceorder.SetSize (top.GetNFaces());
+
+	int nedgestocurve = mesh.GetNSeg();
+
+	edgedone = 0;
+	edgeorder = 1;
+	faceorder = 1;
+
+	if (polydeg == 1)
+	{
+	    isHighOrder = 0;
+	    return;
+	}
+
+	
+	/*
+	for (e = 0; e < top.GetNEdges(); e++)
+	  {
+	    edgedone = 0;
+	    edgeorder[e] = 1;
+	  }
+
+	for (f = 0; f < top.GetNFaces(); f++)
+	    faceorder[f] = 1;
+	*/
+
+	for (i = 1; i <= mesh.GetNSeg(); i++) 
+	    edgeorder[top.GetSegmentEdge(i)-1] = polydeg;
+
+
+	if (mesh.GetDimension() == 3)
+	  {
+	    for (i = 1; i <= mesh.GetNSE(); i++)
+	      {
+		faceorder[top.GetSurfaceElementFace(i)-1] = polydeg;
+		
+		Element2d elem = mesh[(SurfaceElementIndex) (i-1)];
+		
+		ARRAY<int> edgenrs;
+		top.GetSurfaceElementEdges(i, edgenrs);
+		
+		nedgestocurve += top.GetNEdges(elem.GetType());
+		
+		for (int e = 0; e < top.GetNEdges(elem.GetType()); e++)
+		  edgeorder[edgenrs[e]-1] = polydeg;
+	      }
+	  }
+
+
+	PrintMessage (1, "Building curved elements, order = ", polydeg);
+	PushStatusF ("curving edges");
+
+
+
+        // set edgecoeffs and facecoeffs arrays index and size
+
+	edgecoeffsindex.SetSize (top.GetNEdges()+1);
+	facecoeffsindex.SetSize (top.GetNFaces()+1);
+
+	edgecoeffsindex[0] = 0;
+	for (e = 2; e <= top.GetNEdges()+1; e++)
+	    edgecoeffsindex[e-1] = edgecoeffsindex[e-2] + edgeorder[e-2]-1;
+
+	facecoeffsindex[0] = 0;
+	for (f = 2; f <= top.GetNFaces()+1; f++)
+	{
+	    switch (top.GetFaceType (f-1))
+	    {
+		case TRIG:
+		    facecoeffsindex[f-1] = facecoeffsindex[f-2] + 
+			(faceorder[f-2]-1)*(faceorder[f-2]-2)/2;
+		    break;
+		case QUAD:
+		    facecoeffsindex[f-1] = facecoeffsindex[f-2] +
+			(faceorder[f-2]-1)*(faceorder[f-2]-1);
+		    break;
+	    }
+	}
+
+	edgecoeffs.SetSize(edgecoeffsindex[top.GetNEdges()]);
+	facecoeffs.SetSize(facecoeffsindex[top.GetNFaces()]);
+
+
+        
+	// evaluate edge points
+
+	PointGeomInfo newgi;          // dummy variable, only needed for function call
+	EdgePointGeomInfo newepgi;    // dummy variable, only needed for function call
+	Point3d xexact;               // new point to be stored in ARRAY edgepts
+
+	ARRAY<double> xi, wi;
+	ComputeGaussRule(nIntegrationPoints, xi, wi);
+
+	for (i=0; i<edgecoeffsindex[top.GetNEdges()]; i++)
+	    edgecoeffs[i] = Vec<3>(0.,0.,0.);
+
+
+
+
+	// all edges belonging to segments
+
+	for (i=0; i<mesh.GetNSeg(); i++) 
+	{
+	  if (multithread.terminate) return;
+
+	  SetThreadPercent( double(100*i/nedgestocurve) );
+
+	  int edgenr = top.GetSegmentEdge(i+1);
+
+	  if (edgedone[edgenr-1]) continue;
+
+	  edgedone[edgenr-1] = 1;
+
+            Segment s = mesh.LineSegment(i+1); 
+
+	    segm.SetElementNumber (i+1);
+	
+	    for (k = 2; k <= segm.GetEdgeOrder(); k++)
+	      edgecoeffs[edgecoeffsindex[edgenr-1]+k-2] = Vec<3>(0.,0.,0.);
+
+	    for (int l = 0; l < nIntegrationPoints; l++)
+	      {
+		segm.SetReferencePoint (Point<1>(xi[l]));
+		segm.CalcVertexShapes ();
+		segm.CalcEdgeLaplaceShapes ();
+		
+		Point<3> xv(0,0,0);
+
+		for (int v = 0; v < 2; v++)
+		  xv = xv + segm.GetVertexShape(v) * mesh.Point(segm.GetVertexNr(v));
+		  		
+		double secpoint = xi[l];
+
+		ref->PointBetween (mesh.Point(segm.GetVertexNr(1)),
+				   mesh.Point(segm.GetVertexNr(0)), secpoint,
+				   s.surfnr2, s.surfnr1,
+				   s.epgeominfo[1], s.epgeominfo[0],
+				   xexact, newepgi);
+		
+		for (int k = 2; k <= segm.GetEdgeOrder(); k++)
+		  edgecoeffs[edgecoeffsindex[edgenr-1]+k-2] -=
+		    wi[l] * segm.GetEdgeLaplaceShape(k-2) * Vec<3>(xexact - xv);
+		
+	      }
+	    
+	    for (k = 2; k <= segm.GetEdgeOrder(); k++)
+	      edgecoeffs[edgecoeffsindex[edgenr-1]+k-2] =
+		(2.0*(k-1.0)+1.0)*edgecoeffs[edgecoeffsindex[edgenr-1]+k-2];
+	
+	}
+
+
+
+
+
+	// all edges belonging to surface elements
+	
+	if (mesh.GetDimension() == 3)
+	  {
+	    int nedgescurved = mesh.GetNSeg();
+	    for (int i=0; i<mesh.GetNSE(); i++) 
+	      {
+		if (multithread.terminate) return;
+		
+		//		SetThreadPercent( double(100*(mesh.GetNSeg()+i)/nedgestocurve) );
+		Element2d elem = mesh[(SurfaceElementIndex) i];
+		const ELEMENT_EDGE * eledges = MeshTopology::GetEdges(elem.GetType());
+		
+		ARRAY<int> edgenrs;
+		ARRAY<int> orient;
+		top.GetSurfaceElementEdges(i+1, edgenrs);
+		top.GetSurfaceElementEdgeOrientations(i+1, orient);
+
+		for (int e = 0; e < top.GetNEdges(elem.GetType()); e++)
+		  {
+//		    cout << "e = " << e << "/" << top.GetNEdges(elem.GetType()) <<  endl;
+
+		    nedgescurved++;
+
+		    if (edgedone[edgenrs[e]-1]) continue;
+		    
+		    edgedone[edgenrs[e]-1] = 1;
+
+		    SetThreadPercent( double(100*(nedgescurved)/nedgestocurve) );
+
+		    edge.SetElementNumber (edgenrs[e]);
+
+		    for (k = 2; k <= edge.GetEdgeOrder(); k++)
+		      edgecoeffs[edgecoeffsindex[edgenrs[e]-1]+k-2] = Vec<3>(0.,0.,0.);
+
+		    for (int l = 0; l < nIntegrationPoints; l++)
+		      {
+//			cout << "." << flush;
+			edge.SetReferencePoint (Point<1>(xi[l]));
+			edge.CalcVertexShapes ();
+			edge.CalcEdgeLaplaceShapes ();
+			
+			Point<3> xv(0,0,0);
+			for (int v = 0; v < 2; v++)
+			  xv = xv + edge.GetVertexShape(v) * mesh.Point(edge.GetVertexNr(v));
+
+			double secpoint = xi[l];
+
+			if (orient[e] == 1)
+			  ref->PointBetween (mesh.Point(edge.GetVertexNr(1)),
+					     mesh.Point(edge.GetVertexNr(0)), secpoint,
+					     mesh.GetFaceDescriptor(elem.GetIndex()).SurfNr(),
+					     elem.GeomInfoPi(eledges[e][1]),
+					     elem.GeomInfoPi(eledges[e][0]),
+					     xexact, newgi);
+			else
+			  ref->PointBetween (mesh.Point(edge.GetVertexNr(1)),
+					     mesh.Point(edge.GetVertexNr(0)), secpoint,
+					     mesh.GetFaceDescriptor(elem.GetIndex()).SurfNr(),
+					     elem.GeomInfoPi(eledges[e][0]),
+					     elem.GeomInfoPi(eledges[e][1]),
+					     xexact, newgi);
+
+			for (k = 2; k <= edge.GetEdgeOrder(); k++)
+			  edgecoeffs[edgecoeffsindex[edgenrs[e]-1]+k-2] -=
+			    wi[l] * edge.GetEdgeLaplaceShape(k-2) * Vec<3>(xexact - xv);
+		      }	
+//		    cout << endl;
+		    for (k = 2; k <= edge.GetEdgeOrder(); k++)
+		      edgecoeffs[edgecoeffsindex[edgenrs[e]-1]+k-2] =
+			(2.0*(k-1.0)+1.0)*edgecoeffs[edgecoeffsindex[edgenrs[e]-1]+k-2];
+		    
+		}
+	      }
+	  }
+
+
+
+
+/*
+
+	// L2-Projection for edges
+
+
+	cout << "WARNING: L2-Projection for edges" << endl;
+
+	if (mesh.GetDimension() == 3)
+	{
+	    for (int i=0; i<mesh.GetNSE(); i++) 
+	    {
+		Element2d elem = mesh[(SurfaceElementIndex) i];
+		const ELEMENT_EDGE * eledges = MeshTopology::GetEdges(elem.GetType());
+		
+		ARRAY<int> edgenrs;
+		ARRAY<int> orient;
+		top.GetSurfaceElementEdges(i+1, edgenrs);
+		top.GetSurfaceElementEdgeOrientations(i+1, orient);
+		
+		for (int e = 0; e < top.GetNEdges(elem.GetType()); e++)
+		{
+		    edge.SetElementNumber (edgenrs[e]);
+
+		    int npoints = edge.GetEdgeOrder()-1;
+
+		    if (npoints == 0) continue;
+
+		    DenseMatrix mat(npoints);
+		    DenseMatrix inv(npoints);
+		    Vector vec[3];
+	    
+		    for (int k = 0; k < 3; k++)
+		    {
+			vec[k].SetSize(npoints);
+			for (int n = 1; n <= npoints; n++) vec[k].Set(n, 0.);
+		    }
+		    
+		    for (int l = 0; l < nIntegrationPoints; l++)
+		    {
+			double w = wi[l];
+			
+			edge.SetReferencePoint (Point<1>(xi[l]));
+			edge.CalcVertexShapes ();
+			edge.CalcEdgeShapes ();
+		
+			for (int n = 0; n < npoints; n++)
+			    for (int m = 0; m < npoints; m++)
+				mat.Set(n+1, m+1, mat.Get(n+1,m+1) +
+					edge.GetEdgeShape(n) * edge.GetEdgeShape(m) * w);
+		
+			Point<3> xv(0,0,0);
+			for (int v = 0; v < 2; v++)
+			    xv = xv + edge.GetVertexShape(v) * mesh.Point(edge.GetVertexNr(v));
+			
+			double secpoint = xi[l];
+			
+			ref->PointBetween (mesh.Point(edge.GetVertexNr(1)),
+					   mesh.Point(edge.GetVertexNr(0)), secpoint,
+					   mesh.GetFaceDescriptor(elem.GetIndex()).SurfNr(),
+					   elem.GeomInfoPi(eledges[e][1]),
+					   elem.GeomInfoPi(eledges[e][0]),
+					   xexact, newgi);
+		
+			for (int k = 2; k <= edge.GetEdgeOrder(); k++)
+			{
+			    vec[0].Set(k-1, vec[0].Get(k-1) + Vec<3>(xexact - xv)(0)*edge.GetEdgeShape(k-2)*w );
+			    vec[1].Set(k-1, vec[1].Get(k-1) + Vec<3>(xexact - xv)(1)*edge.GetEdgeShape(k-2)*w );
+			    vec[2].Set(k-1, vec[2].Get(k-1) + Vec<3>(xexact - xv)(2)*edge.GetEdgeShape(k-2)*w );
+			}
+		
+		    }
+
+
+		    CalcInverse(mat,inv);
+	    
+		    Vector a0, a1, a2;
+		    
+		    a0 = inv*vec[0];
+		    a1 = inv*vec[1];
+		    a2 = inv*vec[2];
+
+		    int index = edgecoeffsindex[edge.GetEdgeNr()-1];
+
+		    for (int n = 0; n < npoints; n++, index++)
+			edgecoeffs[index] =  Vec<3>(a0(n+1), a1(n+1), a2(n+1));
+		}
+	    }
+	}
+
+
+	for (int i=0; i<mesh.GetNSeg(); i++) 
+	{
+	    int edgenr = top.GetSegmentEdge(i+1);
+
+            Segment s = mesh.LineSegment(i+1); 
+
+	    segm.SetElementNumber (i+1);
+
+	    int npoints = segm.GetEdgeOrder()-1;
+
+	    if (npoints == 0) continue;
+
+	    DenseMatrix mat(npoints);
+	    DenseMatrix inv(npoints);
+	    Vector vec[3];
+
+	    for (int k = 0; k < 3; k++)
+	    {
+		vec[k].SetSize(npoints);
+		for (int n = 1; n <= npoints; n++) vec[k].Set(n, 0.);
+	    }
+	
+	    for (int l = 0; l < nIntegrationPoints; l++)
+	    {
+		double w = wi[l];
+
+		segm.SetReferencePoint (Point<1>(xi[l]));
+		segm.CalcVertexShapes ();
+		segm.CalcEdgeShapes ();
+		
+		for (int n = 0; n < npoints; n++)
+		    for (int m = 0; m < npoints; m++)
+			mat.Set(n+1, m+1, mat.Get(n+1,m+1) +
+				segm.GetEdgeShape(n) * segm.GetEdgeShape(m) * w);
+		
+		Point<3> xv(0,0,0);
+		for (int v = 0; v < 2; v++)
+		    xv = xv + segm.GetVertexShape(v) * mesh.Point(segm.GetVertexNr(v));
+		
+		double secpoint = xi[l];
+		
+		if (segm.GetEdgeOrientation() == -1) secpoint = 1. - secpoint; // reverse orientation
+		
+		ref->PointBetween (mesh.Point(segm.GetVertexNr(1)),
+				   mesh.Point(segm.GetVertexNr(0)), secpoint,
+				   s.surfnr2, s.surfnr1,
+				   s.epgeominfo[1], s.epgeominfo[0],
+				   xexact, newepgi);
+		
+		for (int k = 2; k <= segm.GetEdgeOrder(); k++)
+		{
+		    vec[0].Set(k-1, vec[0].Get(k-1) + Vec<3>(xexact - xv)(0)*segm.GetEdgeShape(k-2)*w );
+		    vec[1].Set(k-1, vec[1].Get(k-1) + Vec<3>(xexact - xv)(1)*segm.GetEdgeShape(k-2)*w );
+		    vec[2].Set(k-1, vec[2].Get(k-1) + Vec<3>(xexact - xv)(2)*segm.GetEdgeShape(k-2)*w );
+		}
+		
+	    }
+
+
+	    CalcInverse(mat,inv);
+	    
+	    Vector a0, a1, a2;
+
+	    a0 = inv*vec[0];
+	    a1 = inv*vec[1];
+	    a2 = inv*vec[2];
+
+	    int index = edgecoeffsindex[segm.GetEdgeNr()-1];
+
+	    for (int n = 0; n < npoints; n++, index++)
+		edgecoeffs[index] =  Vec<3>(a0(n+1), a1(n+1), a2(n+1));
+
+
+
+	}
+
+*/
+
+
+
+
+
+	// evaluate face points
+
+	if (mesh.GetDimension() == 3)
+	  {
+	    PopStatus ();
+	    PushStatusF ("curving faces");
+	    
+	    for (int j=0; j<facecoeffsindex[top.GetNFaces()]; j++)
+	      facecoeffs[j] = Vec<3>(0.,0.,0.);
+	    
+	    for (SurfaceElementIndex i = 0; i < mesh.GetNSE(); i++)   // for all surface elements
+	      {
+		if (multithread.terminate) return;
+
+	        SetThreadPercent( double(100*i/mesh.GetNSE()) );
+
+		Element2d elem = mesh[i];
+		
+		if (elem.GetType() == TRIG)
+		    fe2d = &trig;
+                else
+		    fe2d = &quad;
+
+		fe2d->SetElementNumber (i+1);
+
+		int npoints = fe2d->GetNFaceShapes();
+
+		if (npoints == 0) continue;
+
+		DenseMatrix mat(npoints);
+		DenseMatrix inv(npoints);
+		Vector vec[3];
+
+		for (int k = 0; k < 3; k++)
+		{
+		    vec[k].SetSize(npoints);
+		    for (int n = 1; n <= npoints; n++) vec[k].Set(n, 0.);
+		}
+
+		for (int j = 0; j < nIntegrationPoints; j++)
+		{
+		    for (int k = 0; k < nIntegrationPoints; k++)
+		    {
+			double w;
+			Point<2> xr;
+
+			if (elem.GetType() == TRIG)
+			  {
+			    w = wi[j]*wi[k]*(1-xi[j]);
+			    xr = Point<2> (xi[j], xi[k]*(1-xi[j]));
+			  }
+			else
+			  {
+			    w = wi[j]*wi[k];
+			    xr = Point<2> (xi[j], xi[k]);
+			  }
+
+			fe2d->SetReferencePoint (xr);
+			fe2d->CalcFaceShapes ();
+			fe2d->CalcVertexShapes ();
+			fe2d->CalcEdgeShapes ();
+			fe2d->CalcFaceLaplaceShapes ();
+
+			// integration over the product of the gradients of the face shapes
+
+			for (int n = 0; n < npoints; n++)
+			  for (int m = 0; m < npoints; m++)
+			    mat.Set(n+1, m+1,
+				    mat.Get(n+1,m+1) +
+				    fe2d->GetFaceDShape(n)*fe2d->GetFaceDShape(m)*w);
+
+			// integration over the difference between the exact geometry and the one
+			// defined by vertex and edge shape functions times face shape
+
+			// double giu = 0, giv = 0;
+			PointGeomInfo gi;
+			gi.trignum = elem.GeomInfoPi(1).trignum;
+			gi.u = 0.0;
+			gi.v = 0.0;
+			Point<3> xve(0.,0.,0.);
+
+			// vertex shape functions
+			for (int v = 0; v < fe2d->GetNVertices(); v++)
+			  {
+			    xve = xve + fe2d->GetVertexShape(v) * mesh.Point(fe2d->GetVertexNr(v));
+			    gi.u += fe2d->GetVertexShape(v) * elem.GeomInfoPi(v+1).u;
+			    gi.v += fe2d->GetVertexShape(v) * elem.GeomInfoPi(v+1).v;
+			  }
+
+			// edge shape functions
+			int index = 0;
+			for (int e = 0; e < fe2d->GetNEdges(); e++)
+			  {
+			    int gindex = edgecoeffsindex[fe2d->GetEdgeNr(e)-1];
+			    for (int k = 2; k <= fe2d->GetEdgeOrder(e); k++, index++, gindex++)
+			      xve = xve + fe2d->GetEdgeShape(index) * edgecoeffs[gindex];
+			  }
+
+			// exact point
+
+			Point<3> xexact = xve;
+			ref->ProjectToSurface (xexact, mesh.GetFaceDescriptor(elem.GetIndex()).SurfNr(), gi);
+
+			Vec<3> v2 = w*(Vec<3>(xexact)-Vec<3>(xve));
+
+			for (int k = 0; k < 3; k++)
+			  for (int n = 0; n < npoints; n++)
+			    vec[k].Set(n+1, vec[k].Get(n+1) - fe2d->GetFaceLaplaceShape(n)*v2(k));
+		    }
+		}
+
+		CalcInverse(mat,inv);
+		
+		Vector a0(npoints), a1(npoints), a2(npoints);
+		
+		/*
+		a0 = inv*vec[0];
+		a1 = inv*vec[1];
+		a2 = inv*vec[2];
+		*/
+		inv.Mult (vec[0], a0);
+		inv.Mult (vec[1], a1);
+		inv.Mult (vec[2], a2);
+
+		int index = facecoeffsindex[fe2d->GetFaceNr()-1];
+		
+		for (int n = 0; n < npoints; n++, index++)
+		  facecoeffs[index] =  Vec<3>(a0.Elem(n+1), a1.Elem(n+1), a2.Elem(n+1));
+	      }
+	  }
+	
+
+
+	
+/*
+	cout << "WARNING: L2-Projection for faces" << endl;
+
+	// evaluate face points
+
+	if (mesh.GetDimension() == 3)
+	{
+	    for (int i=0; i<facecoeffsindex[top.GetNFaces()]; i++)
+		facecoeffs[i] = Vec<3>(0.,0.,0.);
+
+	    for (SurfaceElementIndex i = 0; i < mesh.GetNSE(); i++)   // for all surface elements
+	    {
+		Element2d elem = mesh[i];
+		
+		if (elem.GetType() == TRIG)
+		    fe2d = &trig;
+                else
+		    fe2d = &quad;
+
+		fe2d->SetElementNumber (i+1);
+
+		int npoints = fe2d->GetNFaceShapes();
+
+		if (npoints == 0) continue;
+
+		DenseMatrix mat(npoints);
+		DenseMatrix inv(npoints);
+		Vector vec[3];
+
+		for (int k = 0; k < 3; k++)
+		{
+		    vec[k].SetSize(npoints);
+		    for (int n = 1; n <= npoints; n++) vec[k].Set(n, 0.);
+		}
+
+		for (int j = 0; j < nIntegrationPoints; j++)
+		{
+		    for (int k = 0; k < nIntegrationPoints; k++)
+		    {
+			double w;
+			Point<2> xr;
+
+			if (elem.GetType() == TRIG)
+			{
+			    w = wi[j]*wi[k]*(1-xi[j]);
+			    xr = Point<2> (xi[j], xi[k]*(1-xi[j]));
+			}
+			else
+			{
+			    w = wi[j]*wi[k];
+			    xr = Point<2> (xi[j], xi[k]);
+			}
+
+			fe2d->SetReferencePoint (xr);
+//			fe2d->CalcFaceDShape (false, true);
+			fe2d->CalcFaceShapes ();
+
+			// integration over the product of the gradients of the face shapes
+
+			for (int n = 0; n < npoints; n++)
+			    for (int m = 0; m < npoints; m++)
+				    mat.Set(n+1, m+1, mat.Get(n+1,m+1) +
+					    fe2d->GetFaceShape(n)*fe2d->GetFaceShape(m)*w);
+
+			// integration over the difference between the exact geometry and the one
+			// defined by vertex and edge shape functions times face shape
+
+			Point<3> xve(0.,0.,0.);
+
+			// vertex shape functions
+			fe2d->CalcVertexShapes ();
+//			fe2d->CalcVertexShape (true, false);
+			for (int v = 0; v < fe2d->GetNVertices(); v++)
+			    xve = xve + fe2d->GetVertexShape(v) * mesh.Point(fe2d->GetVertexNr(v));
+
+			// edge shape functions
+//			fe2d->CalcEdgeShape (true, false);
+			fe2d->CalcEdgeShapes ();
+
+			int index = 0;
+			for (int e = 0; e < fe2d->GetNEdges(); e++)
+			{
+			    int gindex = edgecoeffsindex[fe2d->GetEdgeNr(e)-1];
+
+			    for (int k = 2; k <= fe2d->GetEdgeOrder(e); k++, index++, gindex++)
+				xve = xve + fe2d->GetEdgeShape(index) * edgecoeffs[gindex];
+			}
+
+			// exact point
+
+			Point<3> xexact = xve;
+			ref->ProjectToSurface (xexact, mesh.GetFaceDescriptor(elem.GetIndex()).SurfNr());
+
+			Vec<3> v = w*(Vec<3>(xexact)-Vec<3>(xve));
+
+			fe2d->CalcFaceLaplaceShapes ();
+
+			for (int k = 0; k < 3; k++)
+			    for (int n = 0; n < npoints; n++)
+				vec[k].Set(n+1, vec[k].Get(n+1) + fe2d->GetFaceShape(n)*v(k));
+			}
+		    }
+
+ 		    CalcInverse(mat,inv);
+
+		    Vector a0, a1, a2;
+
+		    a0 = inv*vec[0];
+		    a1 = inv*vec[1];
+		    a2 = inv*vec[2];
+
+		    int index = facecoeffsindex[fe2d->GetFaceNr()-1];
+
+		    for (int n = 0; n < npoints; n++, index++)
+			facecoeffs[index] =  Vec<3>(a0(n+1), a1(n+1), a2(n+1));
+	    }
+	}
+*/
+
+
+    PrintMessage (5, "reducing order");
+   
+    for (e = 0; e < top.GetNEdges(); e++)
+      if (edgeorder[e] > 1)
+	{
+	  int i;
+	  double maxcoeff = 0.;
+
+	  for (i = edgecoeffsindex[e]; i < edgecoeffsindex[e+1]; i++)
+	    maxcoeff = max2 (maxcoeff, edgecoeffs[i].Length());
+
+	  if (maxcoeff < 1e-12) edgeorder[e] = 1;
+	}
+
+    for (f = 0; f < top.GetNFaces(); f++)
+      if (faceorder[f] > 1)
+	{
+	  int i;
+	  double maxcoeff = 0.;
+
+	  for (i = facecoeffsindex[f]; i < facecoeffsindex[f+1]; i++)
+	    maxcoeff = max (maxcoeff, facecoeffs[i].Length());
+
+	  if (maxcoeff < 1e-12) faceorder[f] = 1;
+	}
+    
+    isHighOrder = 1;              // true
+
+    PrintMessage(1, "done");
+    PopStatus();
+    //	cout << "finished" << endl;
+    }
+
+} // namespace netgen
+
+#endif
diff --git a/contrib/Netgen/libsrc/meshing/curvedelems_new.cpp b/contrib/Netgen/libsrc/meshing/curvedelems_new.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..26580bf73b27a4626cf0cab3a4f0140ed0a9b175
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/curvedelems_new.cpp
@@ -0,0 +1,2820 @@
+#include <mystdlib.h>
+
+#include "meshing.hpp"
+#ifdef CURVEDELEMS_NEW
+
+namespace netgen
+{
+  
+  //   bool rational = true;
+
+
+
+  static void ComputeGaussRule (int n, ARRAY<double> & xi, ARRAY<double> & wi)
+  {
+    xi.SetSize (n);
+    wi.SetSize (n);
+    
+    int m = (n+1)/2;
+    double p1, p2, p3;
+    double pp, z, z1;
+    for (int i = 1; i <= m; i++)
+      {
+	z = cos ( M_PI * (i - 0.25) / (n + 0.5));
+	while(1)
+	  {
+	    p1 = 1; p2 = 0;
+	    for (int j = 1; j <= n; j++)
+	      {
+		p3 = p2; p2 = p1;
+		p1 = ((2 * j - 1) * z * p2 - (j - 1) * p3) / j;
+	      }
+	    // p1 is legendre polynomial
+	    
+	    pp = n * (z*p1-p2) / (z*z - 1);
+	    z1 = z;
+	    z = z1-p1/pp;
+	    
+	    if (fabs (z - z1) < 1e-14) break;
+	  }
+	
+	xi[i-1] = 0.5 * (1 - z);
+	xi[n-i] = 0.5 * (1 + z);
+	wi[i-1] = wi[n-i] = 1.0 / ( (1  - z * z) * pp * pp);
+      }
+  }
+  
+  
+
+  // compute edge bubbles up to order n, x \in (-1, 1)
+  static void CalcEdgeShape (int n, double x, double * shape)
+  {
+    double p1 = x, p2 = -1, p3 = 0;
+    for (int j=2; j<=n; j++)
+      {
+	p3=p2; p2=p1;
+	p1=( (2*j-3) * x * p2 - (j-3) * p3) / j;
+	shape[j-2] = p1;
+      } 
+  }
+
+  static void CalcEdgeDx (int n, double x, double * dshape)
+  {
+    double p1 = x, p2 = -1, p3 = 0;
+    double p1dx = 1, p2dx = 0, p3dx = 0;
+
+    for (int j=2; j<=n; j++)
+      {
+	p3=p2; p2=p1;
+	p3dx = p2dx; p2dx = p1dx;
+
+	p1=( (2*j-3) * x * p2 - (j-3) * p3) / j;
+	p1dx = ( (2*j-3) * (x * p2dx + p2) - (j-3) * p3dx) / j;
+
+	dshape[j-2] = p1dx;
+      }    
+  }
+
+  static void CalcEdgeShapeDx (int n, double x, double * shape, double * dshape)
+  {
+    double p1 = x, p2 = -1, p3 = 0;
+    double p1dx = 1, p2dx = 0, p3dx = 0;
+
+    for (int j=2; j<=n; j++)
+      {
+	p3=p2; p2=p1;
+	p3dx = p2dx; p2dx = p1dx;
+
+	p1=( (2*j-3) * x * p2 - (j-3) * p3) / j;
+	p1dx = ( (2*j-3) * (x * p2dx + p2) - (j-3) * p3dx) / j;
+
+	shape[j-2] = p1;
+	dshape[j-2] = p1dx;
+      }    
+  }
+
+  // compute L_i(x/t) * t^i
+  static void CalcScaledEdgeShape (int n, double x, double t, double * shape)
+  {
+    double p1 = x, p2 = -1, p3 = 0;
+    for (int j=0; j<=n-2; j++)
+      {
+	p3=p2; p2=p1;
+	p1=( (2*j+1) * x * p2 - t*t*(j-1) * p3) / (j+2);
+	shape[j] = p1;
+      }    
+  }
+
+  template <int DIST>
+  static void CalcScaledEdgeShapeDxDt (int n, double x, double t, double * dshape)
+  {
+    double p1 = x, p2 = -1, p3 = 0;
+    double p1dx = 1, p1dt = 0;
+    double p2dx = 0, p2dt = 0;
+    double p3dx = 0, p3dt = 0;
+     
+    for (int j=0; j<=n-2; j++)
+      {
+	p3=p2; p3dx=p2dx; p3dt = p2dt;
+	p2=p1; p2dx=p1dx; p2dt = p1dt;
+
+	p1   = ( (2*j+1) * x * p2 - t*t*(j-1) * p3) / (j+2);
+	p1dx = ( (2*j+1) * (x * p2dx + p2) - t*t*(j-1) * p3dx) / (j+2);
+	p1dt = ( (2*j+1) * x * p2dt - (j-1)* (t*t*p3dt+2*t*p3)) / (j+2);
+
+	// shape[j] = p1;
+	dshape[DIST*j  ] = p1dx;
+	dshape[DIST*j+1] = p1dt;
+      }    
+  }
+
+
+  static void LegendrePolynomial (int n, double x, double * values)
+  {
+    switch (n)
+      {
+      case 0:
+	values[0] = 1;
+	break;
+      case 1:
+	values[0] = 1;
+	values[1] = x;
+	break;
+
+      default:
+
+	if (n < 0) return;
+
+	double p1 = 1.0, p2 = 0.0, p3;
+	
+	values[0] = 1.0;
+	for (int j=1; j<=n; j++)
+	  {
+	    p3 = p2; p2 = p1;
+	    p1 = ((2.0*j-1.0)*x*p2 - (j-1.0)*p3) / j;
+	    values[j] = p1;
+	  }
+      }
+  }
+
+
+  static void ScaledLegendrePolynomial (int n, double x, double t, double * values)
+  {
+    switch (n)
+      {
+      case 0:
+	values[0] = 1;
+	break;
+
+      case 1:
+	values[0] = 1;
+	values[1] = x;
+	break;
+
+      default:
+
+	if (n < 0) return;
+
+	double p1 = 1.0, p2 = 0.0, p3;
+	values[0] = 1.0;
+	for (int j=1; j<=n; j++)
+	  {
+	    p3 = p2; p2 = p1;
+	    p1 = ((2.0*j-1.0)*x*p2 - t*t*(j-1.0)*p3) / j;
+	    values[j] = p1;
+	  }
+      }
+  }
+
+
+  // compute face bubbles up to order n, 0 < y, y-x < 1, x+y < 1
+  static void CalcTrigShape (int n, double x, double y, double * shape)
+  { 
+    if (n < 3) return;
+    double hx[20], hy[20];
+    ScaledLegendrePolynomial (n-3, 2*x-1, 1-y, hx);
+    LegendrePolynomial (n-3, 2*y-1, hy);
+
+    int ii = 0;
+    double bub = (1+x-y)*y*(1-x-y);
+    for (int iy = 0; iy <= n-3; iy++)
+      for (int ix = 0; ix <= n-3-iy; ix++)
+	shape[ii++] = bub * hx[ix]*hy[iy];
+  }
+
+  static void CalcTrigShapeDxDy (int n, double x, double y, double * dshape)
+  { 
+    if (n < 3) return;
+    
+    int ndof = (n-1)*(n-2)/2;
+    double h1[20], h2[20];
+    double eps = 1e-4;
+  
+    CalcTrigShape (n, x+eps, y, h1);
+    CalcTrigShape (n, x-eps, y, h2);
+
+    for (int i = 0; i < ndof; i++)
+      dshape[2*i] = (h1[i]-h2[i])/(2*eps);
+
+    CalcTrigShape (n, x, y+eps, h1);
+    CalcTrigShape (n, x, y-eps, h2);
+
+    for (int i = 0; i < ndof; i++)
+      dshape[2*i+1] = (h1[i]-h2[i])/(2*eps);
+  }
+
+
+  // compute face bubbles up to order n, 0 < y, y-x < 1, x+y < 1
+  static void CalcScaledTrigShape (int n, double x, double y, double t, double * shape)
+  {
+    if (n < 3) return;
+
+    double hx[20], hy[20];
+    ScaledLegendrePolynomial (n-3, (2*x-1), t-y, hx);
+    ScaledLegendrePolynomial (n-3, (2*y-1), t, hy);
+
+    int ii = 0;
+    double bub = (t+x-y)*y*(t-x-y);
+    for (int iy = 0; iy <= n-3; iy++)
+      for (int ix = 0; ix <= n-3-iy; ix++)
+	shape[ii++] = bub * hx[ix]*hy[iy];
+  }
+
+
+  // compute face bubbles up to order n, 0 < y, y-x < 1, x+y < 1
+  static void CalcScaledTrigShapeDxDyDt (int n, double x, double y, double t, double * dshape)
+  {
+    if (n < 3) return;
+    double hvl[100], hvr[100];
+    int nd = (n-1)*(n-2)/2;
+    
+    double eps = 1e-6;
+
+    CalcScaledTrigShape (n, x-eps, y, t, hvl);
+    CalcScaledTrigShape (n, x+eps, y, t, hvr);
+    for (int i = 0; i < nd; i++)
+      dshape[3*i] = (hvr[i]-hvl[i])/(2*eps);
+
+    CalcScaledTrigShape (n, x, y-eps, t, hvl);
+    CalcScaledTrigShape (n, x, y+eps, t, hvr);
+    for (int i = 0; i < nd; i++)
+      dshape[3*i+1] = (hvr[i]-hvl[i])/(2*eps);
+
+    CalcScaledTrigShape (n, x, y, t-eps, hvl);
+    CalcScaledTrigShape (n, x, y, t+eps, hvr);
+    for (int i = 0; i < nd; i++)
+      dshape[3*i+2] = (hvr[i]-hvl[i])/(2*eps);
+  }
+
+    
+
+  
+
+  CurvedElements :: CurvedElements (const Mesh & amesh)
+    : mesh (amesh)
+  {
+    order = 1;
+    rational = 0;
+  }
+
+
+  CurvedElements :: ~CurvedElements()
+  {
+    ;
+  }
+
+
+  void CurvedElements :: BuildCurvedElements(Refinement * ref, int aorder,
+                                             bool arational)
+  {
+    if (mesh.coarsemesh)
+      {
+	mesh.coarsemesh->GetCurvedElements().BuildCurvedElements (ref, aorder, arational);
+        order = aorder;
+        rational = arational;
+	return;
+      }
+    
+    PrintMessage (1, "Curve elements, order = ", aorder);
+    if (rational) PrintMessage (1, "curved elements with rational splines");
+
+    const_cast<Mesh&> (mesh).UpdateTopology();
+    const MeshTopology & top = mesh.GetTopology();
+
+
+    rational = arational;
+
+    ARRAY<int> edgenrs;
+
+    edgeorder.SetSize (top.GetNEdges());
+    faceorder.SetSize (top.GetNFaces());
+
+    edgeorder = 1;
+    faceorder = 1;
+
+    if (rational)
+      {
+        edgeweight.SetSize (top.GetNEdges());
+        edgeweight = 1.0;
+      }
+
+    
+    if (aorder <= 1) return;
+
+
+    if (rational) aorder = 2;
+
+
+    if (mesh.GetDimension() == 3)
+      for (SurfaceElementIndex i = 0; i < mesh.GetNSE(); i++)
+	{
+	  top.GetSurfaceElementEdges (i+1, edgenrs);
+	  for (int j = 0; j < edgenrs.Size(); j++)
+	    edgeorder[edgenrs[j]-1] = aorder;
+	  faceorder[top.GetSurfaceElementFace (i+1)-1] = aorder;
+	}
+    for (SegmentIndex i = 0; i < mesh.GetNSeg(); i++)
+      edgeorder[top.GetSegmentEdge (i+1)-1] = aorder;
+
+    if (rational)
+      {
+        edgeorder = 2;
+        faceorder = 1;
+      }
+
+
+    edgecoeffsindex.SetSize (top.GetNEdges()+1);
+    int nd = 0;
+    for (int i = 0; i < top.GetNEdges(); i++)
+      {
+	edgecoeffsindex[i] = nd;
+	nd += max (0, edgeorder[i]-1);
+      }
+    edgecoeffsindex[top.GetNEdges()] = nd;
+
+    edgecoeffs.SetSize (nd);
+    edgecoeffs = Vec<3> (0,0,0);
+    
+
+    facecoeffsindex.SetSize (top.GetNFaces()+1);
+    nd = 0;
+    for (int i = 0; i < top.GetNFaces(); i++)
+      {
+	facecoeffsindex[i] = nd;
+	if (top.GetFaceType(i+1) == TRIG)
+	  nd += max (0, (faceorder[i]-1)*(faceorder[i]-2)/2);
+	else
+	  nd += max (0, sqr(faceorder[i]-1));
+      }
+    facecoeffsindex[top.GetNFaces()] = nd;
+
+    facecoeffs.SetSize (nd);
+    facecoeffs = Vec<3> (0,0,0);
+
+
+    if (!ref || aorder <= 1) 
+      {
+        order = aorder;
+        return;
+      }
+    
+    ARRAY<double> xi, weight;
+
+    ComputeGaussRule (aorder+4, xi, weight);  // on (0,1)
+
+    PrintMessage (3, "Curving edges");
+
+    if (mesh.GetDimension() == 3 || rational)
+      for (SurfaceElementIndex i = 0; i < mesh.GetNSE(); i++)
+        {
+	  SetThreadPercent(double(i)/mesh.GetNSE()*100.);
+          const Element2d & el = mesh[i];
+          top.GetSurfaceElementEdges (i+1, edgenrs);
+          for (int j = 0; j < edgenrs.Size(); j++)
+            edgenrs[j]--;
+          const ELEMENT_EDGE * edges = MeshTopology::GetEdges (el.GetType());
+
+          for (int i2 = 0; i2 < edgenrs.Size(); i2++)
+            {
+              PointIndex pi1 = edges[i2][0]-1;
+              PointIndex pi2 = edges[i2][1]-1;
+
+              bool swap = el[pi1] > el[pi2];
+
+              Point<3> p1 = mesh[el[pi1]];
+              Point<3> p2 = mesh[el[pi2]];
+
+              int order1 = edgeorder[edgenrs[i2]];
+              int ndof = max (0, order1-1);
+
+              if (rational && order1 >= 2)
+                {
+                  Point<3> pm = Center (p1, p2);
+
+                  int surfnr = mesh.GetFaceDescriptor(el.GetIndex()).SurfNr();
+
+                  Vec<3> n1 = ref -> GetNormal (p1, surfnr, el.GeomInfoPi(edges[i2][0]));
+                  Vec<3> n2 = ref -> GetNormal (p2, surfnr, el.GeomInfoPi(edges[i2][1]));
+
+                  // p3 = pm + alpha1 n1 + alpha2 n2
+                  
+                  Mat<2> mat, inv;
+                  Vec<2> rhs, sol;
+
+                  mat(0,0) = n1*n1;
+                  mat(0,1) = mat(1,0) = n1*n2;
+                  mat(1,1) = n2*n2;
+                  
+                  rhs(0) = n1 * (p1-pm);
+                  rhs(1) = n2 * (p2-pm);
+                  
+
+                  Point<3> p3;
+
+                  if (fabs (Det (mat)) > 1e-10)
+                    {
+                      CalcInverse (mat, inv);
+                      sol = inv * rhs;
+
+                      p3 = pm + sol(0) * n1 + sol(1) * n2;
+                    }
+                  else
+                    p3 = pm;
+
+                  edgecoeffs[edgecoeffsindex[edgenrs[i2]]] = Vec<3> (p3);
+
+
+                  double wold = 1, w = 1, dw = 0.1;
+                  double dold = 1e99;
+                  while (fabs (dw) > 1e-12)
+                    {
+                      Vec<3> v05 = 0.25 * Vec<3> (p1) + 0.5*w* Vec<3>(p3) + 0.25 * Vec<3> (p2);
+                      v05 /= 1 + (w-1) * 0.5;
+                      Point<3> p05 (v05), pp05(v05);
+                      ref -> ProjectToSurface (pp05, surfnr,  el.GeomInfoPi(edges[i2][0]));
+                      double d = Dist (pp05, p05);
+                      
+                      if (d < dold)
+                        {
+                          dold = d;
+                          wold = w;
+                          w += dw;
+                        }
+                      else
+                        {
+                          dw *= -0.7;
+                          w = wold + dw;
+                        }
+                    }
+                  
+                  edgeweight[edgenrs[i2]] = w;
+                  continue;
+                }
+	    
+              Vector shape(ndof);
+              DenseMatrix mat(ndof, ndof), inv(ndof, ndof),
+                rhs(ndof, 3), sol(ndof, 3);
+	    
+              rhs = 0.0;
+              mat = 0.0;
+              for (int j = 0; j < xi.Size(); j++)
+                {
+                  Point<3> p;
+                  Point<3> pp;
+                  PointGeomInfo ppgi;
+		
+                  if (swap)
+                    {
+                      p = p1 + xi[j] * (p2-p1);
+                      ref -> PointBetween (p1, p2, xi[j], 
+                                           mesh.GetFaceDescriptor(el.GetIndex()).SurfNr(),
+                                           el.GeomInfoPi(edges[i2][0]),
+                                           el.GeomInfoPi(edges[i2][1]),
+                                           pp, ppgi);
+                    }
+                  else
+                    {
+                      p = p2 + xi[j] * (p1-p2);
+                      ref -> PointBetween (p2, p1, xi[j], 
+                                           mesh.GetFaceDescriptor(el.GetIndex()).SurfNr(),
+                                           el.GeomInfoPi(edges[i2][1]),
+                                           el.GeomInfoPi(edges[i2][0]),
+                                           pp, ppgi);
+                    }
+		
+                  Vec<3> dist = pp - p;
+		
+                  CalcEdgeShape (order1, 2*xi[j]-1, &shape(0));
+		
+                  for (int k = 0; k < ndof; k++)
+                    for (int l = 0; l < ndof; l++)
+                      mat(k,l) += weight[j] * shape(k) * shape(l);
+		
+                  for (int k = 0; k < ndof; k++)
+                    for (int l = 0; l < 3; l++)
+                      rhs(k,l) += weight[j] * shape(k) * dist(l);
+                }
+	    
+              CalcInverse (mat, inv);
+              Mult (inv, rhs, sol);
+	    
+              int first = edgecoeffsindex[edgenrs[i2]];
+              for (int j = 0; j < ndof; j++)
+                for (int k = 0; k < 3; k++)
+                  edgecoeffs[first+j](k) = sol(j,k);
+            }
+        }
+
+
+    
+    for (SegmentIndex i = 0; i < mesh.GetNSeg(); i++)
+      {
+	SetThreadPercent(double(i)/mesh.GetNSeg()*100.);
+	const Segment & seg = mesh[i];
+	PointIndex pi1 = mesh[i].p1;
+	PointIndex pi2 = mesh[i].p2;
+
+	bool swap = (pi1 > pi2);
+
+	Point<3> p1 = mesh[pi1];
+	Point<3> p2 = mesh[pi2];
+
+	int segnr = top.GetSegmentEdge (i+1)-1;
+
+	int order1 = edgeorder[segnr];
+	int ndof = max (0, order1-1);
+
+
+        if (rational)
+          {
+            Vec<3> tau1 = ref -> GetTangent (p1, seg.surfnr2, seg.surfnr1, seg.epgeominfo[0]);
+            Vec<3> tau2 = ref -> GetTangent (p2, seg.surfnr2, seg.surfnr1, seg.epgeominfo[1]);
+            // p1 + alpha1 tau1 = p2 + alpha2 tau2;
+
+            Mat<3,2> mat;
+            Mat<2,3> inv;
+            Vec<3> rhs;
+            Vec<2> sol;
+            for (int j = 0; j < 3; j++)
+              {
+                mat(j,0) = tau1(j); 
+                mat(j,1) = -tau2(j); 
+                rhs(j) = p2(j)-p1(j); 
+              }
+            CalcInverse (mat, inv);
+            sol = inv * rhs;
+
+            Point<3> p3 = p1+sol(0) * tau1;
+            edgecoeffs[edgecoeffsindex[segnr]] = Vec<3> (p3);
+
+            
+//             double dopt = 1e99;
+//             double wopt = 0;
+//             for (double w = 0; w <= 2; w += 0.0001)
+//               {
+//                 Vec<3> v05 = 0.25 * Vec<3> (p1) + 0.5*w* Vec<3>(p3) + 0.25 * Vec<3> (p2);
+//                 v05 /= 1 + (w-1) * 0.5;
+//                 Point<3> p05 (v05), pp05(v05);
+//                 ref -> ProjectToEdge (pp05, seg.surfnr1, seg.surfnr2, seg.epgeominfo[0]);
+//                 double d = Dist (pp05, p05);
+//                 if (d < dopt)
+//                   {
+//                     wopt = w;
+//                     dopt = d;
+//                   }
+//               }
+            
+            double wold = 1, w = 1, dw = 0.1;
+            double dold = 1e99;
+            while (fabs (dw) > 1e-12)
+              {
+                Vec<3> v05 = 0.25 * Vec<3> (p1) + 0.5*w* Vec<3>(p3) + 0.25 * Vec<3> (p2);
+                v05 /= 1 + (w-1) * 0.5;
+                Point<3> p05 (v05), pp05(v05);
+                ref -> ProjectToEdge (pp05, seg.surfnr1, seg.surfnr2, seg.epgeominfo[0]);
+                double d = Dist (pp05, p05);
+
+                if (d < dold)
+                  {
+                    dold = d;
+                    wold = w;
+                    w += dw;
+                  }
+                else
+                  {
+                    dw *= -0.7;
+                    w = wold + dw;
+                  }
+                // *testout << "w = " << w << ", dw = " << dw << endl;
+              }
+
+            // cout << "wopt = " << w << ", dopt = " << dold << endl;
+            edgeweight[segnr] = w;
+            
+//             cout << "p1 = " << p1 << ", tau1 = " << tau1 << ", alpha1 = " << sol(0) << endl;
+//             cout << "p2 = " << p2 << ", tau2 = " << tau2 << ", alpha2 = " << -sol(1) << endl;
+//             cout << "p+alpha tau = " << p1 + sol(0) * tau1 
+//                  << " =?= " << p2 +sol(1) * tau2 << endl;
+            
+          }
+
+        else
+          
+          {
+
+            Vector shape(ndof);
+            DenseMatrix mat(ndof, ndof), inv(ndof, ndof),
+              rhs(ndof, 3), sol(ndof, 3);
+
+            rhs = 0.0;
+            mat = 0.0;
+            for (int j = 0; j < xi.Size(); j++)
+              {
+                Point<3> p;
+
+                Point<3> pp;
+                EdgePointGeomInfo ppgi;
+	    
+                if (swap)
+                  {
+                    p = p1 + xi[j] * (p2-p1);
+                    ref -> PointBetween (p1, p2, xi[j], 
+                                         seg.surfnr2, seg.surfnr1, 
+                                         seg.epgeominfo[0], seg.epgeominfo[1],
+                                         pp, ppgi);
+                  }
+                else
+                  {
+                    p = p2 + xi[j] * (p1-p2);
+                    ref -> PointBetween (p2, p1, xi[j], 
+                                         seg.surfnr2, seg.surfnr1, 
+                                         seg.epgeominfo[1], seg.epgeominfo[0],
+                                         pp, ppgi);
+                  }
+	    
+                Vec<3> dist = pp - p;
+
+                CalcEdgeShape (order1, 2*xi[j]-1, &shape(0));
+
+                for (int k = 0; k < ndof; k++)
+                  for (int l = 0; l < ndof; l++)
+                    mat(k,l) += weight[j] * shape(k) * shape(l);
+
+                for (int k = 0; k < ndof; k++)
+                  for (int l = 0; l < 3; l++)
+                    rhs(k,l) += weight[j] * shape(k) * dist(l);
+              }
+
+            CalcInverse (mat, inv);
+            Mult (inv, rhs, sol);
+
+            int first = edgecoeffsindex[segnr];
+            for (int j = 0; j < ndof; j++)
+              for (int k = 0; k < 3; k++)
+                edgecoeffs[first+j](k) = sol(j,k);
+          }
+      }
+
+   
+
+    
+    PrintMessage (3, "Curving faces");
+
+    if (mesh.GetDimension() == 3)
+    for (SurfaceElementIndex i = 0; i < mesh.GetNSE(); i++)
+      {
+	SetThreadPercent(double(i)/mesh.GetNSE()*100.);
+	const Element2d & el = mesh[i];
+	int facenr = top.GetSurfaceElementFace (i+1)-1;
+
+	if (el.GetType() == TRIG && order >= 3)
+	  {
+	    int fnums[] = { 0, 1, 2 };
+	    if (el[fnums[0]] > el[fnums[1]]) swap (fnums[0], fnums[1]);
+	    if (el[fnums[1]] > el[fnums[2]]) swap (fnums[1], fnums[2]);
+	    if (el[fnums[0]] > el[fnums[1]]) swap (fnums[0], fnums[1]);
+
+	    int order1 = faceorder[facenr];
+	    int ndof = max (0, (order1-1)*(order1-2)/2);
+	    
+	    Vector shape(ndof);
+	    DenseMatrix mat(ndof, ndof), inv(ndof, ndof),
+	      rhs(ndof, 3), sol(ndof, 3);
+	    
+	    rhs = 0.0;
+	    mat = 0.0;
+
+	    for (int jx = 0; jx < xi.Size(); jx++)
+	      for (int jy = 0; jy < xi.Size(); jy++)
+		{
+		  double y = xi[jy];
+		  double x = (1-y) * xi[jx];
+		  double lami[] = { x, y, 1-x-y };
+		  double wi = weight[jx]*weight[jy]*(1-y);
+
+		  Point<2> xii (x, y);
+		  Point<3> p1, p2;
+		  CalcSurfaceTransformation (xii, i, p1);
+		  p2 = p1;
+		  ref -> ProjectToSurface (p2, mesh.GetFaceDescriptor(el.GetIndex()).SurfNr());
+
+		  Vec<3> dist = p2-p1;
+		
+		  CalcTrigShape (order1, lami[fnums[1]]-lami[fnums[0]],
+				 1-lami[fnums[1]]-lami[fnums[0]], &shape(0));
+
+		  for (int k = 0; k < ndof; k++)
+		    for (int l = 0; l < ndof; l++)
+		      mat(k,l) += wi * shape(k) * shape(l);
+		  
+		  for (int k = 0; k < ndof; k++)
+		    for (int l = 0; l < 3; l++)
+		      rhs(k,l) += wi * shape(k) * dist(l);
+		}
+
+	    CalcInverse (mat, inv);
+	    Mult (inv, rhs, sol);
+	    
+	    int first = facecoeffsindex[facenr];
+	    for (int j = 0; j < ndof; j++)
+	      for (int k = 0; k < 3; k++)
+		facecoeffs[first+j](k) = sol(j,k);
+	  }
+      }
+    
+    PrintMessage (3, "Complete");
+
+
+    // compress edge and face tables
+    int newbase = 0;
+    for (int i = 0; i < edgeorder.Size(); i++)
+      {
+	bool curved = 0;
+	int oldbase = edgecoeffsindex[i];
+	nd = edgecoeffsindex[i+1] - edgecoeffsindex[i];
+
+	for (int j = 0; j < nd; j++)
+	  if (edgecoeffs[oldbase+j].Length() > 1e-10)
+	    curved = 1;
+        if (rational) curved = 1;
+
+	if (curved && newbase != oldbase)
+	  for (int j = 0; j < nd; j++)
+	    edgecoeffs[newbase+j] = edgecoeffs[oldbase+j];
+
+	edgecoeffsindex[i] = newbase;
+	if (!curved) edgeorder[i] = 1;
+	if (curved) newbase += nd;
+      }
+    edgecoeffsindex.Last() = newbase;
+
+
+    newbase = 0;
+    for (int i = 0; i < faceorder.Size(); i++)
+      {
+	bool curved = 0;
+	int oldbase = facecoeffsindex[i];
+	nd = facecoeffsindex[i+1] - facecoeffsindex[i];
+
+	for (int j = 0; j < nd; j++)
+	  if (facecoeffs[oldbase+j].Length() > 1e-10)
+	    curved = 1;
+
+	if (curved && newbase != oldbase)
+	  for (int j = 0; j < nd; j++)
+	    facecoeffs[newbase+j] = facecoeffs[oldbase+j];
+
+	facecoeffsindex[i] = newbase;
+	if (!curved) faceorder[i] = 1;
+	if (curved) newbase += nd;
+      }
+    facecoeffsindex.Last() = newbase;
+
+    order = aorder;
+
+    // (*testout) << "edgecoeffs = " << endl << edgecoeffs << endl;
+    // (*testout) << "facecoeffs = " << endl << facecoeffs << endl;
+  }
+
+
+
+
+
+
+
+
+
+
+  // ***********************  Transform edges *****************************
+
+  
+  bool CurvedElements ::  IsSegmentCurved (SegmentIndex elnr) const
+  {
+    if (mesh.coarsemesh)
+      {
+	const HPRefElement & hpref_el =
+	  (*mesh.hpelements) [mesh[elnr].hp_elnr];
+	
+	return mesh.coarsemesh->GetCurvedElements().IsSegmentCurved (hpref_el.coarse_elnr);
+      }
+
+    SegmentInfo info;
+    info.elnr = elnr;
+    info.order = order;
+    info.ndof = info.nv = 2;
+    if (info.order > 1)
+      {
+	const MeshTopology & top = mesh.GetTopology();
+	info.edgenr = top.GetSegmentEdge (elnr+1)-1;	
+	info.ndof += edgeorder[info.edgenr]-1;
+      }
+
+    return (info.ndof > info.nv);
+  }
+
+
+ 
+  
+
+  void CurvedElements :: 
+  CalcSegmentTransformation (double xi, SegmentIndex elnr,
+			     Point<3> * x, Vec<3> * dxdxi, bool * curved)
+  {
+    if (mesh.coarsemesh)
+      {
+        *testout << "calcSegmentTrafo, coarse edge" << endl;
+
+	const HPRefElement & hpref_el =
+	  (*mesh.hpelements) [mesh[elnr].hp_elnr];
+	
+	// xi umrechnen
+	double lami[2] = { xi, 1-xi };
+	double dlami[2] = { 1, -1 };
+
+	double coarse_xi = 0;
+	double trans = 0;
+	for (int i = 0; i < 2; i++)
+	  {
+	    coarse_xi += hpref_el.param[i][0] * lami[i];
+	    trans += hpref_el.param[i][0] * dlami[i];
+	  }
+
+	mesh.coarsemesh->GetCurvedElements().CalcSegmentTransformation (coarse_xi, hpref_el.coarse_elnr, x, dxdxi, curved);
+	if (dxdxi) *dxdxi *= trans;
+	
+	return;
+      }
+    
+
+    Vector shapes, dshapes;
+    ARRAY<Vec<3> > coefs;
+
+    SegmentInfo info;
+    info.elnr = elnr;
+    info.order = order;
+    info.ndof = info.nv = 2;
+
+    if (info.order > 1)
+      {
+	const MeshTopology & top = mesh.GetTopology();
+	info.edgenr = top.GetSegmentEdge (elnr+1)-1;	
+	info.ndof += edgeorder[info.edgenr]-1;
+      }
+
+    CalcElementShapes (info, xi, shapes);
+    GetCoefficients (info, coefs);
+
+    *x = 0;
+    for (int i = 0; i < shapes.Size(); i++)
+      *x += shapes(i) * coefs[i];
+
+
+    if (dxdxi)
+      {
+	CalcElementDShapes (info, xi, dshapes);
+	
+	*dxdxi = 0;
+	for (int i = 0; i < shapes.Size(); i++)
+	  for (int j = 0; j < 3; j++)
+	    (*dxdxi)(j) += dshapes(i) * coefs[i](j);
+      }
+
+    if (curved)
+      *curved = (info.order > 1);
+  }
+
+
+
+
+  void CurvedElements :: 
+  CalcElementShapes (SegmentInfo & info, double xi, Vector & shapes) const
+  {
+    if (rational && info.order == 2)
+      {
+        shapes.SetSize(3);
+        double w = edgeweight[info.edgenr];
+        shapes(0) = xi*xi;
+        shapes(1) = (1-xi)*(1-xi);
+        shapes(2) = 2*w*xi*(1-xi);
+        shapes *= 1.0 / (1 + (w-1) *2*xi*(1-xi));
+        return;
+      }
+
+
+    shapes.SetSize(info.ndof);
+    shapes(0) = xi;
+    shapes(1) = 1-xi;
+
+    if (info.order >= 2)
+      {
+	if (mesh[info.elnr].p1 > mesh[info.elnr].p2)
+	  xi = 1-xi;
+	CalcEdgeShape (edgeorder[info.edgenr], 2*xi-1, &shapes(2));
+      }
+  }
+
+  void CurvedElements :: 
+  CalcElementDShapes (SegmentInfo & info, double xi, Vector & dshapes) const
+  {
+    if (rational && info.order == 2)
+      {
+        dshapes.SetSize(3);
+        double wi = edgeweight[info.edgenr];
+        double shapes[3];
+        shapes[0] = xi*xi;
+        shapes[1] = (1-xi)*(1-xi);
+        shapes[2] = 2*wi*xi*(1-xi);
+        double w = 1 + (wi-1) *2*xi*(1-xi);
+        double dw = (wi-1) * (2 - 4*xi);
+        
+        dshapes(0) = 2*xi;
+        dshapes(1) = 2*(xi-1);
+        dshapes(2) = 2*wi*(1-2*xi);
+
+        for (int j = 0;j < 3; j++)
+          dshapes(j) = dshapes(j) / w - shapes[j] * dw / (w*w);
+        return;
+      }
+
+
+
+
+
+
+    dshapes.SetSize(info.ndof);
+    dshapes = 0;
+    dshapes(0) = 1;
+    dshapes(1) = -1;
+
+    // int order = edgeorder[info.edgenr];
+
+    if (info.order >= 2)
+      {
+        double fac = 2;
+	if (mesh[info.elnr].p1 > mesh[info.elnr].p2)
+          {
+            xi = 1-xi; 
+            fac *= -1;
+          }
+	CalcEdgeDx (edgeorder[info.edgenr], 2*xi-1, &dshapes(2));
+        for (int i = 2; i < dshapes.Size(); i++)
+          dshapes(i) *= fac;
+      }
+
+    // ??? not implemented ????
+  }
+
+  void CurvedElements :: 
+  GetCoefficients (SegmentInfo & info, ARRAY<Vec<3> > & coefs) const
+  {
+    const Segment & el = mesh[info.elnr];
+
+    coefs.SetSize(info.ndof);
+
+    coefs[0] = Vec<3> (mesh[el.p1]);
+    coefs[1] = Vec<3> (mesh[el.p2]);
+
+    if (info.order >= 2)
+      {
+	int first = edgecoeffsindex[info.edgenr]; 
+	int next = edgecoeffsindex[info.edgenr+1]; 
+	for (int i = 0; i < next-first; i++)
+	  coefs[i+2] = edgecoeffs[first+i];
+      }
+  }
+
+
+
+
+
+
+
+
+
+
+
+
+
+  // ********************** Transform surface elements *******************
+
+
+  bool CurvedElements :: IsSurfaceElementCurved (SurfaceElementIndex elnr) const
+  {
+    if (mesh.coarsemesh)
+      {
+	const HPRefElement & hpref_el =
+	  (*mesh.hpelements) [mesh[elnr].hp_elnr];
+	
+	return mesh.coarsemesh->GetCurvedElements().IsSurfaceElementCurved (hpref_el.coarse_elnr);
+      }
+
+    const Element2d & el = mesh[elnr];
+    ELEMENT_TYPE type = el.GetType();
+    
+    SurfaceElementInfo info;
+    info.elnr = elnr;
+    info.order = order;
+    info.ndof = info.nv = (type == TRIG) ? 3 : 4;
+    if (info.order > 1)
+      {
+	const MeshTopology & top = mesh.GetTopology();
+	
+	top.GetSurfaceElementEdges (elnr+1, info.edgenrs);
+	for (int i = 0; i < info.edgenrs.Size(); i++)
+	  info.edgenrs[i]--;
+	info.facenr = top.GetSurfaceElementFace (elnr+1)-1;
+
+	for (int i = 0; i < info.edgenrs.Size(); i++)
+	  info.ndof += edgecoeffsindex[info.edgenrs[i]+1] - edgecoeffsindex[info.edgenrs[i]];
+	info.ndof += facecoeffsindex[info.facenr+1] - facecoeffsindex[info.facenr];
+      }
+
+    return (info.ndof > info.nv);
+  }
+  
+  void CurvedElements :: 
+  CalcSurfaceTransformation (Point<2> xi, SurfaceElementIndex elnr,
+			     Point<3> * x, Mat<3,2> * dxdxi, bool * curved)
+  {
+    if (mesh.coarsemesh)
+      {
+	const HPRefElement & hpref_el =
+	  (*mesh.hpelements) [mesh[elnr].hp_elnr];
+	
+	  // xi umrechnen
+	double lami[4];
+	FlatVector vlami(4, lami);
+	vlami = 0;
+	mesh[elnr].GetShapeNew (xi, vlami);
+	
+	Mat<2,2> trans;
+	Mat<3,2> dxdxic;
+	if (dxdxi)
+	  {
+	    MatrixFixWidth<2> dlami(4);
+	    dlami = 0;
+	    mesh[elnr].GetDShapeNew (xi, dlami);	  
+	    
+	    trans = 0;
+	    for (int k = 0; k < 2; k++)
+	      for (int l = 0; l < 2; l++)
+		for (int i = 0; i < hpref_el.np; i++)
+		  trans(l,k) += hpref_el.param[i][l] * dlami(i, k);
+	    }
+	
+	Point<2> coarse_xi(0,0);
+	for (int i = 0; i < hpref_el.np; i++)
+	  for (int j = 0; j < 2; j++)
+	    coarse_xi(j) += hpref_el.param[i][j] * lami[i];
+	
+	mesh.coarsemesh->GetCurvedElements().CalcSurfaceTransformation (coarse_xi, hpref_el.coarse_elnr, x, &dxdxic, curved);
+	
+	if (dxdxi)
+	  *dxdxi = dxdxic * trans;
+	
+	return;
+      }
+    
+
+
+    Vector shapes;
+    DenseMatrix dshapes;
+    ARRAY<Vec<3> > coefs;
+
+    const Element2d & el = mesh[elnr];
+    ELEMENT_TYPE type = el.GetType();
+
+    SurfaceElementInfo info;
+    info.elnr = elnr;
+    info.order = order;
+    info.ndof = info.nv = (type == TRIG) ? 3 : 4;
+    if (info.order > 1)
+      {
+	const MeshTopology & top = mesh.GetTopology();
+	
+	top.GetSurfaceElementEdges (elnr+1, info.edgenrs);
+	for (int i = 0; i < info.edgenrs.Size(); i++)
+	  info.edgenrs[i]--;
+	info.facenr = top.GetSurfaceElementFace (elnr+1)-1;
+
+
+	bool firsttry = true;
+	bool problem = false;
+
+	while(firsttry || problem)
+	  {
+	    problem = false;
+
+	    for (int i = 0; !problem && i < info.edgenrs.Size(); i++)
+	      {
+		if(info.edgenrs[i]+1 >= edgecoeffsindex.Size())
+		  problem = true;
+		else
+		  info.ndof += edgecoeffsindex[info.edgenrs[i]+1] - edgecoeffsindex[info.edgenrs[i]];
+	      }
+	    if(info.facenr+1 >= facecoeffsindex.Size())
+	      problem = true;
+	    else
+	      info.ndof += facecoeffsindex[info.facenr+1] - facecoeffsindex[info.facenr];
+
+	    if(problem && !firsttry)
+	      throw NgException("something wrong with curved elements");
+	    
+	    if(problem)
+	      BuildCurvedElements(NULL,order,rational);
+
+	    firsttry = false;
+	  }
+      }
+
+    CalcElementShapes (info, xi, shapes);
+    GetCoefficients (info, coefs);
+
+    *x = 0;
+    for (int i = 0; i < coefs.Size(); i++)
+      *x += shapes(i) * coefs[i];
+
+    if (dxdxi)
+      {
+	CalcElementDShapes (info, xi, dshapes);
+	
+	*dxdxi = 0;
+	for (int i = 0; i < coefs.Size(); i++)
+	  for (int j = 0; j < 3; j++)
+	    for (int k = 0; k < 2; k++)
+	      (*dxdxi)(j,k) += dshapes(i,k) * coefs[i](j);
+      }
+
+    if (curved)
+      *curved = (info.ndof > info.nv);
+  }
+
+
+
+
+  void CurvedElements :: 
+  CalcElementShapes (SurfaceElementInfo & info, const Point<2> & xi, Vector & shapes) const
+  {
+    const Element2d & el = mesh[info.elnr];
+
+    shapes.SetSize(info.ndof);
+    shapes = 0;	  
+
+    if (rational && info.order >= 2)
+      {
+        shapes.SetSize(6);
+        double w = 1;
+        double lami[3] = { xi(0), xi(1), 1-xi(0)-xi(1) };
+        for (int j = 0; j < 3; j++)
+          shapes(j) = lami[j] * lami[j];
+
+        const ELEMENT_EDGE * edges = MeshTopology::GetEdges (TRIG);
+        for (int j = 0; j < 3; j++)
+          {
+            double wi = edgeweight[info.edgenrs[j]];
+            shapes(j+3) = 2 * wi * lami[edges[j][0]-1] * lami[edges[j][1]-1];
+            w += (wi-1) * 2 * lami[edges[j][0]-1] * lami[edges[j][1]-1];
+          }
+
+        shapes *= 1.0 / w;
+        return;
+      }
+
+    switch (el.GetType())
+      {
+      case TRIG:
+	{
+	  shapes(0) = xi(0);
+	  shapes(1) = xi(1);
+	  shapes(2) = 1-xi(0)-xi(1);
+
+	  if (info.order == 1) return;
+
+	  int ii = 3;
+	  const ELEMENT_EDGE * edges = MeshTopology::GetEdges (TRIG);
+	  
+	  for (int i = 0; i < 3; i++)
+	    {
+	      int eorder = edgeorder[info.edgenrs[i]];
+	      if (eorder >= 2)
+		{
+		  int vi1 = edges[i][0]-1, vi2 = edges[i][1]-1;
+		  if (el[vi1] > el[vi2]) swap (vi1, vi2);
+
+		  CalcScaledEdgeShape (eorder, shapes(vi1)-shapes(vi2), shapes(vi1)+shapes(vi2), &shapes(ii));
+		  ii += eorder-1;
+		}
+	    }
+
+	  int forder = faceorder[info.facenr];
+	  if (forder >= 3)
+	    {
+	      int fnums[] = { 0, 1, 2 };
+	      if (el[fnums[0]] > el[fnums[1]]) swap (fnums[0], fnums[1]);
+	      if (el[fnums[1]] > el[fnums[2]]) swap (fnums[1], fnums[2]);
+	      if (el[fnums[0]] > el[fnums[1]]) swap (fnums[0], fnums[1]);
+	      
+	      CalcTrigShape (forder, 
+			     shapes(fnums[1])-shapes(fnums[0]),
+			     1-shapes(fnums[1])-shapes(fnums[0]), &shapes(ii));
+	    }
+	  break;
+	}
+
+      case QUAD:
+	{
+	  shapes(0) = (1-xi(0))*(1-xi(1));
+	  shapes(1) =    xi(0) *(1-xi(1));
+	  shapes(2) =    xi(0) *   xi(1) ;
+	  shapes(3) = (1-xi(0))*   xi(1) ;
+
+	  if (info.order == 1) return;
+	  
+	  double mu[4] = { 
+	    1 - xi(0) + 1 - xi(1), 
+	        xi(0) + 1 - xi(1), 
+	        xi(0) +     xi(1), 
+	    1 - xi(0) +     xi(1), 
+	  };
+	    
+	  int ii = 4;
+	  const ELEMENT_EDGE * edges = MeshTopology::GetEdges (QUAD);
+	  
+	  for (int i = 0; i < 4; i++)
+	    {
+	      int eorder = edgeorder[info.edgenrs[i]];
+	      if (eorder >= 2)
+		{
+		  int vi1 = edges[i][0]-1, vi2 = edges[i][1]-1;
+		  if (el[vi1] > el[vi2]) swap (vi1, vi2);
+
+		  CalcEdgeShape (eorder, mu[vi1]-mu[vi2], &shapes(ii));
+		  double lame = shapes(vi1)+shapes(vi2);
+		  for (int j = 0; j < order-1; j++)
+		    shapes(ii+j) *= lame;
+		  ii += eorder-1;
+		}
+	    }
+	  
+	  for (int i = ii; i < info.ndof; i++)
+	    shapes(i) = 0;
+
+	  break;
+	}
+      };
+  }
+
+
+  void CurvedElements :: 
+  CalcElementDShapes (SurfaceElementInfo & info, const Point<2> & xi, DenseMatrix & dshapes) const
+  {
+    const Element2d & el = mesh[info.elnr];
+    ELEMENT_TYPE type = el.GetType();
+
+    double lami[4];
+
+    dshapes.SetSize(info.ndof,2);
+    dshapes = 0;	  
+
+
+
+    if (rational && info.order >= 2)
+      {
+        double w = 1;
+        double dw[2] = { 0, 0 };
+
+
+        lami[0] = xi(0); lami[1] = xi(1); lami[2] = 1-xi(0)-xi(1);
+        double dlami[3][2] = { { 1, 0 }, { 0, 1 }, { -1, -1 }};
+        double shapes[6];
+
+        for (int j = 0; j < 3; j++)
+          {
+            shapes[j] = lami[j] * lami[j];
+            dshapes(j,0) = 2 * lami[j] * dlami[j][0];
+            dshapes(j,1) = 2 * lami[j] * dlami[j][1];
+          }
+
+        const ELEMENT_EDGE * edges = MeshTopology::GetEdges (TRIG);
+        for (int j = 0; j < 3; j++)
+          {
+            double wi = edgeweight[info.edgenrs[j]];
+
+            shapes[j+3] = 2 * wi * lami[edges[j][0]-1] * lami[edges[j][1]-1];
+            for (int k = 0; k < 2; k++)
+              dshapes(j+3,k) = 2*wi* (lami[edges[j][0]-1] * dlami[edges[j][1]-1][k] +
+                                      lami[edges[j][1]-1] * dlami[edges[j][0]-1][k]);
+
+            w += (wi-1) * 2 * lami[edges[j][0]-1] * lami[edges[j][1]-1];
+            for (int k = 0; k < 2; k++)
+              dw[k] += 2*(wi-1) * (lami[edges[j][0]-1] * dlami[edges[j][1]-1][k] +
+                                  lami[edges[j][1]-1] * dlami[edges[j][0]-1][k]);
+          }
+        // shapes *= 1.0 / w;
+        dshapes *= 1.0 / w;
+        for (int i = 0; i < 6; i++)
+          for (int j = 0; j < 2; j++)
+            dshapes(i,j) -= shapes[i] * dw[j] / (w*w);
+        return;
+      }
+
+
+
+
+
+    switch (type)
+      {
+      case TRIG:
+	{
+	  dshapes(0,0) = 1;
+	  dshapes(1,1) = 1;
+	  dshapes(2,0) = -1;
+	  dshapes(2,1) = -1;
+	  
+	  if (info.order == 1) return;
+
+	  lami[0] = xi(0);
+	  lami[1] = xi(1);
+	  lami[2] = 1-xi(0)-xi(1);
+
+	  int ii = 3;
+	  const ELEMENT_EDGE * edges = MeshTopology::GetEdges (TRIG);
+	  
+	  for (int i = 0; i < 3; i++)
+	    {
+	      int eorder = edgeorder[info.edgenrs[i]];
+	      if (eorder >= 2)
+		{
+		  int vi1 = edges[i][0]-1, vi2 = edges[i][1]-1;
+		  if (el[vi1] > el[vi2]) swap (vi1, vi2);
+
+		  CalcScaledEdgeShapeDxDt<2> (eorder, lami[vi1]-lami[vi2], lami[vi1]+lami[vi2], &dshapes(ii,0));
+
+		  Mat<2,2> trans;
+		  for (int j = 0; j < 2; j++)
+		    {
+		      trans(0,j) = dshapes(vi1,j)-dshapes(vi2,j);
+		      trans(1,j) = dshapes(vi1,j)+dshapes(vi2,j);
+		    }
+		  
+		  for (int j = 0; j < eorder-1; j++)
+		    {
+		      double ddx = dshapes(ii+j,0);
+		      double ddt = dshapes(ii+j,1);
+		      dshapes(ii+j,0) = ddx * trans(0,0) + ddt * trans(1,0);
+		      dshapes(ii+j,1) = ddx * trans(0,1) + ddt * trans(1,1);
+		    }
+
+		  ii += eorder-1;
+		}
+	    }
+
+	  int forder = faceorder[info.facenr];
+	  if (forder >= 3)
+	    {
+	      int fnums[] = { 0, 1, 2 };
+	      if (el[fnums[0]] > el[fnums[1]]) swap (fnums[0], fnums[1]);
+	      if (el[fnums[1]] > el[fnums[2]]) swap (fnums[1], fnums[2]);
+	      if (el[fnums[0]] > el[fnums[1]]) swap (fnums[0], fnums[1]);
+	      
+	      CalcTrigShapeDxDy (forder, 
+				 lami[fnums[1]]-lami[fnums[0]],
+				 1-lami[fnums[1]]-lami[fnums[0]], &dshapes(ii,0));
+
+	      int nd = (forder-1)*(forder-2)/2;
+	      Mat<2,2> trans;
+	      for (int j = 0; j < 2; j++)
+		{
+		  trans(0,j) = dshapes(fnums[1],j)-dshapes(fnums[0],j);
+		  trans(1,j) = -dshapes(fnums[1],j)-dshapes(fnums[0],j);
+		}
+
+	      for (int j = 0; j < nd; j++)
+		{
+		  double ddx = dshapes(ii+j,0);
+		  double ddt = dshapes(ii+j,1);
+		  dshapes(ii+j,0) = ddx * trans(0,0) + ddt * trans(1,0);
+		  dshapes(ii+j,1) = ddx * trans(0,1) + ddt * trans(1,1);
+		}
+	    }
+
+	  break;
+	}
+      case QUAD:
+	{
+	  dshapes(0,0) = -(1-xi(1));
+	  dshapes(0,1) = -(1-xi(0));
+	  dshapes(1,0) =  (1-xi(1));
+	  dshapes(1,1) =    -xi(0);
+	  dshapes(2,0) =     xi(1);
+	  dshapes(2,1) =     xi(0);
+	  dshapes(3,0) =    -xi(1);
+	  dshapes(3,1) =  (1-xi(0));
+
+	  if (info.order == 1) return;
+
+	  double shapes[4] = {
+	    (1-xi(0))*(1-xi(1)),
+	       xi(0) *(1-xi(1)),
+	       xi(0) *   xi(1) ,
+	    (1-xi(0))*   xi(1) 
+	  };
+
+	  double mu[4] = { 
+	    1 - xi(0) + 1 - xi(1), 
+	        xi(0) + 1 - xi(1), 
+	        xi(0) +     xi(1), 
+	    1 - xi(0) +     xi(1), 
+	  };
+
+	  double dmu[4][2] = {
+	    { -1, -1 },
+	    { 1, -1 },
+	    { 1, 1 },
+	    { -1, 1 } };
+	    
+	  // double hshapes[20], hdshapes[20];
+          ArrayMem<double, 20> hshapes(order+1), hdshapes(order+1);
+
+	  int ii = 4;
+	  const ELEMENT_EDGE * edges = MeshTopology::GetEdges (QUAD);
+	  
+	  for (int i = 0; i < 4; i++)
+	    {
+	      int eorder = edgeorder[info.edgenrs[i]];
+	      if (eorder >= 2)
+		{
+		  int vi1 = edges[i][0]-1, vi2 = edges[i][1]-1;
+		  if (el[vi1] > el[vi2]) swap (vi1, vi2);
+
+		  CalcEdgeShapeDx (eorder, mu[vi1]-mu[vi2], &hshapes[0], &hdshapes[0]);
+
+		  double lame = shapes[vi1]+shapes[vi2];
+		  double dlame[2] = {
+		    dshapes(vi1, 0) + dshapes(vi2, 0),
+		    dshapes(vi1, 1) + dshapes(vi2, 1) };
+		    
+		  for (int j = 0; j < eorder-1; j++)
+		    for (int k = 0; k < 2; k++)
+		      dshapes(ii+j, k) = 
+			lame * hdshapes[j] * (dmu[vi1][k]-dmu[vi2][k])
+			+ dlame[k] * hshapes[j];
+
+		  ii += eorder-1;
+		}
+	    }
+
+	  /*	  
+	  *testout << "quad, dshape = " << endl << dshapes << endl;
+	  for (int i = 0; i < 2; i++)
+	    {
+	      Point<2> xil = xi, xir = xi;
+	      Vector shapesl(dshapes.Height()), shapesr(dshapes.Height());
+	      xil(i) -= 1e-6;
+	      xir(i) += 1e-6;
+	      CalcElementShapes (info, xil, shapesl);
+	      CalcElementShapes (info, xir, shapesr);
+	      
+	      for (int j = 0; j < dshapes.Height(); j++)
+		dshapes(j,i) = 1.0 / 2e-6 * (shapesr(j)-shapesl(j));
+	    }
+	  
+	  *testout << "quad, num dshape = " << endl << dshapes << endl;
+	  */
+	  break;
+	}
+      };
+  }
+
+
+
+  void CurvedElements :: 
+  GetCoefficients (SurfaceElementInfo & info, ARRAY<Vec<3> > & coefs) const
+  {
+    const Element2d & el = mesh[info.elnr];
+
+    coefs.SetSize (info.ndof);
+    // coefs = Vec<3> (0,0,0);
+    
+    for (int i = 0; i < info.nv; i++)
+      coefs[i] = Vec<3> (mesh[el[i]]);
+    
+    if (info.order == 1) return;
+
+    int ii = info.nv;
+	  
+    for (int i = 0; i < info.edgenrs.Size(); i++)
+      {
+	int first = edgecoeffsindex[info.edgenrs[i]];
+	int next = edgecoeffsindex[info.edgenrs[i]+1];
+	for (int j = first; j < next; j++, ii++)
+	  coefs[ii] = edgecoeffs[j];
+      }
+    
+    int first = facecoeffsindex[info.facenr];
+    int next = facecoeffsindex[info.facenr+1];
+    for (int j = first; j < next; j++, ii++)
+      coefs[ii] = facecoeffs[j];
+  }
+
+
+
+
+
+
+
+  // ********************** Transform volume elements *******************
+
+
+  bool CurvedElements :: IsElementCurved (ElementIndex elnr) const
+  {
+    if (mesh.coarsemesh)
+      {
+	const HPRefElement & hpref_el =
+	  (*mesh.hpelements) [mesh[elnr].hp_elnr];
+	
+	return mesh.coarsemesh->GetCurvedElements().IsElementCurved (hpref_el.coarse_elnr);
+      }
+
+    const Element & el = mesh[elnr];
+    ELEMENT_TYPE type = el.GetType();
+    
+    ElementInfo info;
+    info.elnr = elnr;
+    info.order = order;
+    info.ndof = info.nv = MeshTopology::GetNVertices (type);
+    if (info.order > 1)
+      {
+	const MeshTopology & top = mesh.GetTopology();
+	
+	info.nedges = top.GetElementEdges (elnr+1, info.edgenrs, 0);
+	for (int i = 0; i < info.nedges; i++)
+	  info.edgenrs[i]--;
+
+	info.nfaces = top.GetElementFaces (elnr+1, info.facenrs, 0);
+	for (int i = 0; i < info.nfaces; i++)
+	  info.facenrs[i]--;
+
+	for (int i = 0; i < info.nedges; i++)
+	  info.ndof += edgecoeffsindex[info.edgenrs[i]+1] - edgecoeffsindex[info.edgenrs[i]];
+	for (int i = 0; i < info.nfaces; i++)
+	  info.ndof += facecoeffsindex[info.facenrs[i]+1] - facecoeffsindex[info.facenrs[i]];
+      }
+
+    return (info.ndof > info.nv);
+  }
+
+
+
+
+
+
+  void CurvedElements :: 
+  CalcElementTransformation (Point<3> xi, ElementIndex elnr,
+			     Point<3> * x, Mat<3,3> * dxdxi, //  bool * curved,
+                             void * buffer, bool valid)
+  {
+    if (mesh.coarsemesh)
+      {
+	  const HPRefElement & hpref_el =
+	    (*mesh.hpelements) [mesh[elnr].hp_elnr];
+	  
+	  // xi umrechnen
+	  double lami[8];
+	  FlatVector vlami(8, lami);
+	  vlami = 0;
+	  mesh[elnr].GetShapeNew (xi, vlami);
+
+	  Mat<3,3> trans, dxdxic;
+	  if (dxdxi)
+	    {
+	      MatrixFixWidth<3> dlami(8);
+	      dlami = 0;
+	      mesh[elnr].GetDShapeNew (xi, dlami);	  
+	      
+	      trans = 0;
+	      for (int k = 0; k < 3; k++)
+		for (int l = 0; l < 3; l++)
+		  for (int i = 0; i < hpref_el.np; i++)
+		    trans(l,k) += hpref_el.param[i][l] * dlami(i, k);
+	    }
+
+	  Point<3> coarse_xi(0,0,0);
+	  for (int i = 0; i < hpref_el.np; i++)
+	    for (int j = 0; j < 3; j++)
+	      coarse_xi(j) += hpref_el.param[i][j] * lami[i];
+
+	  mesh.coarsemesh->GetCurvedElements().CalcElementTransformation (coarse_xi, hpref_el.coarse_elnr, x, &dxdxic /* , curved */);
+
+	  if (dxdxi)
+	    *dxdxi = dxdxic * trans;
+
+	  return;
+	}
+
+
+    Vector shapes;
+    MatrixFixWidth<3> dshapes;
+
+    const Element & el = mesh[elnr];
+    ELEMENT_TYPE type = el.GetType();
+
+    ElementInfo hinfo;
+    ElementInfo & info = (buffer) ? *static_cast<ElementInfo*> (buffer) : hinfo;
+    
+
+    if (!valid)
+      {
+        info.elnr = elnr;
+        info.order = order;
+        info.ndof = info.nv = MeshTopology::GetNVertices (type);
+        if (info.order > 1)
+          {
+            const MeshTopology & top = mesh.GetTopology();
+            
+            info.nedges = top.GetElementEdges (elnr+1, info.edgenrs, 0);
+            for (int i = 0; i < info.nedges; i++)
+              info.edgenrs[i]--;
+            
+            info.nfaces = top.GetElementFaces (elnr+1, info.facenrs, 0);
+            for (int i = 0; i < info.nfaces; i++)
+              info.facenrs[i]--;
+            
+            for (int i = 0; i < info.nedges; i++)
+              info.ndof += edgecoeffsindex[info.edgenrs[i]+1] - edgecoeffsindex[info.edgenrs[i]];
+            for (int i = 0; i < info.nfaces; i++)
+              info.ndof += facecoeffsindex[info.facenrs[i]+1] - facecoeffsindex[info.facenrs[i]];
+          }
+      }
+
+    CalcElementShapes (info, xi, shapes);
+
+    Vec<3> * coefs =  (info.ndof <= 10) ? 
+      &info.hcoefs[0] : new Vec<3> [info.ndof];
+
+    if (info.ndof > 10 || !valid)
+      GetCoefficients (info, coefs);
+
+    if (x)
+      {
+        *x = 0;
+        for (int i = 0; i < shapes.Size(); i++)
+          *x += shapes(i) * coefs[i];
+      }
+
+    if (dxdxi)
+      {
+        if (valid && info.order == 1 && info.nv == 4)   // a linear tet
+          {
+            *dxdxi = info.hdxdxi;
+          }
+        else
+          {
+            CalcElementDShapes (info, xi, dshapes);
+            
+            *dxdxi = 0;
+            for (int i = 0; i < shapes.Size(); i++)
+              for (int j = 0; j < 3; j++)
+                for (int k = 0; k < 3; k++)
+                  (*dxdxi)(j,k) += dshapes(i,k) * coefs[i](j);
+            
+            info.hdxdxi = *dxdxi;
+          }
+      }
+
+    // *testout << "curved_elements, dshapes = " << endl << dshapes << endl;
+
+    //    if (curved) *curved = (info.ndof > info.nv);
+
+    if (info.ndof > 10) delete [] coefs;
+  }
+
+
+
+
+  void CurvedElements ::   CalcElementShapes (ElementInfo & info, const Point<3> & xi, Vector & shapes) const
+  {
+    const Element & el = mesh[info.elnr];
+
+    if (rational && info.order >= 2)
+      {
+        shapes.SetSize(10);
+        double w = 1;
+        double lami[4] = { xi(0), xi(1), xi(2), 1-xi(0)-xi(1)-xi(2) };
+        for (int j = 0; j < 4; j++)
+          shapes(j) = lami[j] * lami[j];
+
+        const ELEMENT_EDGE * edges = MeshTopology::GetEdges (TET);
+        for (int j = 0; j < 6; j++)
+          {
+            double wi = edgeweight[info.edgenrs[j]];
+            shapes(j+4) = 2 * wi * lami[edges[j][0]-1] * lami[edges[j][1]-1];
+            w += (wi-1) * 2 * lami[edges[j][0]-1] * lami[edges[j][1]-1];
+          }
+
+        shapes *= 1.0 / w;
+        return;
+      }
+
+    shapes.SetSize(info.ndof);
+    
+    switch (el.GetType())
+      {
+      case TET:
+	{
+	  shapes(0) = xi(0);
+	  shapes(1) = xi(1);
+	  shapes(2) = xi(2);
+	  shapes(3) = 1-xi(0)-xi(1)-xi(2);
+
+	  if (info.order == 1) return;
+
+	  int ii = 4;
+	  const ELEMENT_EDGE * edges = MeshTopology::GetEdges (TET);
+	  for (int i = 0; i < 6; i++)
+	    {
+	      int eorder = edgeorder[info.edgenrs[i]];
+	      if (eorder >= 2)
+		{
+		  int vi1 = edges[i][0]-1, vi2 = edges[i][1]-1;
+		  if (el[vi1] > el[vi2]) swap (vi1, vi2);
+
+		  CalcScaledEdgeShape (eorder, shapes(vi1)-shapes(vi2), shapes(vi1)+shapes(vi2), &shapes(ii));
+		  ii += eorder-1;
+		}
+	    }
+	  const ELEMENT_FACE * faces = MeshTopology::GetFaces (TET);
+	  for (int i = 0; i < 4; i++)
+	    {
+	      int forder = faceorder[info.facenrs[i]];
+	      if (forder >= 3)
+		{
+		  int fnums[] = { faces[i][0]-1, faces[i][1]-1, faces[i][2]-1 }; 
+		  if (el[fnums[0]] > el[fnums[1]]) swap (fnums[0], fnums[1]);
+		  if (el[fnums[1]] > el[fnums[2]]) swap (fnums[1], fnums[2]);
+		  if (el[fnums[0]] > el[fnums[1]]) swap (fnums[0], fnums[1]);
+
+		  CalcScaledTrigShape (forder, 
+				       shapes(fnums[1])-shapes(fnums[0]), shapes(fnums[2]), 
+				       shapes(fnums[0])+shapes(fnums[1])+shapes(fnums[2]), &shapes(ii));
+		  ii += (forder-1)*(forder-2)/2;
+		  // CalcScaledEdgeShape (forder, shapes(vi1)-shapes(vi2), shapes(vi1)+shapes(vi2), &shapes(ii));
+		  // ii += forder-1;
+		}
+	    }
+
+
+	  break;
+	}
+      case PRISM:
+	{
+	  double lami[6] = { xi(0), xi(1), 1-xi(0)-xi(1), xi(0), xi(1), 1-xi(0)-xi(1) };
+	  double lamiz[6] = { 1-xi(2), 1-xi(2), 1-xi(2), xi(2), xi(2), xi(2) };
+	  for (int i = 0; i < 6; i++)
+	    shapes(i) = lami[i%3] * ( (i < 3) ? (1-xi(2)) : xi(2) );
+	  for (int i = 6; i < info.ndof; i++)
+	    shapes(i) = 0;
+
+          if (info.order == 1) return;
+
+
+	  int ii = 6;
+ 	  const ELEMENT_EDGE * edges = MeshTopology::GetEdges (PRISM);
+	  for (int i = 0; i < 6; i++)    // horizontal edges
+	    {
+	      int eorder = edgeorder[info.edgenrs[i]];
+	      if (eorder >= 2)
+		{
+		  int vi1 = (edges[i][0]-1) % 3, vi2 = (edges[i][1]-1) % 3;
+		  if (el[vi1] > el[vi2]) swap (vi1, vi2);
+
+		  CalcScaledEdgeShape (eorder, lami[vi1]-lami[vi2], lami[vi1]+lami[vi2], &shapes(ii));
+		  double facz = (i < 3) ? (1-xi(2)) : xi(2);
+		  for (int j = 0; j < eorder-1; j++)
+		    shapes(ii+j) *= facz;
+
+		  ii += eorder-1;
+		}
+	    }
+
+	  for (int i = 6; i < 9; i++)    // vertical edges
+	    {
+	      int eorder = edgeorder[info.edgenrs[i]];
+	      if (eorder >= 2)
+		{
+		  int vi1 = (edges[i][0]-1), vi2 = (edges[i][1]-1);
+		  if (el[vi1] > el[vi2]) swap (vi1, vi2);
+
+		  double bubz = lamiz[vi1]*lamiz[vi2];
+		  double polyz = lamiz[vi1] - lamiz[vi2];
+		  double bubxy = lami[(vi1)%3];
+
+		  for (int j = 0; j < eorder-1; j++)
+		    {
+		      shapes(ii+j) = bubxy * bubz;
+		      bubz *= polyz;
+		    }
+		  ii += eorder-1;
+		}
+	    }
+
+	  // FACE SHAPES
+	  const ELEMENT_FACE * faces = MeshTopology::GetFaces (PRISM);
+	  for (int i = 0; i < 2; i++)
+	    {
+	      int forder = faceorder[info.facenrs[i]];
+	      if ( forder < 3 ) continue;
+	      int fav[3] = { faces[i][0]-1, faces[i][1]-1, faces[i][2]-1 };
+	      if(el[fav[0]] > el[fav[1]]) swap(fav[0],fav[1]); 
+	      if(el[fav[1]] > el[fav[2]]) swap(fav[1],fav[2]);
+	      if(el[fav[0]] > el[fav[1]]) swap(fav[0],fav[1]); 	
+
+	      CalcTrigShape (forder, 
+			     lami[fav[2]]-lami[fav[1]], lami[fav[0]],
+			     &shapes(ii));
+	      
+	      int ndf = (forder+1)*(forder+2)/2 - 3 - 3*(forder-1);
+	      for ( int j = 0; j < ndf; j++ )
+		shapes(ii+j) *= lamiz[fav[1]];
+	      ii += ndf;
+	    }
+	  break;
+	}
+
+      case PYRAMID:
+	{
+	  shapes = 0.0;
+	  double x = xi(0);
+	  double y = xi(1);
+	  double z = xi(2);
+	  
+	  if (z == 1.) z = 1-1e-10;
+	  shapes[0] = (1-z-x)*(1-z-y) / (1-z);
+	  shapes[1] = x*(1-z-y) / (1-z);
+	  shapes[2] = x*y / (1-z);
+	  shapes[3] = (1-z-x)*y / (1-z);
+	  shapes[4] = z;
+          
+          if (info.order == 1) return;
+
+	  int ii = 5;
+	  const ELEMENT_EDGE * edges = MeshTopology::GetEdges (PYRAMID);
+	  for (int i = 0; i < 4; i++)    // horizontal edges
+	    {
+	      int eorder = edgeorder[info.edgenrs[i]];
+	      if (eorder >= 2)
+		{
+		  int vi1 = (edges[i][0]-1), vi2 = (edges[i][1]-1);
+		  if (el[vi1] > el[vi2]) swap (vi1, vi2);
+
+		  CalcScaledEdgeShape (eorder, shapes[vi1]-shapes[vi2], shapes[vi1]+shapes[vi2], &shapes(ii));
+		  double fac = (shapes[vi1]+shapes[vi2]) / (1-z);
+		  for (int j = 0; j < eorder-1; j++)
+		    shapes(ii+j) *= fac;
+
+		  ii += eorder-1;
+		}
+	    }
+
+
+
+	  break;
+	}
+
+      case HEX:
+        {
+	  shapes = 0.0;
+	  double x = xi(0);
+	  double y = xi(1);
+	  double z = xi(2);
+	  
+	  shapes[0] = (1-x)*(1-y)*(1-z);
+	  shapes[1] =    x *(1-y)*(1-z);
+	  shapes[2] =    x *   y *(1-z);
+	  shapes[3] = (1-x)*   y *(1-z);
+	  shapes[4] = (1-x)*(1-y)*(z);
+	  shapes[5] =    x *(1-y)*(z);
+	  shapes[6] =    x *   y *(z);
+	  shapes[7] = (1-x)*   y *(z);
+          break;
+        }
+      };
+  }
+
+
+  void CurvedElements :: 
+  CalcElementDShapes (ElementInfo & info, const Point<3> & xi, MatrixFixWidth<3> & dshapes) const
+  {
+    const Element & el = mesh[info.elnr];
+
+    dshapes.SetSize(info.ndof);
+    dshapes = 0.0;
+
+
+
+    if (rational && info.order >= 2)
+      {
+        double w = 1;
+        double dw[3] = { 0, 0, 0 };
+
+        double lami[4] = { xi(0), xi(1), xi(2), 1-xi(0)-xi(1)-xi(2) };
+        double dlami[4][3] = { { 1, 0, 0 }, { 0, 1, 0 }, { 0, 0, 1 }, { -1, -1, -1 }};
+        double shapes[10];
+
+        for (int j = 0; j < 4; j++)
+          {
+            shapes[j] = lami[j] * lami[j];
+            dshapes(j,0) = 2 * lami[j] * dlami[j][0];
+            dshapes(j,1) = 2 * lami[j] * dlami[j][1];
+            dshapes(j,2) = 2 * lami[j] * dlami[j][2];
+          }
+
+        const ELEMENT_EDGE * edges = MeshTopology::GetEdges (TET);
+        for (int j = 0; j < 6; j++)
+          {
+            double wi = edgeweight[info.edgenrs[j]];
+
+            shapes[j+4] = 2 * wi * lami[edges[j][0]-1] * lami[edges[j][1]-1];
+            for (int k = 0; k < 3; k++)
+              dshapes(j+4,k) = 2*wi* (lami[edges[j][0]-1] * dlami[edges[j][1]-1][k] +
+                                      lami[edges[j][1]-1] * dlami[edges[j][0]-1][k]);
+
+            w += (wi-1) * 2 * lami[edges[j][0]-1] * lami[edges[j][1]-1];
+            for (int k = 0; k < 3; k++)
+              dw[k] += 2*(wi-1) * (lami[edges[j][0]-1] * dlami[edges[j][1]-1][k] +
+                                   lami[edges[j][1]-1] * dlami[edges[j][0]-1][k]);
+          }
+        // shapes *= 1.0 / w;
+        dshapes *= 1.0 / w;
+        for (int i = 0; i < 10; i++)
+          for (int j = 0; j < 3; j++)
+            dshapes(i,j) -= shapes[i] * dw[j] / (w*w);
+        return;
+      }
+
+    switch (el.GetType())
+      {
+      case TET:
+	{
+	  dshapes(0,0) = 1;
+	  dshapes(1,1) = 1;
+	  dshapes(2,2) = 1;
+	  dshapes(3,0) = -1;
+	  dshapes(3,1) = -1;
+	  dshapes(3,2) = -1;
+
+	  if (info.order == 1) return;
+
+	  double lami[] = { xi(0), xi(1), xi(2), 1-xi(0)-xi(1)-xi(2) };
+	  int ii = 4;
+	  const ELEMENT_EDGE * edges = MeshTopology::GetEdges (TET);
+	  for (int i = 0; i < 6; i++)
+	    {
+	      int eorder = edgeorder[info.edgenrs[i]];
+	      if (eorder >= 2)
+		{
+		  int vi1 = edges[i][0]-1, vi2 = edges[i][1]-1;
+		  if (el[vi1] > el[vi2]) swap (vi1, vi2);
+
+		  CalcScaledEdgeShapeDxDt<3> (eorder, lami[vi1]-lami[vi2], lami[vi1]+lami[vi2], &dshapes(ii,0));
+
+		  Mat<2,3> trans;
+		  for (int j = 0; j < 3; j++)
+		    {
+		      trans(0,j) = dshapes(vi1,j)-dshapes(vi2,j);
+		      trans(1,j) = dshapes(vi1,j)+dshapes(vi2,j);
+		    }
+		  
+		  for (int j = 0; j < order-1; j++)
+		    {
+		      double ddx = dshapes(ii+j,0);
+		      double ddt = dshapes(ii+j,1);
+		      dshapes(ii+j,0) = ddx * trans(0,0) + ddt * trans(1,0);
+		      dshapes(ii+j,1) = ddx * trans(0,1) + ddt * trans(1,1);
+		      dshapes(ii+j,2) = ddx * trans(0,2) + ddt * trans(1,2);
+		    }
+
+		  ii += eorder-1;
+		}
+	    }
+
+	  const ELEMENT_FACE * faces = MeshTopology::GetFaces (TET);
+	  for (int i = 0; i < 4; i++)
+	    {
+	      int forder = faceorder[info.facenrs[i]];
+	      if (forder >= 3)
+		{
+		  int fnums[] = { faces[i][0]-1, faces[i][1]-1, faces[i][2]-1 }; 
+		  if (el[fnums[0]] > el[fnums[1]]) swap (fnums[0], fnums[1]);
+		  if (el[fnums[1]] > el[fnums[2]]) swap (fnums[1], fnums[2]);
+		  if (el[fnums[0]] > el[fnums[1]]) swap (fnums[0], fnums[1]);
+
+		  CalcScaledTrigShapeDxDyDt (forder, 
+					     lami[fnums[1]]-lami[fnums[0]], 
+					     lami[fnums[2]], lami[fnums[0]]+lami[fnums[1]]+lami[fnums[2]],
+					     &dshapes(ii,0));
+
+		  Mat<3,3> trans;
+		  for (int j = 0; j < 3; j++)
+		    {
+		      trans(0,j) = dshapes(fnums[1],j)-dshapes(fnums[0],j);
+		      trans(1,j) = dshapes(fnums[2],j);
+		      trans(2,j) = dshapes(fnums[0],j)+dshapes(fnums[1],j)+dshapes(fnums[2],j);
+		    }
+		  
+		  int nfd = (forder-1)*(forder-2)/2;
+		  for (int j = 0; j < nfd; j++)
+		    {
+		      double ddx = dshapes(ii+j,0);
+		      double ddy = dshapes(ii+j,1);
+		      double ddt = dshapes(ii+j,2);
+		      dshapes(ii+j,0) = ddx * trans(0,0) + ddy * trans(1,0) + ddt * trans(2,0);
+		      dshapes(ii+j,1) = ddx * trans(0,1) + ddy * trans(1,1) + ddt * trans(2,1);
+		      dshapes(ii+j,2) = ddx * trans(0,2) + ddy * trans(1,2) + ddt * trans(2,2);
+		    }
+
+		  ii += nfd;
+		}
+	    }
+
+	  break;
+	}
+      case PRISM:
+	{
+	  double lami[6] = { xi(0), xi(1), 1-xi(0)-xi(1), xi(0), xi(1), 1-xi(0)-xi(1)  };
+	  double lamiz[6] = { 1-xi(2), 1-xi(2), 1-xi(2), xi(2), xi(2), xi(2) };
+	  double dlamiz[6] = { -1, -1, -1, 1, 1, 1 };
+	  double dlami[6][2] = 
+	    { { 1, 0, },
+	      { 0, 1, },
+	      { -1, -1 },
+	      { 1, 0, },
+	      { 0, 1, },
+	      { -1, -1 } };
+	  for (int i = 0; i < 6; i++)
+	    {
+	      // shapes(i) = lami[i%3] * ( (i < 3) ? (1-xi(2)) : xi(2) );
+	      dshapes(i,0) = dlami[i%3][0] * ( (i < 3) ? (1-xi(2)) : xi(2) );
+	      dshapes(i,1) = dlami[i%3][1] * ( (i < 3) ? (1-xi(2)) : xi(2) );
+	      dshapes(i,2) = lami[i%3] * ( (i < 3) ? -1 : 1 );
+	    }
+
+	  int ii = 6;
+
+	  if (info.order == 1) return;
+
+
+	  const ELEMENT_EDGE * edges = MeshTopology::GetEdges (PRISM);
+	  for (int i = 0; i < 6; i++)    // horizontal edges
+	    {
+	      int order = edgeorder[info.edgenrs[i]];
+	      if (order >= 2)
+		{
+		  int vi1 = (edges[i][0]-1) % 3, vi2 = (edges[i][1]-1) % 3;
+		  if (el[vi1] > el[vi2]) swap (vi1, vi2);
+
+		  Vector shapei(order+1);
+		  CalcScaledEdgeShapeDxDt<3> (order, lami[vi1]-lami[vi2], lami[vi1]+lami[vi2], &dshapes(ii,0) );
+		  CalcScaledEdgeShape(order, lami[vi1]-lami[vi2], lami[vi1]+lami[vi2], &shapei(0) );
+
+		  Mat<2,2> trans;
+		  for (int j = 0; j < 2; j++)
+		    {
+		      trans(0,j) = dlami[vi1][j]-dlami[vi2][j];
+		      trans(1,j) = dlami[vi1][j]+dlami[vi2][j];
+		    }
+		  
+		  for (int j = 0; j < order-1; j++)
+		    {
+		      double ddx = dshapes(ii+j,0);
+		      double ddt = dshapes(ii+j,1);
+		      dshapes(ii+j,0) = ddx * trans(0,0) + ddt * trans(1,0);
+		      dshapes(ii+j,1) = ddx * trans(0,1) + ddt * trans(1,1);
+		    }
+
+
+
+		  double facz = (i < 3) ? (1-xi(2)) : xi(2);
+		  double dfacz = (i < 3) ? (-1) : 1;
+		  for (int j = 0; j < order-1; j++)
+		    {
+		      dshapes(ii+j,0) *= facz;
+		      dshapes(ii+j,1) *= facz;
+		      dshapes(ii+j,2) = shapei(j) * dfacz;
+		    }
+
+		  ii += order-1;
+		}
+	    }
+	  for (int i = 6; i < 9; i++)    // vertical edges
+	    {
+	      int eorder = edgeorder[info.edgenrs[i]];
+	      if (eorder >= 2)
+		{
+		  int vi1 = (edges[i][0]-1), vi2 = (edges[i][1]-1);
+		  if (el[vi1] > el[vi2]) swap (vi1, vi2);
+
+		  double bubz = lamiz[vi1] * lamiz[vi2];
+		  double dbubz = dlamiz[vi1]*lamiz[vi2] + lamiz[vi1]*dlamiz[vi2];
+		  double polyz = lamiz[vi1] - lamiz[vi2];
+		  double dpolyz = dlamiz[vi1] - dlamiz[vi2];
+		  double bubxy = lami[(vi1)%3];
+		  double dbubxydx = dlami[(vi1)%3][0];
+		  double dbubxydy = dlami[(vi1)%3][1];
+
+		  for (int j = 0; j < eorder-1; j++)
+		    {
+		      dshapes(ii+j,0) = dbubxydx * bubz;
+		      dshapes(ii+j,1) = dbubxydy * bubz;
+		      dshapes(ii+j,2) = bubxy * dbubz;
+
+		      dbubz = bubz * dpolyz + dbubz * polyz;
+		      bubz *= polyz;
+		    }
+		  ii += eorder-1;
+		}
+	    }
+
+
+	  if (info.order == 2) return;
+	  // FACE SHAPES
+	  const ELEMENT_FACE * faces = MeshTopology::GetFaces (PRISM);
+	  for (int i = 0; i < 2; i++)
+	    {
+	      int forder = faceorder[info.facenrs[i]];
+	      if ( forder < 3 ) continue;
+	      int ndf = (forder+1)*(forder+2)/2 - 3 - 3*(forder-1);
+
+	      int fav[3] = { faces[i][0]-1, faces[i][1]-1, faces[i][2]-1 };
+	      if(el[fav[0]] > el[fav[1]]) swap(fav[0],fav[1]); 
+	      if(el[fav[1]] > el[fav[2]]) swap(fav[1],fav[2]);
+	      if(el[fav[0]] > el[fav[1]]) swap(fav[0],fav[1]); 	
+
+	      MatrixFixWidth<2> dshapei(ndf);
+	      Vector shapei(ndf);
+
+	      CalcTrigShapeDxDy (forder, 
+				 lami[fav[2]]-lami[fav[1]], lami[fav[0]],
+				 &dshapei(0,0));
+	      CalcTrigShape (forder, lami[fav[2]]-lami[fav[1]], lami[fav[0]],
+				 &shapei(0));
+	      
+	      Mat<2,2> trans;
+	      for (int j = 0; j < 2; j++)
+		{
+		  trans(0,j) = dlami[fav[2]][j]-dlami[fav[1]][j];
+		  trans(1,j) = dlami[fav[0]][j];
+		}
+		  
+	      for (int j = 0; j < order-1; j++)
+		{
+		  double ddx = dshapes(ii+j,0);
+		  double ddt = dshapes(ii+j,1);
+		  dshapes(ii+j,0) = ddx * trans(0,0) + ddt * trans(1,0);
+		  dshapes(ii+j,1) = ddx * trans(0,1) + ddt * trans(1,1);
+		}
+
+	      for ( int j = 0; j < ndf; j++ )
+		{
+		  dshapes(ii+j,0) *= lamiz[fav[1]];
+		  dshapes(ii+j,1) *= lamiz[fav[1]];
+		  dshapes(ii+j,2) = shapei(j) * dlamiz[fav[1]];
+		}
+	      ii += ndf;
+	    }
+
+	  break;
+
+	}
+
+      case PYRAMID:
+	{
+	  dshapes = 0.0;
+	  double x = xi(0);
+	  double y = xi(1);
+	  double z = xi(2);
+	  
+	  if (z == 1.) z = 1-1e-10;
+	  double z1 = 1-z;
+	  double z2 = z1*z1;
+	  
+	  dshapes(0,0) = -(z1-y)/z1;
+	  dshapes(0,1) = -(z1-x)/z1;
+	  dshapes(0,2) = ((x+y+2*z-2)*z1+(z1-y)*(z1-x))/z2;
+
+	  dshapes(1,0) = (z1-y)/z1;
+	  dshapes(1,1) = -x/z1;
+	  dshapes(1,2) = (-x*z1+x*(z1-y))/z2;
+
+	  dshapes(2,0) = y/z1;
+	  dshapes(2,1) = x/z1;
+	  dshapes(2,2) = x*y/z2;
+
+	  dshapes(3,0) = -y/z1;
+	  dshapes(3,1) = (z1-x)/z1;
+	  dshapes(3,2) = (-y*z1+y*(z1-x))/z2;
+
+	  dshapes(4,0) = 0;
+	  dshapes(4,1) = 0;
+	  dshapes(4,2) = 1;
+		  /* old:
+	  vdshape[0] = Vec<3>( -(z1-y)/z1, -(z1-x)/z1, ((x+y+2*z-2)*z1+(z1-y)*(z1-x))/z2 );
+	  vdshape[1] = Vec<3>( (z1-y)/z1,  -x/z1,      (-x*z1+x*(z1-y))/z2 );
+	  vdshape[2] = Vec<3>( y/z1,       x/z1,       x*y/z2 );
+	  vdshape[3] = Vec<3>( -y/z1,      (z1-x)/z1,  (-y*z1+y*(z1-x))/z2 );
+	  vdshape[4] = Vec<3>( 0, 0, 1 );
+		  */
+	  break;
+	}
+
+      case HEX:
+        {
+          dshapes = 0.0;
+
+	  double x = xi(0);
+	  double y = xi(1);
+	  double z = xi(2);
+
+	  // shapes[0] = (1-x)*(1-y)*(1-z);
+          dshapes(0,0) = - (1-y)*(1-z);
+          dshapes(0,1) = (1-x) * (-1) * (1-z);
+          dshapes(0,2) = (1-x) * (1-y) * (-1);
+
+	  // shapes[1] =    x *(1-y)*(1-z);
+          dshapes(1,0) = (1-y)*(1-z);
+          dshapes(1,1) = -x * (1-z);
+          dshapes(1,2) = -x * (1-y);
+
+	  // shapes[2] =    x *   y *(1-z);
+          dshapes(2,0) = y * (1-z);
+          dshapes(2,1) = x * (1-z);
+          dshapes(2,2) = -x * y;
+
+	  // shapes[3] = (1-x)*   y *(1-z);
+          dshapes(3,0) = -y * (1-z);
+          dshapes(3,1) = (1-x) * (1-z);
+          dshapes(3,2) = -(1-x) * y;
+
+	  // shapes[4] = (1-x)*(1-y)*z;
+          dshapes(4,0) = - (1-y)*z;
+          dshapes(4,1) = (1-x) * (-1) * z;
+          dshapes(4,2) = (1-x) * (1-y) * 1;
+
+	  // shapes[5] =    x *(1-y)*z;
+          dshapes(5,0) = (1-y)*z;
+          dshapes(5,1) = -x * z;
+          dshapes(5,2) = x * (1-y);
+
+	  // shapes[6] =    x *   y *z;
+          dshapes(6,0) = y * z;
+          dshapes(6,1) = x * z;
+          dshapes(6,2) = x * y;
+
+	  // shapes[7] = (1-x)*   y *z;
+          dshapes(7,0) = -y * z;
+          dshapes(7,1) = (1-x) * z;
+          dshapes(7,2) = (1-x) * y;
+
+          break;
+        }
+      }
+    
+    /*
+    DenseMatrix dshapes2 (info.ndof, 3);
+    Vector shapesl(info.ndof); 
+    Vector shapesr(info.ndof); 
+    
+    double eps = 1e-6;
+    for (int i = 0; i < 3; i++)
+      {
+	Point<3> xl = xi;
+	Point<3> xr = xi;
+	
+	xl(i) -= eps;
+	xr(i) += eps;
+	CalcElementShapes (info, xl, shapesl);
+	CalcElementShapes (info, xr, shapesr);
+	
+	for (int j = 0; j < info.ndof; j++)
+	  dshapes2(j,i) = (shapesr(j)-shapesl(j)) / (2*eps);
+      }
+    (*testout) << "dshapes = " << endl << dshapes << endl;
+    (*testout) << "dshapes2 = " << endl << dshapes2 << endl;
+    dshapes2 -= dshapes;
+    (*testout) << "diff = " << endl << dshapes2 << endl;
+    */
+  }
+
+
+
+  void CurvedElements :: 
+  GetCoefficients (ElementInfo & info, Vec<3> * coefs) const
+  {
+    // cout << "getcoeffs, info.elnr = " << info.elnr << endl;
+    // cout << "getcoeffs, info.nv = " << info.nv << endl;
+
+    const Element & el = mesh[info.elnr];
+
+    /*
+    coefs.SetSize (info.ndof);
+    coefs = Vec<3> (0,0,0);
+    */
+    /*
+    for (int i = 0; i < info.ndof; i++)
+      coefs[i] = Vec<3> (0,0,0);
+    */
+    for (int i = 0; i < info.nv; i++)
+      coefs[i] = Vec<3> (mesh[el[i]]);
+
+    if (info.order == 1) return;
+
+    int ii = info.nv;
+	  
+    for (int i = 0; i < info.nedges; i++)
+      {
+	int first = edgecoeffsindex[info.edgenrs[i]];
+	int next = edgecoeffsindex[info.edgenrs[i]+1];
+	for (int j = first; j < next; j++, ii++)
+	  coefs[ii] = edgecoeffs[j];
+      }
+    for (int i = 0; i < info.nfaces; i++)
+      {
+	int first = facecoeffsindex[info.facenrs[i]];
+	int next = facecoeffsindex[info.facenrs[i]+1];
+	for (int j = first; j < next; j++, ii++)
+	  coefs[ii] = facecoeffs[j];
+      }
+  }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+  void CurvedElements :: 
+  CalcMultiPointSegmentTransformation (ARRAY<double> * xi, SegmentIndex segnr,
+				       ARRAY<Point<3> > * x,
+				       ARRAY<Vec<3> > * dxdxi)
+  {
+    ;
+  }
+
+  void CurvedElements :: 
+  CalcMultiPointSurfaceTransformation (ARRAY< Point<2> > * xi, SurfaceElementIndex elnr,
+				       ARRAY< Point<3> > * x,
+				       ARRAY< Mat<3,2> > * dxdxi)
+  {
+    if (mesh.coarsemesh)
+      {
+	const HPRefElement & hpref_el =
+	  (*mesh.hpelements) [mesh[elnr].hp_elnr];
+	
+	  // xi umrechnen
+	double lami[4];
+	FlatVector vlami(4, lami);
+
+	ArrayMem<Point<2>, 50> coarse_xi (xi->Size());
+	
+	for (int pi = 0; pi < xi->Size(); pi++)
+	  {
+	    vlami = 0;
+	    mesh[elnr].GetShapeNew ( (*xi)[pi], vlami);
+	    
+	    Point<2> cxi(0,0);
+	    for (int i = 0; i < hpref_el.np; i++)
+	      for (int j = 0; j < 2; j++)
+		cxi(j) += hpref_el.param[i][j] * lami[i];
+
+	    coarse_xi[pi] = cxi;
+	  }
+
+	mesh.coarsemesh->GetCurvedElements().
+	  CalcMultiPointSurfaceTransformation (&coarse_xi, hpref_el.coarse_elnr, x, dxdxi);
+
+
+	Mat<2,2> trans;
+        Mat<3,2> dxdxic;
+	if (dxdxi)
+	  {
+	    MatrixFixWidth<2> dlami(4);
+	    dlami = 0;
+
+	    for (int pi = 0; pi < xi->Size(); pi++)
+	      {
+		mesh[elnr].GetDShapeNew ( (*xi)[pi], dlami);	  
+		
+		trans = 0;
+		for (int k = 0; k < 2; k++)
+		  for (int l = 0; l < 2; l++)
+		    for (int i = 0; i < hpref_el.np; i++)
+		      trans(l,k) += hpref_el.param[i][l] * dlami(i, k);
+		
+		dxdxic = (*dxdxi)[pi];
+		(*dxdxi)[pi] = dxdxic * trans;
+	      }
+	  }	
+
+	return;
+      }
+
+
+
+
+
+    Vector shapes;
+    DenseMatrix dshapes;
+    ARRAY<Vec<3> > coefs;
+
+
+    const Element2d & el = mesh[elnr];
+    ELEMENT_TYPE type = el.GetType();
+
+    SurfaceElementInfo info;
+    info.elnr = elnr;
+    info.order = order;
+    info.ndof = info.nv = (type == TRIG) ? 3 : 4;
+    if (info.order > 1)
+      {
+	const MeshTopology & top = mesh.GetTopology();
+	
+	top.GetSurfaceElementEdges (elnr+1, info.edgenrs);
+	for (int i = 0; i < info.edgenrs.Size(); i++)
+	  info.edgenrs[i]--;
+	info.facenr = top.GetSurfaceElementFace (elnr+1)-1;
+
+	for (int i = 0; i < info.edgenrs.Size(); i++)
+	  info.ndof += edgecoeffsindex[info.edgenrs[i]+1] - edgecoeffsindex[info.edgenrs[i]];
+	info.ndof += facecoeffsindex[info.facenr+1] - facecoeffsindex[info.facenr];
+      }
+
+    GetCoefficients (info, coefs);
+
+    if (x)
+      {
+	for (int j = 0; j < xi->Size(); j++)
+	  {
+	    CalcElementShapes (info, (*xi)[j], shapes);
+	    (*x)[j] = 0;
+	    for (int i = 0; i < coefs.Size(); i++)
+	      (*x)[j] += shapes(i) * coefs[i];
+	  }
+      }
+
+    if (dxdxi)
+      {
+	for (int ip = 0; ip < xi->Size(); ip++)
+	  {
+	    CalcElementDShapes (info, (*xi)[ip], dshapes);
+	
+	    (*dxdxi)[ip] = 0;
+	    for (int i = 0; i < coefs.Size(); i++)
+	      for (int j = 0; j < 3; j++)
+		for (int k = 0; k < 2; k++)
+		  (*dxdxi)[ip](j,k) += dshapes(i,k) * coefs[i](j);
+	  }
+      }
+  }
+
+  void CurvedElements :: 
+  CalcMultiPointElementTransformation (ARRAY< Point<3> > * xi, ElementIndex elnr,
+				       ARRAY< Point<3> > * x,
+				       ARRAY< Mat<3,3> > * dxdxi)
+  {
+    if (mesh.coarsemesh)
+      {
+	const HPRefElement & hpref_el =
+	  (*mesh.hpelements) [mesh[elnr].hp_elnr];
+	
+	  // xi umrechnen
+	double lami[8];
+	FlatVector vlami(8, lami);
+
+
+	ArrayMem<Point<3>, 50> coarse_xi (xi->Size());
+	
+	for (int pi = 0; pi < xi->Size(); pi++)
+	  {
+	    vlami = 0;
+	    mesh[elnr].GetShapeNew ( (*xi)[pi], vlami);
+	    
+	    Point<3> cxi(0,0,0);
+	    for (int i = 0; i < hpref_el.np; i++)
+	      for (int j = 0; j < 3; j++)
+		cxi(j) += hpref_el.param[i][j] * lami[i];
+
+	    coarse_xi[pi] = cxi;
+	  }
+
+	mesh.coarsemesh->GetCurvedElements().
+	  CalcMultiPointElementTransformation (&coarse_xi, hpref_el.coarse_elnr, x, dxdxi);
+
+
+	Mat<3,3> trans, dxdxic;
+	if (dxdxi)
+	  {
+	    MatrixFixWidth<3> dlami(8);
+	    dlami = 0;
+
+	    for (int pi = 0; pi < xi->Size(); pi++)
+	      {
+		mesh[elnr].GetDShapeNew ( (*xi)[pi], dlami);	  
+		
+		trans = 0;
+		for (int k = 0; k < 3; k++)
+		  for (int l = 0; l < 3; l++)
+		    for (int i = 0; i < hpref_el.np; i++)
+		      trans(l,k) += hpref_el.param[i][l] * dlami(i, k);
+		
+		dxdxic = (*dxdxi)[pi];
+		(*dxdxi)[pi] = dxdxic * trans;
+	      }
+	  }	
+
+	return;
+      }
+
+
+
+
+
+
+
+
+    Vector shapes;
+    MatrixFixWidth<3> dshapes;
+
+
+    const Element & el = mesh[elnr];
+    ELEMENT_TYPE type = el.GetType();
+
+    ElementInfo info;
+    info.elnr = elnr;
+    info.order = order;
+    info.ndof = info.nv = MeshTopology::GetNVertices (type);
+    if (info.order > 1)
+      {
+	const MeshTopology & top = mesh.GetTopology();
+	
+	info.nedges = top.GetElementEdges (elnr+1, info.edgenrs, 0);
+	for (int i = 0; i < info.nedges; i++)
+	  info.edgenrs[i]--;
+
+	info.nfaces = top.GetElementFaces (elnr+1, info.facenrs, 0);
+	for (int i = 0; i < info.nfaces; i++)
+	  info.facenrs[i]--;
+
+	for (int i = 0; i < info.nedges; i++)
+	  info.ndof += edgecoeffsindex[info.edgenrs[i]+1] - edgecoeffsindex[info.edgenrs[i]];
+	for (int i = 0; i < info.nfaces; i++)
+	  info.ndof += facecoeffsindex[info.facenrs[i]+1] - facecoeffsindex[info.facenrs[i]];
+	// info.ndof += facecoeffsindex[info.facenr+1] - facecoeffsindex[info.facenr];
+      }
+
+    ARRAY<Vec<3> > coefs(info.ndof);
+    GetCoefficients (info, &coefs[0]);
+    if (x)
+      {
+	for (int j = 0; j < xi->Size(); j++)
+	  {
+	    CalcElementShapes (info, (*xi)[j], shapes);
+	    (*x)[j] = 0;
+	    for (int i = 0; i < coefs.Size(); i++)
+	      (*x)[j] += shapes(i) * coefs[i];
+	  }
+      }
+    if (dxdxi)
+      {
+	for (int ip = 0; ip < xi->Size(); ip++)
+	  {
+	    CalcElementDShapes (info, (*xi)[ip], dshapes);
+	
+	    (*dxdxi)[ip] = 0;
+	    for (int i = 0; i < coefs.Size(); i++)
+	      for (int j = 0; j < 3; j++)
+		for (int k = 0; k < 3; k++)
+		  (*dxdxi)[ip](j,k) += dshapes(i,k) * coefs[i](j);
+	  }
+      }
+  }
+
+
+
+
+  void  CurvedElements :: 
+  CalcMultiPointElementTransformation (ElementIndex elnr, int n,
+                                       const double * xi, int sxi,
+                                       double * x, int sx,
+                                       double * dxdxi, int sdxdxi)
+  {
+    if (mesh.coarsemesh)
+      {
+	const HPRefElement & hpref_el =
+	  (*mesh.hpelements) [mesh[elnr].hp_elnr];
+	
+	  // xi umrechnen
+	double lami[8];
+	FlatVector vlami(8, lami);
+
+
+	ArrayMem<double, 100> coarse_xi (3*n);
+	
+	for (int pi = 0; pi < n; pi++)
+	  {
+	    vlami = 0;
+            Point<3> pxi;
+            for (int j = 0; j < 3; j++)
+              pxi(j) = xi[pi*sxi+j];
+
+	    mesh[elnr].GetShapeNew ( pxi, vlami);
+	    
+	    Point<3> cxi(0,0,0);
+	    for (int i = 0; i < hpref_el.np; i++)
+	      for (int j = 0; j < 3; j++)
+		cxi(j) += hpref_el.param[i][j] * lami[i];
+
+            for (int j = 0; j < 3; j++)
+              coarse_xi[3*pi+j] = cxi(j);
+	  }
+
+	mesh.coarsemesh->GetCurvedElements().
+	  CalcMultiPointElementTransformation (hpref_el.coarse_elnr, n, 
+                                               &coarse_xi[0], 3, 
+                                               x, sx, 
+                                               dxdxi, sdxdxi);
+
+	Mat<3,3> trans, dxdxic;
+	if (dxdxi)
+	  {
+	    MatrixFixWidth<3> dlami(8);
+	    dlami = 0;
+
+	    for (int pi = 0; pi < n; pi++)
+	      {
+                Point<3> pxi;
+                for (int j = 0; j < 3; j++)
+                  pxi(j) = xi[pi*sxi+j];
+
+		mesh[elnr].GetDShapeNew (pxi, dlami);	  
+		
+		trans = 0;
+		for (int k = 0; k < 3; k++)
+		  for (int l = 0; l < 3; l++)
+		    for (int i = 0; i < hpref_el.np; i++)
+		      trans(l,k) += hpref_el.param[i][l] * dlami(i, k);
+
+                Mat<3> mat_dxdxic, mat_dxdxi;
+                for (int j = 0; j < 3; j++)
+                  for (int k = 0; k < 3; k++)
+                    mat_dxdxic(j,k) = dxdxi[pi*sdxdxi+3*j+k];
+		
+                mat_dxdxi = mat_dxdxic * trans;
+
+                for (int j = 0; j < 3; j++)
+                  for (int k = 0; k < 3; k++)
+                    dxdxi[pi*sdxdxi+3*j+k] = mat_dxdxi(j,k);
+
+		// dxdxic = (*dxdxi)[pi];
+		// (*dxdxi)[pi] = dxdxic * trans;
+	      }
+	  }	
+	return;
+      }
+
+
+
+
+
+
+
+
+    Vector shapes;
+    MatrixFixWidth<3> dshapes;
+
+
+    const Element & el = mesh[elnr];
+    ELEMENT_TYPE type = el.GetType();
+
+    ElementInfo info;
+    info.elnr = elnr;
+    info.order = order;
+    info.ndof = info.nv = MeshTopology::GetNVertices (type);
+    if (info.order > 1)
+      {
+	const MeshTopology & top = mesh.GetTopology();
+	
+	info.nedges = top.GetElementEdges (elnr+1, info.edgenrs, 0);
+	for (int i = 0; i < info.nedges; i++)
+	  info.edgenrs[i]--;
+
+	info.nfaces = top.GetElementFaces (elnr+1, info.facenrs, 0);
+	for (int i = 0; i < info.nfaces; i++)
+	  info.facenrs[i]--;
+
+	for (int i = 0; i < info.nedges; i++)
+	  info.ndof += edgecoeffsindex[info.edgenrs[i]+1] - edgecoeffsindex[info.edgenrs[i]];
+	for (int i = 0; i < info.nfaces; i++)
+	  info.ndof += facecoeffsindex[info.facenrs[i]+1] - facecoeffsindex[info.facenrs[i]];
+	// info.ndof += facecoeffsindex[info.facenr+1] - facecoeffsindex[info.facenr];
+      }
+
+    ARRAY<Vec<3> > coefs(info.ndof);
+    GetCoefficients (info, &coefs[0]);
+    if (x)
+      {
+	for (int j = 0; j < n; j++)
+	  {
+            Point<3> xij, xj;
+            for (int k = 0; k < 3; k++)
+              xij(k) = xi[j*sxi+k];
+
+	    CalcElementShapes (info, xij, shapes);
+	    xj = 0;
+	    for (int i = 0; i < coefs.Size(); i++)
+	      xj += shapes(i) * coefs[i];
+
+            for (int k = 0; k < 3; k++)
+              x[j*sx+k] = xj(k);
+	  }
+      }
+    if (dxdxi)
+      {
+	for (int ip = 0; ip < n; ip++)
+	  {
+            Point<3> xij;
+            for (int k = 0; k < 3; k++)
+              xij(k) = xi[ip*sxi+k];
+
+	    CalcElementDShapes (info, xij, dshapes);
+            
+            Mat<3> dxdxij;
+            dxdxij = 0.0;
+	    for (int i = 0; i < coefs.Size(); i++)
+	      for (int j = 0; j < 3; j++)
+		for (int k = 0; k < 3; k++)
+		  dxdxij(j,k) += dshapes(i,k) * coefs[i](j);
+
+
+	      for (int j = 0; j < 3; j++)
+		for (int k = 0; k < 3; k++)
+                  dxdxi[ip*sdxdxi+3*j+k] = dxdxij(j,k);
+	  }
+      }
+  }
+
+
+
+
+
+
+
+
+
+};
+
+
+#endif
diff --git a/contrib/Netgen/libsrc/meshing/curvedelems_new.hpp b/contrib/Netgen/libsrc/meshing/curvedelems_new.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..ff9cd88071d0f799d80ed31486313c23e3088d7b
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/curvedelems_new.hpp
@@ -0,0 +1,205 @@
+#ifndef CURVEDELEMS_NEWH
+#define CURVEDELEMS_NEWH
+
+/**************************************************************************/
+/* File:   curvedelems.hpp                                                */
+/* Author: Robert Gaisbauer (first version)                               */
+/*         redesign by Joachim Schoeberl                                  */
+/* Date:   27. Sep. 02, Feb 2006                                          */
+/**************************************************************************/
+
+
+
+
+class Refinement;
+
+
+class CurvedElements
+{
+  const Mesh & mesh;
+
+  ARRAY<int> edgeorder;
+  ARRAY<int> faceorder;
+
+  ARRAY<int> edgecoeffsindex;
+  ARRAY<int> facecoeffsindex;
+
+  ARRAY< Vec<3> > edgecoeffs;
+  ARRAY< Vec<3> > facecoeffs;
+
+  ARRAY< double > edgeweight;  // for rational 2nd order splines
+
+  int order;
+  bool rational;
+
+public:
+  CurvedElements (const Mesh & amesh);
+  ~CurvedElements();
+
+  bool IsHighOrder() const { return order > 1; }
+
+  void SetHighOrder (int aorder) { order=aorder; }
+  
+  void BuildCurvedElements(Refinement * ref, int aorder, bool arational = false);
+
+  int GetOrder () { return order; }
+
+
+  bool IsSegmentCurved (SegmentIndex segnr) const;
+  bool IsSurfaceElementCurved (SurfaceElementIndex sei) const;
+  bool IsElementCurved (ElementIndex ei) const;
+
+
+  void CalcSegmentTransformation (double xi, SegmentIndex segnr,
+				  Point<3> & x)
+  { CalcSegmentTransformation (xi, segnr, &x, NULL); };
+
+  void CalcSegmentTransformation (double xi, SegmentIndex segnr,
+				  Vec<3> & dxdxi)
+  { CalcSegmentTransformation (xi, segnr, NULL, &dxdxi); };
+
+  void CalcSegmentTransformation (double xi, SegmentIndex segnr,
+				  Point<3> & x, Vec<3> & dxdxi)
+  { CalcSegmentTransformation (xi, segnr, &x, &dxdxi, NULL); };
+
+  void CalcSegmentTransformation (double xi, SegmentIndex segnr,
+				  Point<3> & x, Vec<3> & dxdxi, bool & curved)
+  { CalcSegmentTransformation (xi, segnr, &x, &dxdxi, &curved); };
+
+
+
+  void CalcSurfaceTransformation (const Point<2> & xi, SurfaceElementIndex elnr,
+				  Point<3> & x)
+  { CalcSurfaceTransformation (xi, elnr, &x, NULL); };
+
+  void CalcSurfaceTransformation (const Point<2> & xi, SurfaceElementIndex elnr,
+				  Mat<3,2> & dxdxi)
+  { CalcSurfaceTransformation (xi, elnr, NULL, &dxdxi); };
+
+  void CalcSurfaceTransformation (const Point<2> & xi, SurfaceElementIndex elnr,
+				  Point<3> & x, Mat<3,2> & dxdxi)
+  { CalcSurfaceTransformation (xi, elnr, &x, &dxdxi, NULL); };
+
+  void CalcSurfaceTransformation (const Point<2> & xi, SurfaceElementIndex elnr,
+				  Point<3> & x, Mat<3,2> & dxdxi, bool & curved)
+  { CalcSurfaceTransformation (xi, elnr, &x, &dxdxi, &curved); };
+
+
+
+
+
+  void CalcElementTransformation (const Point<3> & xi, ElementIndex elnr,
+				  Point<3> & x)
+  { CalcElementTransformation (xi, elnr, &x, NULL); };
+
+  void CalcElementTransformation (const Point<3> & xi, ElementIndex elnr,
+				  Mat<3,3> & dxdxi)
+  { CalcElementTransformation (xi, elnr, NULL, &dxdxi); };
+
+  void CalcElementTransformation (const Point<3> & xi, ElementIndex elnr,
+				  Point<3> & x, Mat<3,3> & dxdxi)
+  { CalcElementTransformation (xi, elnr, &x, &dxdxi /* , NULL */ ); };
+
+  void CalcElementTransformation (const Point<3> & xi, ElementIndex elnr,
+				  Point<3> & x, Mat<3,3> & dxdxi,
+                                  void * buffer, bool valid)
+  { CalcElementTransformation (xi, elnr, &x, &dxdxi, /* NULL, */ buffer, valid ); };
+
+  // void CalcElementTransformation (const Point<3> & xi, ElementIndex elnr,
+  // 				  Point<3> & x, Mat<3,3> & dxdxi) // , bool & curved)
+  //   { CalcElementTransformation (xi, elnr, &x, &dxdxi /* , &curved * ); }
+
+
+
+  void CalcMultiPointSegmentTransformation (ARRAY<double> * xi, SegmentIndex segnr,
+					    ARRAY<Point<3> > * x,
+					    ARRAY<Vec<3> > * dxdxi);
+
+  void CalcMultiPointSurfaceTransformation (ARRAY< Point<2> > * xi, SurfaceElementIndex elnr,
+					    ARRAY< Point<3> > * x,
+					    ARRAY< Mat<3,2> > * dxdxi);
+
+  void CalcMultiPointElementTransformation (ARRAY< Point<3> > * xi, ElementIndex elnr,
+					    ARRAY< Point<3> > * x,
+					    ARRAY< Mat<3,3> > * dxdxi);
+
+  void CalcMultiPointElementTransformation (ElementIndex elnr, int n,
+                                            const double * xi, int sxi,
+                                            double * x, int sx,
+                                            double * dxdxi, int sdxdxi);
+
+
+
+
+private:
+  
+  void CalcSegmentTransformation (double xi, SegmentIndex segnr,
+				  Point<3> * x = NULL, Vec<3> * dxdxi = NULL, bool * curved = NULL);
+
+  void CalcSurfaceTransformation (Point<2> xi, SurfaceElementIndex elnr,
+				  Point<3> * x = NULL, Mat<3,2> * dxdxi = NULL, bool * curved = NULL);
+
+  void CalcElementTransformation (Point<3> xi, ElementIndex elnr,
+				  Point<3> * x = NULL, Mat<3,3> * dxdxi = NULL, // bool * curved = NULL,
+                                  void * buffer = NULL, bool valid = 0);
+
+
+
+
+
+
+  class SegmentInfo
+  {
+  public:
+    SegmentIndex elnr;
+    int order;
+    int nv;
+    int ndof;
+    int edgenr;
+  };
+
+  void CalcElementShapes (SegmentInfo &  elnr, double xi, Vector & shapes) const;
+  void GetCoefficients (SegmentInfo & elnr, ARRAY<Vec<3> > & coefs) const;
+  void CalcElementDShapes (SegmentInfo & elnr, double xi, Vector & dshapes) const;
+
+
+  class ElementInfo
+  {
+  public:
+    ElementIndex elnr;
+    int order;
+    int nv;
+    int ndof;
+    int nedges;
+    int nfaces;
+    int edgenrs[12];
+    int facenrs[6];
+    Mat<3> hdxdxi;
+    Vec<3> hcoefs[10]; // enough for second order tets
+  };
+
+
+  void CalcElementShapes (ElementInfo & info, const Point<3> & xi, Vector & shapes) const;
+  void GetCoefficients (ElementInfo & info, Vec<3> * coefs) const;
+  void CalcElementDShapes (ElementInfo & info, const Point<3> & xi, MatrixFixWidth<3> & dshapes) const;
+
+  
+  class SurfaceElementInfo
+  {
+  public:
+    SurfaceElementIndex elnr;
+    int order;
+    int nv;
+    int ndof;
+    ArrayMem<int,4> edgenrs;
+    int facenr;
+  };
+
+  void CalcElementShapes (SurfaceElementInfo & elinfo, const Point<2> & xi, Vector & shapes) const;
+  void GetCoefficients (SurfaceElementInfo & elinfo, ARRAY<Vec<3> > & coefs) const;
+  void CalcElementDShapes (SurfaceElementInfo & elinfo, const Point<2> & xi, DenseMatrix & dshapes) const;
+};
+
+
+
+#endif
diff --git a/contrib/Netgen/libsrc/meshing/delaunay.cpp b/contrib/Netgen/libsrc/meshing/delaunay.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..e74afec32b67c6a60115bfe470ee4a1e18556289
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/delaunay.cpp
@@ -0,0 +1,1676 @@
+#include <mystdlib.h>
+#include "meshing.hpp"
+
+
+
+namespace netgen
+{
+
+
+  static const int deltetfaces[][3] = 
+    { { 1, 2, 3 },
+      { 2, 0, 3 },
+      { 0, 1, 3 },
+      { 1, 0, 2 } };
+
+
+
+
+
+
+  class DelaunayTet
+  {
+    PointIndex pnums[4];
+    int nb[4];
+
+  public:
+    DelaunayTet () { ; }
+
+    DelaunayTet (const DelaunayTet & el)
+    {
+      for (int i = 0; i < 4; i++)
+	pnums[i] = el[i];
+    }
+
+    DelaunayTet (const Element & el)
+    {
+      for (int i = 0; i < 4; i++)
+	pnums[i] = el[i];
+    }
+    
+    PointIndex & operator[] (int i) { return pnums[i]; }
+    PointIndex operator[] (int i) const { return pnums[i]; }
+
+    int & NB1(int i) { return nb[i-1]; }
+    int NB1(int i) const { return nb[i-1]; }
+
+    int & NB(int i) { return nb[i]; }
+    int NB(int i) const { return nb[i]; }
+
+
+    int FaceNr (INDEX_3 & face) const  // which face nr is it ?
+    {
+      for (int i = 0; i < 3; i++)
+	if (pnums[i] != face.I1() && 
+	    pnums[i] != face.I2() && 
+	    pnums[i] != face.I3())
+	  return i;
+      return 3;
+    }
+    
+    void GetFace1 (int i, INDEX_3 & face) const
+    {
+      face.I(1) = pnums[deltetfaces[i-1][0]];
+      face.I(2) = pnums[deltetfaces[i-1][1]];
+      face.I(3) = pnums[deltetfaces[i-1][2]];
+    }
+
+    void GetFace (int i, INDEX_3 & face) const
+    {
+      face.I(1) = pnums[deltetfaces[i][0]];
+      face.I(2) = pnums[deltetfaces[i][1]];
+      face.I(3) = pnums[deltetfaces[i][2]];
+    }
+      
+    INDEX_3 GetFace1 (int i) const
+    {
+      return INDEX_3 (pnums[deltetfaces[i-1][0]],
+		      pnums[deltetfaces[i-1][1]],
+		      pnums[deltetfaces[i-1][2]]);
+    }
+
+    INDEX_3 GetFace (int i) const
+    {
+      return INDEX_3 (pnums[deltetfaces[i][0]],
+		      pnums[deltetfaces[i][1]],
+		      pnums[deltetfaces[i][2]]);
+    }
+     
+    void GetFace1 (int i, Element2d & face) const
+    {
+      // face.SetType(TRIG);
+      face[0] = pnums[deltetfaces[i-1][0]];
+      face[1] = pnums[deltetfaces[i-1][1]];
+      face[2] = pnums[deltetfaces[i-1][2]];
+    }
+  };
+
+
+
+
+
+
+
+
+
+  /*
+    Table to maintain neighbour elements
+  */
+  class MeshNB
+  {
+    // face nodes -> one element
+    INDEX_3_CLOSED_HASHTABLE<int> faces;
+
+    // 
+    ARRAY<DelaunayTet> & tets;
+
+  public:
+
+    // estimated number of points
+    MeshNB (ARRAY<DelaunayTet> & atets, int np)
+      : faces(200), tets(atets)
+    { ; }
+
+    // add element with 4 nodes
+    void Add (int elnr);
+
+    // delete element with 4 nodes
+    void Delete (int elnr)
+    {
+      DelaunayTet & el = tets.Elem(elnr);
+      for (int i = 0; i < 4; i++)
+	faces.Set (el.GetFace(i).Sort(), el.NB(i));
+    }
+
+    // get neighbour of element elnr in direction fnr 
+    int GetNB (int elnr, int fnr)
+    { 
+      return tets.Get(elnr).NB1(fnr); 
+    }
+
+    //
+    void ResetFaceHT (int size)
+    {
+      faces.SetSize (size);
+    }
+  };
+
+
+
+  void MeshNB :: Add (int elnr)
+  {
+    DelaunayTet & el = tets.Elem(elnr);
+
+    for (int i = 0; i < 4; i++)
+      {
+	INDEX_3 i3 = INDEX_3::Sort (el.GetFace(i));
+
+	int posnr;
+	
+	if (!faces.PositionCreate (i3, posnr))
+	  {
+	    // face already in use
+	    int othertet = faces.GetData (posnr);
+
+	    el.NB(i) = othertet;
+	    if (othertet)
+	      {
+		int fnr = tets.Get(othertet).FaceNr (i3);
+		tets.Elem(othertet).NB(fnr) = elnr;
+	      }
+	  }
+	else
+	  {
+	    faces.SetData (posnr, elnr);	
+	    el.NB(i) = 0;
+	  }
+      }
+  }
+
+
+
+
+
+
+  /*
+    connected lists of cosphereical elements
+  */
+  class SphereList 
+  {
+    ARRAY<int> links;
+  public:
+    SphereList () 
+    { ; }
+
+    void AddElement (int elnr)
+    {
+      if (elnr > links.Size())
+	links.Append (1);
+      links.Elem(elnr) = elnr;
+    }
+
+    void DeleteElement (int elnr)
+    {
+      links.Elem(elnr) = 0;
+    }    
+  
+    void ConnectElement (int eli, int toi)
+    {
+      links.Elem (eli) = links.Get (toi);
+      links.Elem (toi) = eli;
+    }
+      
+    void GetList (int eli, ARRAY<int> & linked) const;
+  };
+
+
+  void SphereList :: GetList (int eli, ARRAY<int> & linked) const
+  {
+    linked.SetSize (0);
+    int pi = eli;
+
+    do
+      {
+	if (pi <= 0 || pi > links.Size())
+	  {
+	    cerr << "link, error " << endl;
+	    cerr << "pi = " << pi << " linked.s = " << linked.Size() << endl;
+	    exit(1);
+	  }
+	if (linked.Size() > links.Size())
+	  {
+	    cerr << "links have loop" << endl;
+	    exit(1);
+	  }
+
+	linked.Append (pi);
+	pi = links.Get(pi);
+      }
+    while (pi != eli);
+  }
+
+
+
+
+
+  void AddDelaunayPoint (PointIndex newpi, const Point3d & newp, 
+			 ARRAY<DelaunayTet> & tempels, 
+			 Mesh & mesh,
+			 Box3dTree & tettree, 
+			 MeshNB & meshnb,
+			 ARRAY<Point<3> > & centers, ARRAY<double> & radi2,
+			 ARRAY<int> & connected, ARRAY<int> & treesearch, 
+			 ARRAY<int> & freelist, SphereList & list,
+			 IndexSet & insphere, IndexSet & closesphere)
+  {
+    /*
+      find any sphere, such that newp is contained in
+    */
+  
+    DelaunayTet el;
+    int cfelind = -1;
+
+    const Point<3> * pp[4];
+    Point<3> pc;
+    double r2;
+    Point3d tpmin, tpmax;
+
+    tettree.GetIntersecting (newp, newp, treesearch);
+    
+    double quot,minquot(1e20);
+
+    for (int j = 0; j < treesearch.Size(); j++)
+      {
+	int jjj = treesearch[j];
+	quot = Dist2 (centers.Get(jjj), newp) / radi2.Get(jjj);
+	
+	if((cfelind == -1 || quot < 0.99*minquot) && quot < 1)
+	  {
+	    minquot = quot;
+	    el = tempels.Get(jjj);
+	    cfelind = jjj;
+	    if(minquot < 0.917632)
+	      break;
+	  }
+      }
+
+
+    /*
+      int i, j, k, l;
+      if (!felind)
+      {
+      cerr << "not in any sphere, 1" << endl;
+      // old, non tree search
+
+      double mindist = 1e10;
+      for (j = 1; j <= tempels.Size(); j++)
+      {
+      if (tempels.Get(j).PNum(1))
+      {
+      double toofar = 
+      Dist2 (centers.Get(j), newp) - radi2.Get(j);
+      if (toofar < mindist || toofar < 1e-7) 
+      {
+      mindist = toofar;
+      cout << " dist2 = " << Dist2 (centers.Get(j), newp)
+      << " radi2 = " << radi2.Get(j) << endl;
+      }
+      if (toofar < 0)
+      {
+      el = tempels.Get(j);
+      felind = j;
+      cout << "sphere found !" << endl;
+      break; 
+      }
+      }
+      }
+      cout << "point is too far from sheres: " << mindist << endl;
+      }
+    */      
+
+    if (cfelind == -1)
+      {
+	PrintWarning ("Delaunay, point not in any sphere");
+	return;
+      }
+	
+
+    /*
+      insphere:     point is in sphere -> delete element
+      closesphere:  point is close to sphere -> considered for same center
+    */
+
+    // save overestimate
+    insphere.SetMaxIndex (2 * tempels.Size() + 5 * mesh.GetNP());
+    closesphere.SetMaxIndex (2 * tempels.Size() + 5 * mesh.GetNP());
+
+    insphere.Clear();
+    closesphere.Clear();
+
+
+    insphere.Add (cfelind);
+      
+    int changed = 1;
+    int nstarti = 1, starti;
+
+
+    while (changed)
+      {
+	changed = 0;
+	starti = nstarti;
+	nstarti = insphere.Array().Size()+1;
+
+
+	// if point in sphere, then it is also closesphere
+	for (int j = starti; j < nstarti; j++)
+	  {
+	    int helind = insphere.Array().Get(j);
+	    if (!closesphere.IsIn (helind))
+	      closesphere.Add (helind);
+	  }
+
+	// add connected spheres to insphere - list
+	for (int j = starti; j < nstarti; j++)
+	  {
+	    list.GetList (insphere.Array().Get(j), connected);
+	    for (int k = 0; k < connected.Size(); k++)
+	      {
+		int celind = connected[k];
+
+		if (tempels.Get(celind)[0] != -1 && 
+		    !insphere.IsIn (celind))
+		  {
+		    changed = 1;
+		    insphere.Add (celind);
+		  }
+	      }
+	  }
+	
+	// check neighbour-tets
+	for (int j = starti; j < nstarti; j++)
+	  for (int k = 1; k <= 4; k++)
+	    {
+	      int helind = insphere.Array().Get(j);
+	      int nbind = meshnb.GetNB (helind, k);
+
+	      if (nbind && !insphere.IsIn (nbind) )
+		{
+		  //changed
+		  //int prec = testout->precision();
+		  //testout->precision(12);
+		  //(*testout) << "val1 " << Dist2 (centers.Get(nbind), newp)
+		  //	     << " val2 " << radi2.Get(nbind) * (1+1e-8)
+		  //	     << " val3 " << radi2.Get(nbind)
+		  //	     << " val1 / val3 " << Dist2 (centers.Get(nbind), newp)/radi2.Get(nbind) << endl;
+		  //testout->precision(prec);
+		  if (Dist2 (centers.Get(nbind), newp) 
+		      < radi2.Get(nbind) * (1+1e-8) )
+		    closesphere.Add (nbind);
+		    
+		  if (Dist2 (centers.Get(nbind), newp) 
+		      < radi2.Get(nbind) * (1 + 1e-12))
+		    {
+		      // point is in sphere -> remove tet
+		      insphere.Add (nbind);
+		      changed = 1;
+		    }
+		  else
+		    {
+		      /*
+		      Element2d face;
+		      tempels.Get(helind).GetFace (k, face);
+
+		      const Point3d & p1 = mesh.Point (face.PNum(1));
+		      const Point3d & p2 = mesh.Point (face[1]);
+		      const Point3d & p3 = mesh.Point (face[2]);
+		      */
+
+		      INDEX_3 i3 = tempels.Get(helind).GetFace (k-1);
+
+		      const Point3d & p1 = mesh.Point ( PointIndex (i3.I1()));
+		      const Point3d & p2 = mesh.Point ( PointIndex (i3.I2()));
+		      const Point3d & p3 = mesh.Point ( PointIndex (i3.I3()));
+
+
+		      Vec3d v1(p1, p2);
+		      Vec3d v2(p1, p3);
+		      Vec3d n = Cross (v1, v2);
+		      n /= n.Length();
+
+		      if (n * Vec3d (p1, mesh.Point (tempels.Get(helind)[k-1])) > 0)
+			n *= -1;
+			
+		      double dist = n * Vec3d (p1, newp);
+
+
+		      if (dist > -1e-10)  // 1e-10
+			{
+			  insphere.Add (nbind);
+			  changed = 1;
+			}
+
+
+		    }
+		}
+	    }
+      } // while (changed)
+
+    //      (*testout) << "newels: " << endl;
+    ARRAY<Element> newels;
+
+    Element2d face(TRIG);
+
+    for (int j = 1; j <= insphere.Array().Size(); j++)
+      for (int k = 1; k <= 4; k++)
+	{
+	  //	    int elind = insphere.Array().Get(j);
+	  int celind = insphere.Array().Get(j);
+	  int nbind = meshnb.GetNB (celind, k);
+
+	  if (!nbind || !insphere.IsIn (nbind))
+	    {
+	      tempels.Get (celind).GetFace1 (k, face);
+		
+	      Element newel(TET);
+	      for (int l = 0; l < 3; l++)
+                newel[l] = face[l];
+              newel[3] = newpi;
+
+	      newels.Append (newel);
+
+              Vec<3> v1 = mesh[face[1]] - mesh[face[0]];
+              Vec<3> v2 = mesh[face[2]] - mesh[face[0]];
+	      Vec<3> n = Cross (v1, v2);
+
+	      n.Normalize();
+	      if (n * Vec3d(mesh.Point (face[0]), 
+			    mesh.Point (tempels.Get(insphere.Array().Get(j))[k-1]))
+		  > 0)
+		n *= -1;
+
+              double hval = n *  ( newp - mesh[face[0]]);
+		
+	      if (hval > -1e-12)
+		{
+		  cerr << "vec to outer" << endl;
+		  (*testout) << "vec to outer, hval = " << hval << endl;
+		  (*testout) << "v1 x v2 = " << Cross (v1, v2) << endl;
+		  (*testout) << "facep: "
+			     << mesh.Point (face[0]) << " "
+			     << mesh.Point (face[1]) << " "
+			     << mesh.Point (face[2]) << endl;
+		}
+	    }
+	}
+
+    meshnb.ResetFaceHT (10*insphere.Array().Size()+1);
+
+    for (int j = 1; j <= insphere.Array().Size(); j++)
+      {
+	//	  int elind = 
+	int celind = insphere.Array().Get(j);
+
+	meshnb.Delete (celind); 
+	list.DeleteElement (celind);
+	  
+	for (int k = 0; k < 4; k++)
+	  tempels.Elem(celind)[k] = -1;
+
+	((ADTree6&)tettree.Tree()).DeleteElement (celind);
+	freelist.Append (celind);
+      }
+
+
+    int hasclose = 0;
+    for (int j = 1; j <= closesphere.Array().Size(); j++)
+      {
+	int ind = closesphere.Array().Get(j);
+	if (!insphere.IsIn(ind) &&
+	    fabs (Dist2 (centers.Get (ind), newp) - radi2.Get(ind)) < 1e-8 )
+	  hasclose = 1;
+      }
+
+    for (int j = 1; j <= newels.Size(); j++)
+      {
+	int nelind;
+
+	if (!freelist.Size())
+	  {
+	    tempels.Append (newels.Get(j));
+	    nelind = tempels.Size();
+	  }
+	else
+	  {
+	    nelind = freelist.Last();
+	    freelist.DeleteLast();
+
+	    tempels.Elem(nelind) = newels.Get(j);
+	  }
+
+	meshnb.Add (nelind);
+	list.AddElement (nelind);
+
+	for (int k = 0; k < 4; k++)
+	  pp[k] = &mesh.Point (newels.Get(j)[k]);
+
+	if (CalcSphereCenter (&pp[0], pc) )
+	  {
+	    PrintSysError ("Delaunay: New tet is flat");
+
+	    (*testout) << "new tet is flat" << endl;
+	    for (int k = 1; k <= 4; k++)
+	      (*testout) << newels.Get(j).PNum(k) << " ";
+	    (*testout) << endl;
+	    for (int k = 1; k <= 4; k++)
+	      (*testout) << *pp[k-1] << " ";
+	    (*testout) << endl;
+	  }
+
+	r2 = Dist2 (*pp[0], pc);
+	if (hasclose)
+	  for (int k = 1; k <= closesphere.Array().Size(); k++)
+	    {
+	      int csameind = closesphere.Array().Get(k); 
+	      if (!insphere.IsIn(csameind) &&
+		  fabs (r2 - radi2.Get(csameind)) < 1e-10 && 
+		  Dist (pc, centers.Get(csameind)) < 1e-10)
+		{
+		  pc = centers.Get(csameind);
+		  r2 = radi2.Get(csameind);
+		  list.ConnectElement (nelind, csameind);
+		  break;
+		}
+	    }
+      
+	if (centers.Size() < nelind)
+	  {
+	    centers.Append (pc);
+	    radi2.Append (r2);
+	  }
+	else
+	  {
+	    centers.Elem(nelind) = pc;
+	    radi2.Elem(nelind) = r2;
+	  }
+
+	closesphere.Add (nelind);
+	  
+	tpmax = tpmin = *pp[0];
+	for (int k = 1; k <= 3; k++)
+	  {
+	    tpmin.SetToMin (*pp[k]);
+	    tpmax.SetToMax (*pp[k]);
+	  }
+	tpmax = tpmax + 0.01 * (tpmax - tpmin);
+	tettree.Insert (tpmin, tpmax, nelind);
+      }
+  }
+
+
+
+
+
+
+  void Delaunay1 (Mesh & mesh, const MeshingParameters & mp, AdFront3 * adfront,
+		  ARRAY<DelaunayTet> & tempels,
+		  int oldnp, DelaunayTet & startel, Point3d & pmin, Point3d & pmax)
+  {
+    int i, j, k;
+    const Point<3> * pp[4];
+
+    ARRAY<Point<3> > centers;
+    ARRAY<double> radi2;
+  
+    Point3d tpmin, tpmax;
+
+
+    // new: local box
+    mesh.GetBox (pmax, pmin);   // lower bound for pmax, upper for pmin
+    for (i = 1; i <= adfront->GetNF(); i++)
+      {
+	const MiniElement2d & face = adfront->GetFace(i);
+	for (j = 0; j < face.GetNP(); j++)
+	  {
+	    pmin.SetToMin  (mesh.Point (face[j]));
+	    pmax.SetToMax  (mesh.Point (face[j]));
+	  }
+      }
+  
+    for (i = 0; i < mesh.LockedPoints().Size(); i++)
+      {
+	pmin.SetToMin (mesh.Point (mesh.LockedPoints()[i]));
+	pmax.SetToMax (mesh.Point (mesh.LockedPoints()[i]));
+      }
+  
+
+
+    Vec3d vdiag(pmin, pmax);
+    // double r1 = vdiag.Length();
+    double r1 = sqrt (3.0) * max3(vdiag.X(), vdiag.Y(), vdiag.Z());
+    vdiag = Vec3d (r1, r1, r1);
+    //double r2;
+
+    Point3d pmin2 = pmin - 8 * vdiag;
+    Point3d pmax2 = pmax + 8 * vdiag;
+
+    Point3d cp1(pmin2), cp2(pmax2), cp3(pmax2), cp4(pmax2);
+    cp2.X() = pmin2.X();
+    cp3.Y() = pmin2.Y();
+    cp4.Z() = pmin2.Z();
+
+
+
+
+    int np = mesh.GetNP();
+
+    startel[0] = mesh.AddPoint (cp1);
+    startel[1] = mesh.AddPoint (cp2);
+    startel[2] = mesh.AddPoint (cp3);
+    startel[3] = mesh.AddPoint (cp4);
+
+    // flag points to use for Delaunay:
+    BitArrayChar<PointIndex::BASE> usep(np);
+    usep.Clear();
+    for (i = 1; i <= adfront->GetNF(); i++)
+      {
+	const MiniElement2d & face = adfront->GetFace(i);
+	for (j = 0; j < face.GetNP(); j++)
+	  usep.Set (face[j]);
+      }
+
+    for (i = oldnp + PointIndex::BASE; 
+	 i < np + PointIndex::BASE; i++)
+      usep.Set (i);
+
+    for (i = 0; i < mesh.LockedPoints().Size(); i++)
+      usep.Set (mesh.LockedPoints()[i]);
+  
+
+    ARRAY<int> freelist;
+
+
+    int cntp = 0;
+
+    MeshNB meshnb (tempels, mesh.GetNP() + 5);
+    SphereList list;
+
+    pmin2 = pmin2 + 0.1 * (pmin2 - pmax2);
+    pmax2 = pmax2 + 0.1 * (pmax2 - pmin2);
+
+    Box3dTree tettree(pmin2, pmax2);
+
+
+    tempels.Append (startel);
+    meshnb.Add (1);
+    list.AddElement (1);
+    ARRAY<int> connected, treesearch;
+
+
+    tpmin = tpmax = mesh.Point(startel[0]);
+    for (k = 1; k < 4; k++)
+      {
+	tpmin.SetToMin (mesh.Point (startel[k]));
+	tpmax.SetToMax (mesh.Point (startel[k]));
+      }
+    tpmax = tpmax + 0.01 * (tpmax - tpmin);
+    tettree.Insert (tpmin, tpmax, 1);
+
+
+    Point<3> pc;
+	  
+    for (k = 0; k < 4; k++)
+      {
+	pp[k] = &mesh.Point (startel[k]);
+      }
+  
+    CalcSphereCenter (&pp[0], pc);
+    
+    centers.Append (pc);
+    radi2.Append (Dist2 (*pp[0], pc));
+
+
+    IndexSet insphere(mesh.GetNP());
+    IndexSet closesphere(mesh.GetNP());
+
+
+
+    // "random" reordering of points  (speeds a factor 3 - 5 !!!)
+
+    ARRAY<int> mixed(np);
+    int prims[] = { 11, 13, 17, 19, 23, 29, 31, 37 };
+    int prim;
+  
+    i = 0;
+    while (np % prims[i] == 0) i++;
+    prim = prims[i];
+
+    for (i = 1; i <= np; i++)
+      mixed.Elem(i) = (prim * i) % np + PointIndex::BASE;
+
+    for (i = 1; i <= np; i++)
+      {
+	if (i % 1000 == 0)
+	  {
+	    if (i % 10000 == 0)
+	      PrintDot ('+');
+	    else
+	      PrintDot ('.');
+	  }
+
+	multithread.percent = 100.0 * i / np;
+	if (multithread.terminate)
+	  break;
+
+	PointIndex newpi = mixed.Get(i);
+
+	if (!usep.Test(newpi)) 
+	  continue;
+
+	cntp++;
+
+	const Point3d & newp = mesh.Point(newpi);
+      
+	AddDelaunayPoint (newpi, newp, tempels, mesh,
+			  tettree, meshnb, centers, radi2, 
+			  connected, treesearch, freelist, list, insphere, closesphere);
+      }
+
+    for (i = tempels.Size(); i >= 1; i--)
+      if (tempels.Get(i)[0] <= 0)
+	tempels.DeleteElement (i);
+
+    PrintDot ('\n');
+
+    PrintMessage (3, "Points: ", cntp);
+    PrintMessage (3, "Elements: ", tempels.Size());
+    //   (*mycout) << cntp << " / " << tempels.Size() << " points/elements" << endl;
+
+    /*
+      cout << "tempels: ";
+      tempels.PrintMemInfo(cout);
+      cout << "Searchtree: ";
+      tettree.Tree().PrintMemInfo(cout);
+      cout << "MeshNB: ";
+      meshnb.PrintMemInfo(cout);
+    */
+  }
+
+
+
+
+
+
+  void Meshing3 :: Delaunay (Mesh & mesh, int domainnr, const MeshingParameters & mp)
+  {
+    int np, ne;
+
+    PrintMessage (1, "Delaunay meshing");
+    PrintMessage (3, "number of points: ", mesh.GetNP());
+    PushStatus ("Delaunay meshing");
+
+
+    ARRAY<DelaunayTet> tempels;
+    Point3d pmin, pmax;
+
+    DelaunayTet startel;
+
+    int oldnp = mesh.GetNP();
+    if (mp.blockfill)
+      {
+	BlockFillLocalH (mesh, mp);
+	PrintMessage (3, "number of points: ", mesh.GetNP());
+      }
+
+    np = mesh.GetNP();
+
+    Delaunay1 (mesh, mp, adfront, tempels, oldnp, startel, pmin, pmax);
+
+    {
+      // improve delaunay - mesh by swapping !!!!
+
+      Mesh tempmesh;
+      for (PointIndex pi = PointIndex::BASE; pi < mesh.GetNP()+PointIndex::BASE; pi++)
+	tempmesh.AddPoint (mesh[pi]);
+      
+      for (int i = 1; i <= tempels.Size(); i++)
+	{   
+	  Element el(4);
+	  for (int j = 0; j < 4; j++)
+	    el[j] = tempels.Elem(i)[j];
+
+	  el.SetIndex (1);
+
+	  const Point3d & lp1 = mesh.Point (el[0]);
+	  const Point3d & lp2 = mesh.Point (el[1]);
+	  const Point3d & lp3 = mesh.Point (el[2]);
+	  const Point3d & lp4 = mesh.Point (el[3]);
+	  Vec3d v1(lp1, lp2);
+	  Vec3d v2(lp1, lp3);
+	  Vec3d v3(lp1, lp4);
+
+	  Vec3d n = Cross (v1, v2);
+	  double vol = n * v3;
+	  if (vol > 0) swap (el[2], el[3]);
+
+	  tempmesh.AddVolumeElement (el);
+	}
+
+
+      MeshQuality3d (tempmesh);
+
+      tempmesh.AddFaceDescriptor (FaceDescriptor (1, 1, 0, 0));
+      tempmesh.AddFaceDescriptor (FaceDescriptor (2, 1, 0, 0));
+
+
+    
+      for (int i = 1; i <= mesh.GetNOpenElements(); i++)
+	{
+	  Element2d sel = mesh.OpenElement(i);
+	  sel.SetIndex(1);
+	  tempmesh.AddSurfaceElement (sel);
+	  swap (sel[1], sel[2]);
+	  tempmesh.AddSurfaceElement (sel);
+	}
+
+
+      for (int i = 1; i <= 4; i++)
+	{
+	  Element2d self(TRIG);
+	  self.SetIndex (1);
+	  startel.GetFace1 (i, self);
+	  tempmesh.AddSurfaceElement (self);
+	}
+
+      
+      //  for (i = mesh.GetNP() - 3; i <= mesh.GetNP(); i++)
+      //    tempmesh.AddLockedPoint (i);
+      for (PointIndex pi = PointIndex::BASE; 
+	   pi < tempmesh.GetNP() + PointIndex::BASE; pi++)
+	tempmesh.AddLockedPoint (pi);
+      
+      //    tempmesh.PrintMemInfo(cout);
+      // tempmesh.Save ("tempmesh.vol");
+
+      for (int i = 1; i <= 2; i++)
+	{ 
+	  tempmesh.FindOpenElements ();
+
+	  PrintMessage (5, "Num open: ", tempmesh.GetNOpenElements());
+	  tempmesh.CalcSurfacesOfNode ();
+
+	  tempmesh.FreeOpenElementsEnvironment (1);
+
+	  MeshOptimize3d meshopt;
+	  // tempmesh.CalcSurfacesOfNode();
+	  meshopt.SwapImprove(tempmesh, OPT_CONFORM);
+	}
+    
+      MeshQuality3d (tempmesh);
+    
+      tempels.SetSize(0);
+      for (int i = 1; i <= tempmesh.GetNE(); i++)
+	tempels.Append (tempmesh.VolumeElement(i));
+    }
+
+
+
+    // remove degenerated
+
+    BitArray badnode(mesh.GetNP());
+    badnode.Clear();
+    int ndeg = 0;
+    for (int i = 1; i <= tempels.Size(); i++)
+      {
+	Element el(4);
+	for (int j = 0; j < 4; j++)
+	  el[j] = tempels.Elem(i)[j];
+	//      Element & el = tempels.Elem(i);
+	const Point3d & lp1 = mesh.Point (el[0]);
+	const Point3d & lp2 = mesh.Point (el[1]);
+	const Point3d & lp3 = mesh.Point (el[2]);
+	const Point3d & lp4 = mesh.Point (el[3]);
+	Vec3d v1(lp1, lp2);
+	Vec3d v2(lp1, lp3);
+	Vec3d v3(lp1, lp4);
+	Vec3d n = Cross (v1, v2);
+	double vol = n * v3;
+
+	double h = v1.Length() + v2.Length() + v3.Length();
+	if (fabs (vol) < 1e-8 * (h * h * h) &&
+	    (el[0] <= np && el[1] <= np &&
+	     el[2] <= np && el[3] <= np) )   // old: 1e-12
+	  {
+	    badnode.Set(el[0]);
+	    badnode.Set(el[1]);
+	    badnode.Set(el[2]);
+	    badnode.Set(el[3]);
+	    ndeg++;
+	    (*testout) << "vol = " << vol << " h = " << h << endl;
+	  }
+
+	if (vol > 0)
+	  Swap (el[2], el[3]);
+      }
+
+    ne = tempels.Size();
+    for (int i = ne; i >= 1; i--)
+      {
+	const DelaunayTet & el = tempels.Get(i);
+	if (badnode.Test(el[0]) ||
+	    badnode.Test(el[1]) ||
+	    badnode.Test(el[2]) ||
+	    badnode.Test(el[3]) )
+	  tempels.DeleteElement(i);
+      }
+
+  
+    PrintMessage (3, ndeg, " degenerated elements removed");
+
+    // find surface triangles which are no face of any tet
+
+    INDEX_3_HASHTABLE<int> openeltab(mesh.GetNOpenElements()+3);
+    ARRAY<int> openels;
+    for (int i = 1; i <= mesh.GetNOpenElements(); i++)
+      {
+	const Element2d & tri = mesh.OpenElement(i);
+	INDEX_3 i3(tri[0], tri[1], tri[2]);
+	i3.Sort();
+	openeltab.Set (i3, i);
+      }
+
+    for (int i = 1; i <= tempels.Size(); i++)
+      {
+	for (int j = 0; j < 4; j++)
+	  {
+	    INDEX_3 i3 = tempels.Get(i).GetFace (j);
+	    i3.Sort();
+	    if (openeltab.Used(i3))
+	      openeltab.Set (i3, 0);
+	  }
+      }
+  
+    // and store them in openels
+    for (int i = 1; i <= openeltab.GetNBags(); i++)
+      for (int j = 1; j <= openeltab.GetBagSize(i); j++)
+	{
+	  INDEX_3 i3;
+	  int fnr;
+	  openeltab.GetData (i, j, i3, fnr);
+	  if (fnr)
+	    openels.Append (fnr);
+	}
+
+
+
+
+
+    // find open triangle with close edge (from halfening of surface squares)
+  
+    INDEX_2_HASHTABLE<INDEX_2> twotrias(mesh.GetNOpenElements()+5); 
+    //  for (i = 1; i <= mesh.GetNOpenElements(); i++)
+    for (int ii = 1; ii <= openels.Size(); ii++)
+      {
+	int i = openels.Get(ii);
+	const Element2d & el = mesh.OpenElement(i);
+	for (int j = 1; j <= 3; j++)
+	  {
+	    INDEX_2 hi2 (el.PNumMod (j), el.PNumMod(j+1));
+	    hi2.Sort();
+	    if (twotrias.Used(hi2))
+	      {
+		INDEX_2 hi3;
+		hi3 = twotrias.Get (hi2);
+		hi3.I2() = el.PNumMod (j+2);
+		twotrias.Set (hi2, hi3);
+	      }
+	    else
+	      {
+		INDEX_2 hi3(el.PNumMod (j+2), 0);
+		twotrias.Set (hi2, hi3);
+	      }
+	  }
+      }
+
+    INDEX_2_HASHTABLE<int> tetedges(tempels.Size() + 5);
+    for (int i = 1; i <= tempels.Size(); i++)
+      {
+	const DelaunayTet & el = tempels.Get(i);
+	INDEX_2 i2;
+	for (int j = 1; j <= 6; j++)
+	  {
+	    switch (j)
+	      {
+	      case 1: i2.I1()=el[0]; i2.I2()=el[1]; break;
+	      case 2: i2.I1()=el[0]; i2.I2()=el[2]; break;
+	      case 3: i2.I1()=el[0]; i2.I2()=el[3]; break;
+	      case 4: i2.I1()=el[1]; i2.I2()=el[2]; break;
+	      case 5: i2.I1()=el[1]; i2.I2()=el[3]; break;
+	      case 6: i2.I1()=el[2]; i2.I2()=el[3]; break;
+		  default: i2.I1()=i2.I2()=0; break;
+	      }
+	    i2.Sort();
+	    tetedges.Set (i2, 1);
+	  }
+      }
+    //  cout << "tetedges:";
+    //  tetedges.PrintMemInfo (cout);
+
+
+    for (INDEX_2_HASHTABLE<INDEX_2>::Iterator it = twotrias.Begin();
+	 it != twotrias.End(); it++)
+      {
+	INDEX_2 hi2, hi3;
+	twotrias.GetData (it, hi2, hi3);
+	hi3.Sort();
+	if (tetedges.Used (hi3))
+	  {
+	    const Point3d & p1 = mesh.Point ( PointIndex (hi2.I1()));
+	    const Point3d & p2 = mesh.Point ( PointIndex (hi2.I2()));
+	    const Point3d & p3 = mesh.Point ( PointIndex (hi3.I1()));
+	    const Point3d & p4 = mesh.Point ( PointIndex (hi3.I2()));
+	    Vec3d v1(p1, p2);
+	    Vec3d v2(p1, p3);
+	    Vec3d v3(p1, p4);
+	    Vec3d n = Cross (v1, v2);
+	    double vol = n * v3;
+	    
+	    double h = v1.Length() + v2.Length() + v3.Length();
+	    if (fabs (vol) < 1e-4 * (h * h * h))   // old: 1e-12
+	      {
+		badnode.Set(hi3.I1());	
+		badnode.Set(hi3.I2());	
+	      }
+	  }
+      }
+
+    /*
+    for (i = 1; i <= twotrias.GetNBags(); i++)
+      for (j = 1; j <= twotrias.GetBagSize (i); j++)
+	{
+	  INDEX_2 hi2, hi3;
+	  twotrias.GetData (i, j, hi2, hi3);
+	  hi3.Sort();
+	  if (tetedges.Used (hi3))
+	    {
+	      const Point3d & p1 = mesh.Point (hi2.I1());
+	      const Point3d & p2 = mesh.Point (hi2.I2());
+	      const Point3d & p3 = mesh.Point (hi3.I1());
+	      const Point3d & p4 = mesh.Point (hi3.I2());
+	      Vec3d v1(p1, p2);
+	      Vec3d v2(p1, p3);
+	      Vec3d v3(p1, p4);
+	      Vec3d n = Cross (v1, v2);
+	      double vol = n * v3;
+	    
+	      double h = v1.Length() + v2.Length() + v3.Length();
+	      if (fabs (vol) < 1e-4 * (h * h * h))   // old: 1e-12
+		{
+		  badnode.Set(hi3.I1());	
+		  badnode.Set(hi3.I2());	
+		}
+	    }
+	}
+    */
+
+    ne = tempels.Size();
+    for (int i = ne; i >= 1; i--)
+      {
+	const DelaunayTet & el = tempels.Get(i);
+	if (badnode.Test(el[0]) ||
+	    badnode.Test(el[1]) ||
+	    badnode.Test(el[2]) ||
+	    badnode.Test(el[3]) )
+	  tempels.DeleteElement(i);
+      }
+
+
+
+
+    // find intersecting:
+    PrintMessage (3, "Remove intersecting");
+    if (openels.Size())
+      {
+	Box3dTree setree(pmin, pmax);
+
+	/*      
+		cout << "open elements in search tree: " << openels.Size() << endl;
+		cout << "pmin, pmax = " << pmin << " - " << pmax << endl;
+	*/
+
+	for (int i = 1; i <= openels.Size(); i++)
+	  {
+	    int fnr;
+	    fnr = openels.Get(i);
+	    if (fnr)
+	      {
+		const Element2d & tri = mesh.OpenElement(fnr);
+	      
+		Point3d ltpmin (mesh.Point(tri[0]));
+		Point3d ltpmax (ltpmin);
+	      
+		for (int k = 2; k <= 3; k++)
+		  {
+		    ltpmin.SetToMin (mesh.Point (tri.PNum(k)));
+		    ltpmax.SetToMax (mesh.Point (tri.PNum(k)));
+		  }
+		setree.Insert (ltpmin, ltpmax, fnr);
+	      }
+	  }
+      
+	ARRAY<int> neartrias;
+	for (int i = 1; i <= tempels.Size(); i++)
+	  {
+	    const Point<3> *pp[4];
+	    int tetpi[4];
+	    DelaunayTet & el = tempels.Elem(i);
+	  
+	    int intersect = 0;
+	  
+	    for (int j = 0; j < 4; j++)
+	      {
+		pp[j] = &mesh.Point(el[j]);
+		tetpi[j] = el[j];
+	      }
+	  
+	    Point3d tetpmin(*pp[0]);
+	    Point3d tetpmax(tetpmin);
+	    for (int j = 1; j < 4; j++)
+	      {
+		tetpmin.SetToMin (*pp[j]);
+		tetpmax.SetToMax (*pp[j]);
+	      }
+	    tetpmin = tetpmin + 0.01 * (tetpmin - tetpmax);
+	    tetpmax = tetpmax + 0.01 * (tetpmax - tetpmin);
+	  
+	    setree.GetIntersecting (tetpmin, tetpmax, neartrias);
+	  
+	  
+	    //      for (j = 1; j <= mesh.GetNSE(); j++)
+	    //	{
+	    for (int jj = 1; jj <= neartrias.Size(); jj++)
+	      {
+		int j = neartrias.Get(jj);
+	      
+		const Element2d & tri = mesh.OpenElement(j);
+		const Point<3> *tripp[3];
+		int tripi[3];
+	      
+		for (int k = 1; k <= 3; k++)
+		  {
+		    tripp[k-1] = &mesh.Point (tri.PNum(k));
+		    tripi[k-1] = tri.PNum(k);
+		  }
+	      
+		if (IntersectTetTriangle (&pp[0], &tripp[0], tetpi, tripi))
+		  {
+		    /*
+		    int il1, il2;
+		    (*testout) << "intersect !" << endl;
+		    (*testout) << "triind: ";
+		    for (il1 = 0; il1 < 3; il1++)
+		      (*testout) << " " << tripi[il1];
+		    (*testout) << endl;
+		    (*testout) << "tetind: ";
+		    for (il2 = 0; il2 < 4; il2++)
+		      (*testout) << " " << tetpi[il2];
+		    (*testout) << endl;
+		  
+		    (*testout) << "trip: ";
+		    for (il1 = 0; il1 < 3; il1++)
+		      (*testout) << " " << *tripp[il1];
+		    (*testout) << endl;
+		    (*testout) << "tetp: ";
+		    for (il2 = 0; il2 < 4; il2++)
+		      (*testout) << " " << *pp[il2];
+		    (*testout) << endl;
+		    */
+		  
+		  
+		    intersect = 1;
+		    break;
+		  }
+	      }
+	  
+	  
+	    if (intersect)
+	      {
+		tempels.DeleteElement(i);
+		i--;
+	      }
+	  }
+      }
+  
+
+
+
+    PrintMessage (3, "Remove outer");
+
+    // find connected tets (with no face between, and no hole due
+    // to removed intersecting tets.
+    //  INDEX_3_HASHTABLE<INDEX_2> innerfaces(np);
+
+  
+    INDEX_3_HASHTABLE<int> boundaryfaces(mesh.GetNOpenElements()/3+1);
+    for (int i = 1; i <= mesh.GetNOpenElements(); i++)
+      {
+	const Element2d & tri = mesh.OpenElement(i);
+	INDEX_3 i3 (tri[0], tri[1], tri[2]);
+	i3.Sort();
+	boundaryfaces.PrepareSet (i3);
+      }
+    boundaryfaces.AllocateElements();
+    for (int i = 1; i <= mesh.GetNOpenElements(); i++)
+      {
+	const Element2d & tri = mesh.OpenElement(i);
+	INDEX_3 i3 (tri[0], tri[1], tri[2]);
+	i3.Sort();
+	boundaryfaces.Set (i3, 1);
+      }
+
+    for (int i = 0; i < tempels.Size(); i++)
+      for (int j = 0; j < 4; j++)
+	tempels[i].NB(j) = 0;
+  
+    TABLE<int,PointIndex::BASE> elsonpoint(mesh.GetNP());
+    for (int i = 0; i < tempels.Size(); i++)
+      {
+	const DelaunayTet & el = tempels[i];
+	INDEX_4 i4(el[0], el[1], el[2], el[3]);
+	i4.Sort();
+	elsonpoint.IncSizePrepare (i4.I1());
+	elsonpoint.IncSizePrepare (i4.I2());
+      }
+
+    elsonpoint.AllocateElementsOneBlock();
+
+    for (int i = 0; i < tempels.Size(); i++)
+      {
+	const DelaunayTet & el = tempels[i];
+	INDEX_4 i4(el[0], el[1], el[2], el[3]);
+	i4.Sort();
+	elsonpoint.Add (i4.I1(), i+1);
+	elsonpoint.Add (i4.I2(), i+1);
+      }
+
+    //  cout << "elsonpoint mem: ";
+    //  elsonpoint.PrintMemInfo(cout);
+
+    INDEX_3_CLOSED_HASHTABLE<INDEX_2> faceht(100);   
+  
+    Element2d hel(TRIG);
+    for (PointIndex pi = PointIndex::BASE; 
+	 pi < mesh.GetNP()+PointIndex::BASE; pi++)
+      {
+	faceht.SetSize (4 * elsonpoint[pi].Size());
+	for (int ii = 0; ii < elsonpoint[pi].Size(); ii++)
+	  {
+	    int i = elsonpoint[pi][ii];
+	    const DelaunayTet & el = tempels.Get(i);
+
+	    for (int j = 1; j <= 4; j++)
+	      {
+		el.GetFace1 (j, hel);
+		hel.Invert();
+		hel.NormalizeNumbering();
+	      
+		if (hel[0] == pi)
+		  {
+		    INDEX_3 i3(hel[0], hel[1], hel[2]);
+		  
+		    if (!boundaryfaces.Used (i3))
+		      {
+			if (faceht.Used (i3))
+			  {
+			    INDEX_2 i2 = faceht.Get(i3);
+			  
+			    tempels.Elem(i).NB1(j) = i2.I1();
+			    tempels.Elem(i2.I1()).NB1(i2.I2()) = i;
+			  }
+			else
+			  {
+			    hel.Invert();
+			    hel.NormalizeNumbering();
+			    INDEX_3 i3i(hel[0], hel[1], hel[2]);
+			    INDEX_2 i2(i, j);
+			    faceht.Set (i3i, i2);
+			  }
+		      }
+		  }
+	      }
+	  }
+      }
+  
+    /*
+      for (i = 1; i <= tempels.Size(); i++)
+      {
+      const DelaunayTet & el = tempels.Get(i);
+      for (j = 1; j <= 4; j++)
+      {
+      INDEX_3 i3;
+      Element2d face;
+      el.GetFace1 (j, face);
+      for (int kk = 1; kk <= 3; kk++)
+      i3.I(kk) = face.PNum(kk);
+
+      i3.Sort();
+      if (!boundaryfaces.Used (i3))
+      {
+      if (innerfaces.Used(i3))
+      {
+      INDEX_2 i2;
+      i2 = innerfaces.Get(i3);
+      i2.I2() = i;
+      innerfaces.Set (i3, i2);
+      }
+      else
+      {
+      INDEX_2 i2;
+      i2.I1() = i;
+      i2.I2() = 0;
+      innerfaces.Set (i3, i2);
+      }
+      }
+      }
+      }
+    */
+
+    /*
+      (*testout) << "nb elements:" << endl;
+      for (i = 1; i <= tempels.Size(); i++)
+      {
+      (*testout) << i << " ";
+      for (j = 1; j <= 4; j++)
+      (*testout) << tempels.Get(i).NB1(j) << " ";
+      (*testout) << endl;
+      }
+  
+      (*testout) << "pairs:" << endl;
+      for (i = 1; i <= innerfaces.GetNBags(); i++)
+      for (j = 1; j <= innerfaces.GetBagSize(i); j++)
+      {
+      INDEX_3 i3;
+      INDEX_2 i2;
+      innerfaces.GetData (i, j, i3, i2);
+      (*testout) << i2 << endl;
+      }
+    */
+
+
+
+
+
+
+
+    /*
+      cout << "innerfaces: ";
+      innerfaces.PrintMemInfo (cout);
+    */
+
+    //  cout << "boundaryfaces: ";
+    //  boundaryfaces.PrintMemInfo (cout);
+
+
+    PrintMessage (5, "tables filled");
+ 
+
+    ne = tempels.Size();
+    BitArray inner(ne), outer(ne);
+    inner.Clear();
+    outer.Clear();
+    ARRAY<int> elstack;
+
+    /*
+      int starti = 0;
+      for (i = 1; i <= ne; i++)
+      {
+      const Element & el = tempels.Get(i);
+      for (j = 1; j <= 4; j++)
+      for (k = 1; k <= 4; k++)
+      if (el.PNum(j) == startel.PNum(k))
+      {
+      outer.Set(i);
+      starti = i;
+      }
+      }
+    */
+
+    while (1)
+      {
+	int inside;
+	bool done = 1;
+
+	int i;
+	for (i = 1; i <= ne; i++)
+	  if (!inner.Test(i) && !outer.Test(i))
+	    {
+	      done = 0;
+	      break;
+	    }
+
+	if (done) break;
+      
+	const DelaunayTet & el = tempels.Get(i);
+	const Point3d & p1 = mesh.Point (el[0]);
+	const Point3d & p2 = mesh.Point (el[1]);
+	const Point3d & p3 = mesh.Point (el[2]);
+	const Point3d & p4 = mesh.Point (el[3]);
+      
+	Point3d ci = Center (p1, p2, p3, p4);
+
+	inside = adfront->Inside (ci);
+
+	/*
+	  cout << "startel: " << i << endl;
+	  cout << "inside = " << inside << endl;
+	  cout << "ins2 = " << adfront->Inside (Center (ci, p1)) << endl;
+	  cout << "ins3 = " << adfront->Inside (Center (ci, p2)) << endl;
+	*/
+      
+	elstack.SetSize(0);
+	elstack.Append (i);
+  
+	while (elstack.Size())
+	  {
+	    int ei = elstack.Last();
+	    elstack.DeleteLast();
+	  
+	    if (!inner.Test(ei) && !outer.Test(ei))
+	      {
+		if (inside)
+		  inner.Set(ei);
+		else
+		  outer.Set(ei);
+
+
+		for (int j = 1; j <= 4; j++)
+		  {
+		    INDEX_3 i3 = tempels.Get(ei).GetFace1(j);
+		    /*
+		    Element2d face;
+		    tempels.Get(ei).GetFace(j, face);
+		    for (int kk = 1; kk <= 3; kk++)
+		      i3.I(kk) = face.PNum(kk);
+		    */
+		    i3.Sort();
+		  
+
+		    if (tempels.Get(ei).NB1(j))
+		      elstack.Append (tempels.Get(ei).NB1(j));
+
+		    /*
+		      if (innerfaces.Used(i3))
+		      {
+		      INDEX_2 i2 = innerfaces.Get(i3);
+		      int other = i2.I1() + i2.I2() - ei;
+
+		      if (other != tempels.Get(ei).NB1(j))
+		      cerr << "different1 !!" << endl;
+
+		      if (other)
+		      {
+		      elstack.Append (other);
+		      }
+		      }
+		      else
+		      if (tempels.Get(ei).NB1(j))
+		      cerr << "different2 !!" << endl;
+		    */
+
+		  }
+	      }
+	  }
+      }
+
+
+
+    // check outer elements
+    if (debugparam.slowchecks)
+      {
+	for (int i = 1; i <= ne; i++)
+	  {
+	    const DelaunayTet & el = tempels.Get(i);
+	    const Point3d & p1 = mesh.Point (el[0]);
+	    const Point3d & p2 = mesh.Point (el[1]);
+	    const Point3d & p3 = mesh.Point (el[2]);
+	    const Point3d & p4 = mesh.Point (el[3]);
+	  
+	    Point3d ci = Center (p1, p2, p3, p4);
+	  
+	    //       if (adfront->Inside (ci) != adfront->Inside (Center (ci, p1)))
+	    // 	cout << "ERROR: outer test unclear !!!" << endl;	
+	  
+	    if (inner.Test(i) != adfront->Inside (ci))
+	      {
+		/*
+		  cout << "ERROR: outer test wrong !!!" 
+		  << "inner = " << int(inner.Test(i))
+		  << "outer = " << int(outer.Test(i))
+		  << endl;
+	      
+		  cout << "Vol = " << Determinant(Vec3d(p1, p2),
+		  Vec3d(p1, p3),
+		  Vec3d(p1, p4)) << endl;
+	      
+		*/	      
+		for (int j = 1; j <= 4; j++)
+		  {
+		    Point3d hp;
+		    switch (j)
+		      {
+		      case 1: hp = Center (ci, p1); break;
+		      case 2: hp = Center (ci, p2); break;
+		      case 3: hp = Center (ci, p3); break;
+		      case 4: hp = Center (ci, p4); break;
+		      }
+		    //		  cout << "inside(" << hp << ") = " << adfront->Inside(hp) << endl;
+		  }
+	      
+	      }
+	  
+	    if (adfront->Inside(ci))
+	      outer.Clear(i);
+	    else
+	      outer.Set(i);
+	  }
+      }
+
+
+    /*
+
+    // find bug in innerfaces
+
+    tempmesh.DeleteVolumeElements();
+
+    for (i = 1; i <= innerfaces.GetNBags(); i++)
+    for (j = 1; j <= innerfaces.GetBagSize(i); j++)
+    {
+    INDEX_3 i3;
+    INDEX_2 i2;
+    innerfaces.GetData (i, j, i3, i2);
+    if (i2.I2())
+    {
+    if (outer.Test(i2.I1()) != outer.Test(i2.I2()))
+    {
+    tempmesh.AddVolumeElement (tempels.Get(i2.I1()));
+    tempmesh.AddVolumeElement (tempels.Get(i2.I2()));
+    cerr << "outer flag different for connected els" << endl;
+    }
+    }
+    }
+
+
+    cout << "Check intersectiong once more" << endl;
+
+    for (i = 1; i <= openels.Size(); i++)
+    {
+    tempmesh.SurfaceElement(2*openels.Get(i)).SetIndex(2);
+    tempmesh.SurfaceElement(2*openels.Get(i)-1).SetIndex(2);
+    }
+
+    //  for (i = 1; i <= tempmesh.GetNE(); i++)
+    //    for (j = 1; j <= tempmesh.GetNSE(); j++)
+    i = 6; j = 403;
+    if (i <= tempmesh.GetNE() && j <= tempmesh.GetNSE())
+    if (tempmesh.SurfaceElement(j).GetIndex()==2)
+    {
+    const Element & el = tempmesh.VolumeElement(i);
+    const Element2d & sel = tempmesh.SurfaceElement(j);
+
+    const Point3d *tripp[3];
+    const Point3d *pp[4];
+    int tetpi[4], tripi[3];
+
+    for (k = 1; k <= 4; k++)
+    {
+    pp[k-1] = &tempmesh.Point(el.PNum(k));
+    tetpi[k-1] = el.PNum(k);
+    }
+
+    for (k = 1; k <= 3; k++)
+    {
+    tripp[k-1] = &tempmesh.Point (sel.PNum(k));
+    tripi[k-1] = sel.PNum(k);
+    }
+
+    (*testout) << "Check Triangle " << j << ":";
+    for (k = 1; k <= 3; k++)
+    (*testout) << " " << sel.PNum(k);
+    for (k = 1; k <= 3; k++)
+    (*testout) << " " << tempmesh.Point(sel.PNum(k));
+    (*testout) << endl;
+
+    (*testout) << "Check Tet " << i << ":";
+    for (k = 1; k <= 4; k++)
+    (*testout) << " " << el.PNum(k);
+    for (k = 1; k <= 4; k++)
+    (*testout) << " " << tempmesh.Point(el.PNum(k));
+    (*testout) << endl;
+
+    if (IntersectTetTriangle (&pp[0], &tripp[0], tetpi, tripi))
+    {
+    cout << "Intesection detected !!" << endl;
+    }
+    }
+
+    tempmesh.Save ("temp.vol");
+
+    // end bug search
+    */
+
+
+    for (int i = ne; i >= 1; i--)
+      {
+	if (outer.Test(i))
+	  tempels.DeleteElement(i);
+      }
+
+
+    // mesh.points.SetSize(mesh.points.Size()-4);
+
+    for (int i = 0; i < tempels.Size(); i++)
+      {
+	Element el(4);
+	for (int j = 0; j < 4; j++)
+	  el[j] = tempels[i][j];
+	mesh.AddVolumeElement (el);
+      }
+
+    PrintMessage (5, "outer removed");
+
+    mesh.FindOpenElements(domainnr);
+
+    mesh.Compress();
+
+    PopStatus ();
+  }
+}
diff --git a/contrib/Netgen/libsrc/meshing/findip.cpp b/contrib/Netgen/libsrc/meshing/findip.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..7be0ee913d1b295fa5fda890a675a689543504d7
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/findip.cpp
@@ -0,0 +1,115 @@
+// find inner point
+
+#include <mystdlib.h>
+#include "meshing.hpp"
+
+namespace netgen
+{
+
+
+template <typename POINTARRAY, typename FACEARRAY>
+int FindInnerPoint (POINTARRAY & points,
+		    FACEARRAY & faces,
+		    Point3d & p)
+{
+  int i, j;
+  ARRAY<Vec3d> a;
+  ARRAY<double> c;
+  Point3d p1, pmin;
+  int i1, i2, i3, i4;
+  int nf;
+  DenseMatrix m(3), inv(3);
+  Vector rs(3), x(3);
+  double f, fmin, hd, hmax;
+
+  nf = faces.Size();
+
+  //  testout << "#faces  = " << faces.Size() << endl;
+  //  testout << "#points = " << points.Size() << endl;
+
+  a.SetSize (nf);
+  c.SetSize (nf);
+
+  for (i = 1; i <= nf; i++)
+    {
+      p1 = points.Get(faces.Get(i).PNum(1));
+      a.Elem(i) = Cross (points.Get(faces.Get(i).PNum(2)) - points.Get(faces.Get(i).PNum(1)),
+		    points.Get(faces.Get(i).PNum(3)) - points.Get(faces.Get(i).PNum(1)));
+      a.Elem(i) /= a.Get(i).Length();
+      c.Elem(i) = - (a.Get(i).X() * p1.X() + a.Get(i).Y() * p1.Y() + a.Get(i).Z() * p1.Z());
+    }
+
+
+  hmax = 0;
+  for (i = 1; i <= nf; i++)
+    {
+      const Element2d & el = faces.Get(i);
+      for (j = 1; j <= 3; j++)
+	{
+	  double hi = Dist (points.Get(el.PNumMod(j)),
+			    points.Get(el.PNumMod(j+1)));
+	  if (hi > hmax) hmax = hi;
+	}
+    }
+
+
+  fmin = 100;
+  pmin = Point3d (0, 0, 0);
+
+  for (i1 = 1; i1 <= nf; i1++)
+    for (i2 = i1+1; i2 <= nf; i2++)
+      for (i3 = i2+1; i3 <= nf; i3++)
+        for (i4 = i3+1; i4 <= nf; i4++)
+          {
+	    m.Elem(1, 1) = a.Get(i1).X() - a.Get(i2).X();
+	    m.Elem(1, 2) = a.Get(i1).Y() - a.Get(i2).Y();
+	    m.Elem(1, 3) = a.Get(i1).Z() - a.Get(i2).Z();
+	    rs.Elem(1) = c.Get(i2) - c.Get(i1);
+
+	    m.Elem(2, 1) = a.Get(i1).X() - a.Get(i3).X();
+	    m.Elem(2, 2) = a.Get(i1).Y() - a.Get(i3).Y();
+	    m.Elem(2, 3) = a.Get(i1).Z() - a.Get(i3).Z();
+	    rs.Elem(2) = c.Get(i3) - c.Get(i1);
+
+	    m.Elem(3, 1) = a.Get(i1).X() - a.Get(i4).X();
+	    m.Elem(3, 2) = a.Get(i1).Y() - a.Get(i4).Y();
+	    m.Elem(3, 3) = a.Get(i1).Z() - a.Get(i4).Z();
+	    rs.Elem(3) = c.Get(i4) - c.Get(i1);
+
+
+	    if (fabs (m.Det()) > 1e-10)
+	      {
+		CalcInverse (m, inv);
+		inv.Mult (rs, x);
+
+		//            testout << "x = " << x << endl;
+
+
+		f = -1e10;
+		for (i = 1; i <= nf; i++)
+		  {
+		    hd = x.Elem(1) * a.Get(i).X()
+		      + x.Elem(2) * a.Get(i).Y()
+		      + x.Elem(3) * a.Get(i).Z()
+		      + c.Get(i);
+		    if (hd > f) f = hd;
+		  }
+
+		if (f < fmin)
+		  {
+		    fmin = f;
+		    pmin.X() = x.Elem(1);
+		    pmin.Y() = x.Elem(2);
+		    pmin.Z() = x.Elem(3);
+		  }
+	      }
+          }
+
+  //  testout << "fmin = " << fmin << endl;
+  //  testout << "pmin = " << pmin << endl;
+
+  p = pmin;
+  return (fmin < -1e-3 * hmax) ? 1 : 0;
+  //  return (fmin < 0) ? 1 : 0;
+}
+}
diff --git a/contrib/Netgen/libsrc/meshing/findip.hpp b/contrib/Netgen/libsrc/meshing/findip.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..2d9058fc5c8c65f7b962533142ad79a4dc254224
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/findip.hpp
@@ -0,0 +1,192 @@
+// find inner point
+
+
+
+inline void Minimize (const ARRAY<Vec3d> & a,
+		      const ARRAY<double> & c,
+		      int * act, 
+		      Vec<3> & x, double & f,
+		      int * sol)
+{
+  int act1[4];
+  Mat<3> m, inv;
+  Vec<3> rs, xmax, center;
+
+  f = 1e99;
+
+  for (int j = 0; j < 5; j++)
+    {
+      for (int hk = 0, k = 0; hk < 4; hk++)
+	{
+	  if (hk == j) k++;
+	  act1[hk] = act[k];
+	  k++;
+	}
+
+      for (int k = 0; k < 3; k++)
+	{
+	  m(k, 0) = a[act1[0]].X() - a[act1[k+1]].X();
+	  m(k, 1) = a[act1[0]].Y() - a[act1[k+1]].Y();
+	  m(k, 2) = a[act1[0]].Z() - a[act1[k+1]].Z();
+	  rs(k) = c[act1[k+1]] - c[act1[0]];
+	}
+
+      /*
+      (*testout) << "act1 = "
+		 << act1[0] << " "
+		 << act1[1] << " "
+		 << act1[2] << " "
+		 << act1[3] << endl;
+      (*testout) << "Det = " << Det(m) << endl;
+      */
+
+      if (fabs (Det (m)) > 1e-10)
+	{
+	  CalcInverse (m, inv);
+	  xmax = inv * rs;
+	  
+	  double fmax = -1e10;
+	  for (int k = 0; k < 5; k++)
+	    {
+	      double hd = 
+		xmax(0) * a[act[k]].X() + xmax(1) * a[act[k]].Y() + xmax(2) * a[act[k]].Z() + c[act[k]];
+	      if (hd > fmax) fmax = hd;
+	    }
+
+	  if (fmax < f)
+	    {
+	      f = fmax;
+	      x = xmax;
+	      for (int k = 0; k < 4; k++)
+		sol[k] = act1[k];
+	    }
+	}
+    }
+}
+
+
+
+
+template <typename POINTARRAY, typename FACEARRAY>
+inline int FindInnerPoint (POINTARRAY & points,
+			   FACEARRAY & faces,
+			   Point3d & p)
+{
+  static int timer = NgProfiler::CreateTimer ("FindInnerPoint");
+  NgProfiler::RegionTimer reg (timer);
+
+  ARRAY<Vec3d> a;
+  ARRAY<double> c;
+  Mat<3> m, inv;
+  Vec<3> rs, x, center;
+  double f;
+
+  int nf = faces.Size();
+
+  // minimize_x  max_i  a_i x + c_i
+
+  a.SetSize (nf+4);
+  c.SetSize (nf+4);
+
+  for (int i = 0; i < nf; i++)
+    {
+      Point3d p1 = points.Get(faces[i][0]);
+      a[i] = Cross (points.Get(faces[i][1]) - p1,
+		    points.Get(faces[i][2]) - p1);
+      a[i] /= a[i].Length();
+      c[i] = - (a[i].X() * p1.X() + a[i].Y() * p1.Y() + a[i].Z() * p1.Z());
+    }
+
+  /*
+  center = 0;
+  for (int i = 0; i < points.Size(); i++)
+    center += Vec<3> (points[i]);
+  center /= points.Size();
+  */
+
+  center = 0;
+  for (int i = 0; i < faces.Size(); i++)
+    for (int j = 0; j < 3; j++)
+      center += Vec<3> (points.Get(faces[i][j]));
+  center /= (3*faces.Size());
+
+
+  // (*testout) << "center = " << center << endl;
+
+  double hmax = 0;
+  for (int i = 0; i < nf; i++)
+    {
+      // const Element2d & el = faces[i];
+      // (*testout) << "el[" << i << "] = " << el << endl;
+      for (int j = 1; j <= 3; j++)
+	{
+	  double hi = Dist (points.Get(faces[i].PNumMod(j)),
+			    points.Get(faces[i].PNumMod(j+1)));
+	  if (hi > hmax) hmax = hi;
+	}
+    }
+  
+  // (*testout) << "hmax = " << hmax << endl;
+  
+  a[nf] = Vec<3> (1, 0, 0);
+  c[nf] = -center(0) - hmax;
+  a[nf+1] = Vec<3> (0, 1, 0);
+  c[nf+1] = -center(1) - hmax;
+  a[nf+2] = Vec<3> (0, 0, 1);
+  c[nf+2] = -center(2) - hmax;
+  a[nf+3] = Vec<3> (-1, -1, -1);
+  c[nf+3] = center(0)+center(1)+center(2)-3*hmax;
+
+  /*
+  (*testout) << "findip, a now = " << endl << a << endl;
+  (*testout) << "findip, c now = " << endl << c << endl;
+  */
+
+  int act[5] = { 0, nf, nf+1, nf+2, nf+3 };
+  int sol[4];
+
+  while (1)
+    {
+      /*
+      (*testout) << "try ";
+      for (int j = 0; j < 5; j++)
+	(*testout)  << act[j] << " ";
+      */
+
+      Minimize (a, c, act, x, f, sol);
+
+      /*
+      (*testout) << endl << "sol = ";
+      for (int j = 0; j < 4; j++)
+	(*testout)  << sol[j] << " ";
+
+      (*testout) << " fmin = " << f << endl;
+      */
+      for (int j = 0; j < 4; j++) act[j] = sol[j];
+      
+      bool found = 0;
+      double maxval = f;
+      for (int j = 0; j < nf; j++)
+	{
+	  double val = x(0) * a[j].X() + x(1) * a[j].Y() + x(2) * a[j].Z() + c[j];
+	  if (val > maxval + hmax * 1e-6)
+	    {
+	      found = 1;
+	      maxval = val;
+	      act[4] = j;
+	    }
+	}
+      
+      // (*testout) << "maxval = " << maxval << endl;
+      if (!found) break;
+    }
+  
+  // cout << "converged, f = " << f << endl;
+  
+  p = Point3d (x(0), x(1), x(2));
+  // (*testout) << "findip, f = " << f << ", hmax = " << hmax << endl;
+  return (f < -1e-5 * hmax);
+}
+
+
+
diff --git a/contrib/Netgen/libsrc/meshing/findip2.hpp b/contrib/Netgen/libsrc/meshing/findip2.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..fa9215d95c25264943e5d09adc7ecd4691c59982
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/findip2.hpp
@@ -0,0 +1,95 @@
+// find inner point
+
+template <typename POINTARRAY, typename FACEARRAY>
+inline int FindInnerPoint2 (POINTARRAY & points,
+			    FACEARRAY & faces,
+			    Point3d & p)
+{
+  static int timer = NgProfiler::CreateTimer ("FindInnerPoint2");
+  NgProfiler::RegionTimer reg (timer);
+
+  ARRAY<Vec3d> a;
+  ARRAY<double> c;
+  Mat<3> m, inv;
+  Vec<3> rs, x, pmin;
+
+  int nf = faces.Size();
+
+  a.SetSize (nf);
+  c.SetSize (nf);
+
+  for (int i = 0; i < nf; i++)
+    {
+      Point3d p1 = points.Get(faces[i][0]);
+      a[i] = Cross (points.Get(faces[i][1]) - p1,
+		    points.Get(faces[i][2]) - p1);
+      a[i] /= a[i].Length();
+      c[i] = - (a[i].X() * p1.X() + a[i].Y() * p1.Y() + a[i].Z() * p1.Z());
+    }
+
+
+  x = 0;
+  
+  
+  double hmax = 0;
+  for (int i = 0; i < nf; i++)
+    {
+      const Element2d & el = faces[i];
+      for (int j = 1; j <= 3; j++)
+	{
+	  double hi = Dist (points.Get(el.PNumMod(j)),
+			    points.Get(el.PNumMod(j+1)));
+	  if (hi > hmax) hmax = hi;
+	}
+    }
+
+  double fmin = 0;
+
+  for (int i1 = 1; i1 <= nf; i1++)
+    for (int i2 = i1+1; i2 <= nf; i2++)
+      for (int i3 = i2+1; i3 <= nf; i3++)
+        for (int i4 = i3+1; i4 <= nf; i4++)
+          {
+	    m(0, 0) = a.Get(i1).X() - a.Get(i2).X();
+	    m(0, 1) = a.Get(i1).Y() - a.Get(i2).Y();
+	    m(0, 2) = a.Get(i1).Z() - a.Get(i2).Z();
+	    rs(0) = c.Get(i2) - c.Get(i1);
+
+	    m(1, 0) = a.Get(i1).X() - a.Get(i3).X();
+	    m(1, 1) = a.Get(i1).Y() - a.Get(i3).Y();
+	    m(1, 2) = a.Get(i1).Z() - a.Get(i3).Z();
+	    rs(1) = c.Get(i3) - c.Get(i1);
+
+	    m(2, 0) = a.Get(i1).X() - a.Get(i4).X();
+	    m(2, 1) = a.Get(i1).Y() - a.Get(i4).Y();
+	    m(2, 2) = a.Get(i1).Z() - a.Get(i4).Z();
+	    rs(2) = c.Get(i4) - c.Get(i1);
+
+
+	    if (fabs (Det (m)) > 1e-10)
+	      {
+		CalcInverse (m, inv);
+		x = inv * rs;
+
+		double f = -1e10;
+		for (int i = 0; i < nf; i++)
+		  {
+		    double hd = 
+		      x(0) * a[i].X() + x(1) * a[i].Y() + x(2) * a[i].Z() + c[i];
+		    if (hd > f) f = hd;
+		    if (hd > fmin) break;
+		  }
+
+		if (f < fmin)
+		  {
+		    fmin = f;
+		    pmin = x;
+		  }
+	      }
+          }
+
+  p = Point3d (pmin(0), pmin(1), pmin(2));
+  (*testout) << "fmin = " << fmin << endl;
+  return (fmin < -1e-3 * hmax);
+}
+
diff --git a/contrib/Netgen/libsrc/meshing/geomsearch.cpp b/contrib/Netgen/libsrc/meshing/geomsearch.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..1bedd23ccb899fbf48bbd61c524ded8eab8e4a5a
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/geomsearch.cpp
@@ -0,0 +1,263 @@
+#include <mystdlib.h>
+#include "meshing.hpp"
+
+
+namespace netgen
+{
+  GeomSearch3d :: GeomSearch3d() 
+  {
+    size.i1 = 0; size.i2 = 0; size.i3 = 0; 
+  };
+
+  GeomSearch3d :: ~GeomSearch3d()
+  {
+    //delete old Hashtable:
+    if (size.i1 != 0)
+      {
+	for (int i = 0; i < size.i1*size.i2*size.i3; i++)
+	  delete hashtable[i];
+      } 
+  }
+
+  void GeomSearch3d :: Init (ARRAY <FrontPoint3,PointIndex::BASE> *pointsi, ARRAY <FrontFace> *facesi)
+  {
+    points = pointsi;
+    faces = facesi;
+    size.i1 = 0; size.i2 = 0; size.i3 = 0; 
+    reset = 1;
+    hashcount = 1;
+  }
+
+  void GeomSearch3d :: ElemMaxExt(Point3d& minp, Point3d& maxp, const MiniElement2d& elem)
+  {
+    maxp.X()=(*points)[elem.PNum(1)].P()(0);
+    maxp.Y()=(*points)[elem.PNum(1)].P()(1);
+    maxp.Z()=(*points)[elem.PNum(1)].P()(2);
+    minp.X()=(*points)[elem.PNum(1)].P()(0);
+    minp.Y()=(*points)[elem.PNum(1)].P()(1);
+    minp.Z()=(*points)[elem.PNum(1)].P()(2);
+  
+    for (int i=2; i <= 3; i++)
+      {
+	maxp.X()=max2((*points)[elem.PNum(i)].P()(0),maxp.X());
+	maxp.Y()=max2((*points)[elem.PNum(i)].P()(1),maxp.Y());
+	maxp.Z()=max2((*points)[elem.PNum(i)].P()(2),maxp.Z());
+	minp.X()=min2((*points)[elem.PNum(i)].P()(0),minp.X());
+	minp.Y()=min2((*points)[elem.PNum(i)].P()(1),minp.Y());
+	minp.Z()=min2((*points)[elem.PNum(i)].P()(2),minp.Z());
+      }
+  }
+
+  void GeomSearch3d :: MinCoords(const Point3d& p1, Point3d& p2)
+  {
+    p2.X()=min2(p1.X(),p2.X());
+    p2.Y()=min2(p1.Y(),p2.Y());
+    p2.Z()=min2(p1.Z(),p2.Z());
+  }
+
+  void GeomSearch3d :: MaxCoords(const Point3d& p1, Point3d& p2)
+  {
+    p2.X()=max2(p1.X(),p2.X());
+    p2.Y()=max2(p1.Y(),p2.Y());
+    p2.Z()=max2(p1.Z(),p2.Z());
+  }
+
+  void GeomSearch3d :: Create()
+  {
+    INDEX i,j,k;
+    if (reset)
+      {
+	const double hashelemsizefactor = 4;
+	reset = 0;
+	/*
+	  minext=Point3d(MAXDOUBLE, MAXDOUBLE, MAXDOUBLE);
+	  maxext=Point3d(MINDOUBLE, MINDOUBLE, MINDOUBLE);
+	*/
+	ElemMaxExt(minext, maxext, faces->Get(1).Face());
+	Point3d maxp, minp;
+	Vec3d midext(0,0,0);
+      
+	//get max Extension of Frontfaces
+	for (i = 1; i <= faces->Size(); i++)
+	  {
+	    ElemMaxExt(minp, maxp, faces->Get(i).Face());
+	    MinCoords(minp, minext);
+	    MaxCoords(maxp, maxext);
+	    midext+=maxp-minp;
+	  }
+
+
+	maxextreal = maxext;
+	maxext = maxext + 1e-4 * (maxext - minext);
+
+	midext*=1./faces->Size();
+	Vec3d boxext = maxext - minext;
+      
+	//delete old Hashtable:
+	if (size.i1 != 0)
+	  {
+	    for (i = 1; i <= size.i1*size.i2*size.i3; i++)
+	      {
+		delete hashtable.Get(i);
+	      }
+	  } 
+      
+	size.i1 = int (boxext.X()/midext.X()/hashelemsizefactor+1);
+	size.i2 = int (boxext.Y()/midext.Y()/hashelemsizefactor+1);
+	size.i3 = int (boxext.Z()/midext.Z()/hashelemsizefactor+1);
+	// PrintMessage (5, "hashsizes = ", size.i1, ", ", size.i2, ", ", size.i3);
+      
+	elemsize.X()=boxext.X()/size.i1;
+	elemsize.Y()=boxext.Y()/size.i2;
+	elemsize.Z()=boxext.Z()/size.i3;
+
+	//create Hasharrays:
+	hashtable.SetSize(size.i1*size.i2*size.i3);
+	for (i = 1; i <= size.i1; i++)
+	  {
+	    for (j = 1; j <= size.i2; j++)
+	      {
+		for (k = 1; k <= size.i3; k++)
+		  {
+		    INDEX ind=i+(j-1)*size.i1+(k-1)*size.i2*size.i1;
+		    hashtable.Elem(ind) = new ARRAY <int> ();
+		  }
+	      }
+	  }
+      }
+    else
+      {
+	//Clear all Hash-Arrays
+	for (i = 1; i <= size.i1; i++)
+	  {
+	    for (j = 1; j <= size.i2; j++)
+	      {
+		for (k = 1; k <= size.i3; k++)
+		  {
+		    INDEX ind=i+(j-1)*size.i1+(k-1)*size.i2*size.i1;
+		    hashtable.Elem(ind)->SetSize(0);
+		  }
+	      }
+	  }	  
+      }
+  
+    //Faces in Hashtable einfuegen:
+    for (i = 1; i <= faces->Size(); i++)
+      {
+	AddElem(faces->Get(i).Face(),i);
+      }
+  
+  }
+
+  void GeomSearch3d :: AddElem(const MiniElement2d& elem, INDEX elemnum)
+  {
+    Point3d minp, maxp;
+    ElemMaxExt(minp, maxp, elem);
+    int sx = int ((minp.X()-minext.X())/elemsize.X()+1.);
+    int ex = int ((maxp.X()-minext.X())/elemsize.X()+1.);
+    int sy = int ((minp.Y()-minext.Y())/elemsize.Y()+1.);
+    int ey = int ((maxp.Y()-minext.Y())/elemsize.Y()+1.);
+    int sz = int ((minp.Z()-minext.Z())/elemsize.Z()+1.);
+    int ez = int ((maxp.Z()-minext.Z())/elemsize.Z()+1.);
+  
+    for (int ix = sx; ix <= ex; ix++)
+      for (int iy = sy; iy <= ey; iy++)
+        for (int iz = sz; iz <= ez; iz++)
+          {
+            INDEX ind=ix+(iy-1)*size.i1+(iz-1)*size.i2*size.i1;
+            if (ind < 1 || ind > size.i1 * size.i2 * size.i3)
+              {
+                cerr << "Illegal hash-position";
+                cerr << "Position: " << ix << "," << iy << "," << iz << endl;
+		    throw NgException ("Illegal position in Geomsearch");
+              }
+            hashtable.Elem(ind)->Append(elemnum);		      
+          }
+  }
+
+  void GeomSearch3d :: GetLocals(ARRAY<MiniElement2d> & locfaces,  ARRAY<INDEX> & findex,
+				 INDEX fstind, const Point3d& p0, double xh)
+  {
+    hashcount++;
+  
+    Point3d minp, maxp, midp; 
+
+    minp=p0-Vec3d(xh,xh,xh); //lay cube over sphere
+    maxp=p0+Vec3d(xh,xh,xh);
+
+    MaxCoords(minext,minp); //cube may not be out of hash-region
+    MinCoords(maxextreal,maxp);
+
+
+    int cluster = faces->Get(fstind).Cluster();
+  
+    int sx = int((minp.X()-minext.X())/elemsize.X()+1.);
+    int ex = int((maxp.X()-minext.X())/elemsize.X()+1.);
+    int sy = int((minp.Y()-minext.Y())/elemsize.Y()+1.);
+    int ey = int((maxp.Y()-minext.Y())/elemsize.Y()+1.);
+    int sz = int((minp.Z()-minext.Z())/elemsize.Z()+1.);
+    int ez = int((maxp.Z()-minext.Z())/elemsize.Z()+1.);
+    int ix,iy,iz,i,k;
+
+    int cnt1 = 0;  // test, how efficient hashtable is
+    int cnt2 = 0;
+    int cnt3 = 0;
+  
+    for (ix = sx; ix <= ex; ix++)
+      {
+	for (iy = sy; iy <= ey; iy++)
+	  {
+	    for (iz = sz; iz <= ez; iz++)
+	      {
+		INDEX ind=ix+(iy-1)*size.i1+(iz-1)*size.i2*size.i1;
+	      
+		//go through all elements in one hash area
+		const ARRAY <int> & area = *hashtable.Elem(ind);
+		for (k = 1; k <= area.Size(); k++)
+		  {
+		    cnt2++;
+		    i = area.Get(k);
+		    if (faces->Get(i).Cluster() == cluster && 
+			faces->Get(i).Valid() &&
+			faces->Get(i).HashValue() != hashcount && 
+			i != fstind)
+		      {
+			cnt1++;
+			const MiniElement2d & face = faces->Get(i).Face();
+		      
+			const Point3d & p1 = (*points)[face.PNum(1)].P();
+			const Point3d & p2 = (*points)[face.PNum(2)].P();
+			const Point3d & p3 = (*points)[face.PNum(3)].P();
+		      
+			midp = Center (p1, p2, p3);
+		      
+			// if (Dist2 (midp, p0) <= xh*xh)  
+                        if((Dist2 (p1, p0) <= xh*xh) ||
+                           (Dist2 (p2, p0) <= xh*xh) ||
+                           (Dist2 (p3, p0) <= xh*xh) ||
+                           (Dist2 (midp, p0) <= xh*xh) )  // by Jochen Wild
+			  {
+			    cnt3++;
+			    locfaces.Append(faces->Get(i).Face());
+			    findex.Append(i);
+			    faces->Elem(i).SetHashValue(hashcount);
+			  }
+		      }
+		  }
+	      }
+	  }
+      }
+    /*
+      if (faces->Size() != 0 && hashcount % 200 == 0)
+      {
+      (*mycout) << "n.o.f= " << faces->Size();
+      (*mycout) << ", n.o.lf= " << locfaces.Size();
+      (*mycout) << ", hashf= " << (double)cnt2/(double)faces->Size();
+      (*mycout) << " (" << (double)cnt1/(double)faces->Size();
+      (*mycout) << ", " << (double)cnt3/(double)faces->Size() << ")" << endl;
+      }
+    */
+
+  }
+
+}
diff --git a/contrib/Netgen/libsrc/meshing/geomsearch.hpp b/contrib/Netgen/libsrc/meshing/geomsearch.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..236c98b13f35b25ca395e86d7dd734f6a6810d22
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/geomsearch.hpp
@@ -0,0 +1,117 @@
+#ifndef FILE_GEOMSEARCH
+#define FILE_GEOMSEARCH
+
+/**************************************************************************/
+/* File:   geomsearch.hh                                                  */
+/* Author: Johannes Gerstmayr                                             */
+/* Date:   19. Nov. 97                                                    */
+/**************************************************************************/
+
+class FrontPoint3;
+class FrontFace;
+class MiniElement2d;
+
+  /// class for quick access of 3D-elements; class cannot delete elements, but only append
+class GeomSearch3d
+{
+
+public:
+  ///
+  GeomSearch3d();
+  ///
+  virtual ~GeomSearch3d();
+
+  ///
+  void Init (ARRAY <FrontPoint3,PointIndex::BASE> *pointsi, ARRAY <FrontFace> *facesi);
+
+  ///get elements max extension
+  void ElemMaxExt(Point3d& minp, Point3d& maxp, const MiniElement2d& elem);
+  
+  ///get minimum coordinates of two points ->p2
+  void MinCoords(const Point3d& p1, Point3d& p2);
+
+  ///get minimum coordinates of two points ->p2
+  void MaxCoords(const Point3d& p1, Point3d& p2);
+
+  ///create a hashtable from an existing array of triangles
+  ///sizei = number of pieces in one direction
+  void Create();
+
+  ///add new element to Hashtable
+  void AddElem(const MiniElement2d& elem, INDEX elemnum);
+
+  ///GetLocal faces in sphere with radius xh and middlepoint p
+  void GetLocals(ARRAY<MiniElement2d> & locfaces,  ARRAY<INDEX> & findex,
+		 INDEX fstind, const Point3d& p0, double xh);
+
+private:
+  
+  ARRAY <FrontFace> *faces; // Pointers to Arrays in Adfront
+  ARRAY <FrontPoint3,PointIndex::BASE> *points;
+
+  ARRAY <ARRAY <int>*> hashtable;
+
+  Point3d minext; //extension of Hashdomain
+  Point3d maxext;
+  Point3d maxextreal;
+  Vec3d elemsize;  //size of one Hash-Element
+
+  threeint size; // size of Hashtable in each direction
+  int reset;
+  int hashcount;
+};
+
+#endif
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/contrib/Netgen/libsrc/meshing/global.cpp b/contrib/Netgen/libsrc/meshing/global.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..60a1fbe51d15b2846c108725384962b23b62b614
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/global.cpp
@@ -0,0 +1,53 @@
+#include <mystdlib.h>
+#include "meshing.hpp"
+
+namespace netgen
+{
+  ostream * testout = &cout;
+
+  ostream * mycout = &cout;
+  ostream * myerr = &cerr;
+
+
+  // Flags globflags; // not used anymoure
+  Flags parameters;
+
+
+  int silentflag = 0;
+  int testmode = 0;
+
+  MeshingParameters mparam;
+  volatile multithreadt multithread;
+
+  string ngdir = ".";
+
+  ARRAY<int> tets_in_qualclass;
+
+
+  multithreadt :: multithreadt()
+  {
+    pause =0;
+    testmode = 0;
+    redraw = 0;
+    drawing = 0;
+    terminate = 0;
+    running = 0;
+    percent = 0;
+    task = "";
+  }
+
+  DebugParameters debugparam;
+  bool verbose = 0;
+
+  int timestamp = 0;
+  int GetTimeStamp() 
+  { 
+    return timestamp; 
+  }
+
+  int NextTimeStamp()
+  {
+    timestamp++;
+    return timestamp;
+  }
+}
diff --git a/contrib/Netgen/libsrc/meshing/global.hpp b/contrib/Netgen/libsrc/meshing/global.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..1019624518a27d15530e48a6910bb4838b45627b
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/global.hpp
@@ -0,0 +1,54 @@
+#ifndef FILE_GLOBAL
+#define FILE_GLOBAL
+
+
+/**************************************************************************/
+/* File:   global.hh                                                      */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   01. Okt. 95                                                    */
+/**************************************************************************/
+
+/*
+  global functions and variables
+*/
+
+///
+extern double GetTime ();
+extern void ResetTime ();
+
+///
+extern int testmode;
+
+// extern ostream * testout;
+// extern AutoPtr<ostream> testout;
+
+/// calling parameters
+extern Flags parameters;
+
+extern MeshingParameters mparam;
+
+extern ARRAY<int> tets_in_qualclass;
+
+
+class multithreadt
+{
+public:
+  int pause;
+  int testmode;
+  int redraw;
+  int drawing;
+  int terminate;
+  int running;
+  double percent;
+  const char * task;
+  bool demorunning;
+  multithreadt();
+};
+
+extern volatile multithreadt multithread;
+
+extern string ngdir;
+extern DebugParameters debugparam;
+extern bool verbose;  
+
+#endif
diff --git a/contrib/Netgen/libsrc/meshing/hpref_hex.hpp b/contrib/Netgen/libsrc/meshing/hpref_hex.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..11e3f86e4949da4beccb772f2c2d4beeff066e8d
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/hpref_hex.hpp
@@ -0,0 +1,236 @@
+// SZ 
+
+// HP_HEX  ... no refinement
+int refhex_splitedges[][3] =
+  {
+      { 0, 0, 0 }
+  };
+HPREF_ELEMENT_TYPE refhex_newelstypes[] =
+  {
+    HP_HEX,
+    HP_NONE,
+  };
+int refhex_newels[][8] =
+  {
+    { 1, 2, 3, 4, 5, 6, 7, 8 }
+  };
+HPRef_Struct refhex =
+  {
+    HP_HEX,
+    refhex_splitedges, 
+    0, 0,
+    refhex_newelstypes, 
+    refhex_newels
+  };
+
+// HP_HEX_1F  ... face (1 - 4 - 3 -2) singular 
+int refhex_1f_0e_0v_splitedges[][3] =
+  {
+    { 1, 5, 9 },
+    { 2, 6, 10 },
+    { 3, 7, 11 },
+    { 4, 8, 12 }, 
+    { 0, 0, 0 }
+  };
+HPREF_ELEMENT_TYPE refhex_1f_0e_0v_newelstypes[] =
+  {
+    HP_HEX,
+    HP_HEX_1F_0E_0V,
+    HP_NONE,
+  };
+int  refhex_1f_0e_0v_newels[][8] =
+  {
+    { 9, 10, 11, 12, 5, 6, 7, 8 }, 
+    { 1, 2, 3, 4, 9, 10, 11, 12}  
+ }; 
+HPRef_Struct refhex_1f_0e_0v =
+  {
+    HP_HEX,
+    refhex_1f_0e_0v_splitedges, 
+    0, 0,
+    refhex_1f_0e_0v_newelstypes, 
+    refhex_1f_0e_0v_newels
+  };
+
+
+
+// HP_HEX_1FA_1FB  ... face (1 - 4 - 3 -2) and face (1-2-6-5) singular 
+int refhex_1fa_1fb_0e_0v_splitedges[][3] =
+  {
+    { 1, 5, 9 },
+    { 2, 6, 10 },
+    { 3, 7, 11 },
+    { 4, 8, 12 },
+    { 1, 4, 13 },
+    { 2, 3, 14 },  
+    { 6, 7, 15 }, 
+    { 5, 8, 16 }, 
+    { 0, 0, 0 }
+  };
+
+int refhex_1fa_1fb_0e_0v_splitfaces[][4] =
+  {
+    { 2, 3, 6, 17 },
+    { 1, 4, 5, 18 },
+    { 0, 0, 0, 0 },
+  };
+HPREF_ELEMENT_TYPE refhex_1fa_1fb_0e_0v_newelstypes[] =
+  {
+    HP_HEX,
+    HP_HEX_1F_0E_0V,
+    HP_HEX_1F_0E_0V, 
+    HP_HEX_1FA_1FB_0E_0V, 
+    HP_NONE,
+  };
+int  refhex_1fa_1fb_0e_0v_newels[][8] =
+  {
+    {18, 17, 11, 12, 16, 15, 7, 8}, 
+    {13, 14, 3, 4, 18, 17, 11, 12},
+    { 5, 6, 10, 9, 16, 15, 17, 18}, 
+    { 1, 2, 14, 13, 9, 10, 17, 18} 
+  }; 
+HPRef_Struct refhex_1fa_1fb_0e_0v =
+  {
+    HP_HEX,
+    refhex_1fa_1fb_0e_0v_splitedges, 
+    refhex_1fa_1fb_0e_0v_splitfaces, 0,
+    refhex_1fa_1fb_0e_0v_newelstypes, 
+    refhex_1fa_1fb_0e_0v_newels
+  };
+
+
+
+// Refine Dummies 
+  // HP_HEX_0E_1V
+  int refhex_0e_1v_splitedges[][3] =
+    {
+      { 0, 0, 0 }
+    };
+  HPREF_ELEMENT_TYPE refhex_0e_1v_newelstypes[] =
+    {
+      HP_TET_0E_1V,
+      HP_TET,
+      HP_TET,
+      HP_TET,
+      HP_TET,
+      HP_TET,
+      HP_NONE,
+    };
+  int refhex_0e_1v_newels[][8] =
+    {
+      { 1, 5, 2, 4 },
+      { 7, 3, 6, 8 },
+      { 2, 8, 5, 6 },
+      { 2, 8, 6, 3 },
+      { 2, 8, 3, 4 },
+      { 2, 8, 4, 5 },
+    };
+  HPRef_Struct refhex_0e_1v =
+    {
+      HP_HEX,
+      refhex_0e_1v_splitedges, 
+      0, 0,
+      refhex_0e_1v_newelstypes, 
+      refhex_0e_1v_newels
+    };
+
+
+
+// Refine Dummies 
+  // HP_HEX_1E_1V
+  int refhex_1e_1v_splitedges[][3] =
+    {
+      { 0, 0, 0 }
+    };
+  HPREF_ELEMENT_TYPE refhex_1e_1v_newelstypes[] =
+    {
+      HP_TET_1E_1VA,
+      HP_TET,
+      HP_TET_0E_1V,
+      HP_TET_0E_1V,
+      HP_TET_0E_1V,
+      HP_TET_0E_1V,
+      HP_NONE,
+    };
+  int refhex_1e_1v_newels[][8] =
+    {
+      // { 1, 5, 2, 4 }, 
+      { 1, 2, 4, 5 },
+      { 7, 3, 6, 8 },
+      { 2, 8, 5, 6 },
+      { 2, 8, 6, 3 },
+      { 2, 8, 3, 4 },
+      { 2, 8, 4, 5 },
+    };
+  HPRef_Struct refhex_1e_1v =
+    {
+      HP_HEX,
+      refhex_1e_1v_splitedges, 
+      0, 0,
+      refhex_1e_1v_newelstypes, 
+      refhex_1e_1v_newels
+    };
+
+
+// Refine Dummies 
+  // HP_HEX_3E_0V
+  int refhex_3e_0v_splitedges[][3] =
+    {
+      { 0, 0, 0 }
+    };
+  HPREF_ELEMENT_TYPE refhex_3e_0v_newelstypes[] =
+    {
+      HP_TET_1E_1VA,
+      HP_TET_1E_1VA,
+      HP_TET_1E_1VA,
+      HP_TET_0E_1V,
+      HP_TET,
+      HP_NONE,
+    };
+  int refhex_3e_0v_newels[][8] =
+    {
+      { 1, 2, 3, 6 },
+      { 1, 4, 8, 3 },
+      { 1, 5, 6, 8 },
+      { 1, 6, 3, 8 },
+      { 3, 8, 6, 7 },
+    };
+  HPRef_Struct refhex_3e_0v =
+    {
+      HP_HEX,
+      refhex_3e_0v_splitedges, 
+      0, 0,
+      refhex_3e_0v_newelstypes, 
+      refhex_3e_0v_newels
+    };
+
+
+
+// Refine Dummies 
+  // HP_HEX_1E_0V 
+  int refhex_1e_0v_splitedges[][3] =
+    {
+      { 0, 0, 0 }
+    };
+
+  HPREF_ELEMENT_TYPE refhex_1e_0v_newelstypes[] =
+    {
+      HP_PRISM_SINGEDGE,         // HP_PRISM_SINGEDGE_H1,
+      HP_PRISM,
+      HP_NONE,
+    };
+  int refhex_1e_0v_newels[][8] =
+    {
+      { 1, 4, 5, 2, 3, 6 },
+      { 5, 4, 8, 6, 3, 7 },
+    };
+  HPRef_Struct refhex_1e_0v =
+    {
+      HP_HEX,
+      refhex_1e_0v_splitedges, 
+      0, 0,
+      refhex_1e_0v_newelstypes, 
+      refhex_1e_0v_newels
+    };
+
+
diff --git a/contrib/Netgen/libsrc/meshing/hpref_prism.hpp b/contrib/Netgen/libsrc/meshing/hpref_prism.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..3cceb44a5726d52fa25f5c0af623fe375bd096a0
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/hpref_prism.hpp
@@ -0,0 +1,3405 @@
+
+  // HP_PRISM  ... no refinement
+  int refprism_splitedges[][3] =
+    {
+      { 0, 0, 0 }
+    };
+  HPREF_ELEMENT_TYPE refprism_newelstypes[] =
+    {
+      HP_PRISM,
+      HP_NONE,
+    };
+  int refprism_newels[][8] =
+    {
+      { 1, 2, 3, 4, 5, 6 }
+    };
+  HPRef_Struct refprism =
+    {
+      HP_PRISM,
+      refprism_splitedges, 
+      0, 0,
+      refprism_newelstypes, 
+      refprism_newels
+    };
+
+
+
+  // HP_PRISM_SINGEDGE  ... vertical edge 1-4 is singular
+  int refprism_singedge_splitedges[][3] =
+    {
+      { 1, 2, 7 },
+      { 1, 3, 8 },
+      { 4, 5, 9 },
+      { 4, 6, 10 },
+      { 0, 0, 0 }
+    };
+  HPREF_ELEMENT_TYPE refprism_singedge_newelstypes[] =
+    {
+      HP_PRISM_SINGEDGE,
+      HP_HEX,
+      HP_NONE,
+    };
+  int refprism_singedge_newels[][8] =
+    {
+      { 1, 7, 8, 4, 9, 10 },
+      { 3, 8, 7, 2, 6, 10, 9, 5 }
+    };
+  HPRef_Struct refprism_singedge =
+    {
+      HP_PRISM,
+      refprism_singedge_splitedges, 
+      0, 0,
+      refprism_singedge_newelstypes, 
+      refprism_singedge_newels
+    };
+
+
+
+
+
+
+  // HP_PRISM_SINGEDGE_V12  vertical edges 1-4 and 2-5 are singular 
+  int refprism_singedge_v12_splitedges[][3] =
+    {
+      { 1, 2, 7 },
+      { 1, 3, 8 },
+      { 2, 1, 9 },
+      { 2, 3, 10 },
+      { 4, 5, 11 },
+      { 4, 6, 12 },
+      { 5, 4, 13 },
+      { 5, 6, 14},
+      { 0, 0, 0 }
+    };
+  HPREF_ELEMENT_TYPE refprism_singedge_v12_newelstypes[] =
+    {
+      HP_HEX,
+      HP_PRISM_SINGEDGE,
+      HP_PRISM_SINGEDGE,
+      HP_PRISM,
+      HP_NONE,
+    };
+  int refprism_singedge_v12_newels[][8] =
+    {
+      { 7, 9, 10, 8, 11, 13, 14, 12 },
+      { 1, 7, 8, 4, 11, 12 },
+      { 2, 10, 9, 5, 14, 13 },
+      { 3, 8, 10, 6, 12, 14 },
+    };
+  HPRef_Struct refprism_singedge_v12 =
+    {
+      HP_PRISM,
+      refprism_singedge_v12_splitedges, 
+      0, 0,
+      refprism_singedge_v12_newelstypes, 
+      refprism_singedge_v12_newels
+    };
+
+
+
+
+
+
+  // HP_PRISM_SINGEDGE_H12
+  int refprism_singedge_h12_splitedges[][3] =
+    {
+      { 1, 3, 7 },
+      { 2, 1, 8 },
+      { 2, 3, 9 },
+      { 3, 1, 10 },
+
+      { 4, 6, 12 },
+      { 5, 4, 13 },
+      { 5, 6, 14 },
+      { 6, 4, 15 },
+
+      { 0, 0, 0 }
+    };
+
+  int refprism_singedge_h12_splitfaces[][4] =
+    {
+      { 2, 1, 3, 11 },
+      { 5, 4, 6, 16 },
+      { 0, 0, 0, 0 },
+    };
+
+  HPREF_ELEMENT_TYPE refprism_singedge_h12_newelstypes[] =
+    {
+      HP_HEX,
+      HP_HEX,
+      HP_PRISM,
+      HP_PRISM,
+      HP_PRISM,
+      HP_NONE,
+    };
+  int refprism_singedge_h12_newels[][8] =
+    {
+      { 1, 8, 11, 7, 4, 13, 16, 12 },
+      { 9, 3, 10, 11, 14, 6, 15, 16 },
+      { 7, 11, 10, 12, 16, 15 },
+      { 2, 9, 11, 5, 14, 16 },
+      { 8, 2, 11, 13, 5, 16 }
+    };
+  HPRef_Struct refprism_singedge_h12 =
+    {
+      HP_PRISM,
+      refprism_singedge_h12_splitedges, 
+      refprism_singedge_h12_splitfaces, 
+      0,
+      refprism_singedge_h12_newelstypes, 
+      refprism_singedge_h12_newels
+    };
+
+
+
+
+
+
+  // HP_PRISM_SINGEDGE_H1
+  int refprism_singedge_h1_splitedges[][3] =
+    {
+      { 1, 3, 7 },
+      { 2, 3, 8 },
+      { 4, 6, 9 },
+      { 5, 6, 10 },
+      { 0, 0, 0 }
+    };
+  HPREF_ELEMENT_TYPE refprism_singedge_h1_newelstypes[] =
+    {
+      HP_HEX,
+      HP_PRISM,
+      HP_NONE,
+    };
+  int refprism_singedge_h1_newels[][8] =
+    {
+      { 1, 2, 8, 7, 4, 5, 10, 9 },
+      { 3, 7, 8, 6, 9, 10 }
+    };
+  HPRef_Struct refprism_singedge_h1 =
+    {
+      HP_PRISM,
+      refprism_singedge_h1_splitedges, 
+      0, 0,
+      refprism_singedge_h1_newelstypes, 
+      refprism_singedge_h1_newels
+    };
+
+
+
+//  HP_PRISM_1FA_0E_0V
+  int refprism_1fa_0e_0v_splitedges[][3] =
+    {
+      { 1, 4, 16 },
+      { 2, 5, 17 },
+      { 3, 6, 18 },
+      { 0, 0, 0 }
+    };
+  HPREF_ELEMENT_TYPE refprism_1fa_0e_0v_newelstypes[] =
+    {
+      HP_PRISM,
+      HP_PRISM_1FA_0E_0V,
+      HP_NONE,
+    };
+  int refprism_1fa_0e_0v_newels[][8] =
+    {
+      { 16, 17, 18, 4, 5, 6 },      
+      { 1, 2, 3, 16, 17, 18 }
+    };
+  HPRef_Struct refprism_1fa_0e_0v =
+    {
+      HP_PRISM,
+      refprism_1fa_0e_0v_splitedges, 
+      0, 0,
+      refprism_1fa_0e_0v_newelstypes, 
+      refprism_1fa_0e_0v_newels
+    };
+
+//  HP_PRISM_1FA_1E_0V
+  int refprism_1fa_1e_0v_splitedges[][3] =
+    {
+      { 1, 4, 16 },
+      { 2, 5, 17 },
+      { 3, 6, 18 },
+      { 1, 2, 7},
+      { 1, 3, 12},
+      { 4, 6, 45},
+      { 4, 5, 40},
+      { 0, 0, 0 }
+    };
+  int refprism_1fa_1e_0v_splitfaces[][4] =
+    {
+      {1,2,4,19},
+      {1,3,4,24},
+      {0,0,0,0}
+    }; 
+
+  HPREF_ELEMENT_TYPE refprism_1fa_1e_0v_newelstypes[] =
+    {
+      HP_PRISM_SINGEDGE,
+      HP_HEX,
+      HP_PRISM_1FA_1E_0V,
+      HP_HEX_1F_0E_0V,
+      HP_NONE,
+    };
+  int refprism_1fa_1e_0v_newels[][8] =
+    {
+      { 16, 19, 24, 4, 40, 45 }, 
+      { 24, 19,  17, 18, 45 , 40, 5, 6 }, 
+      { 1, 7 , 12 , 16, 19, 24 }, 
+      { 7, 2, 3, 12,  19, 17, 18, 24 }
+    };
+  HPRef_Struct refprism_1fa_1e_0v =
+    {
+      HP_PRISM,
+      refprism_1fa_1e_0v_splitedges, 
+      refprism_1fa_1e_0v_splitfaces, 
+      0,
+      refprism_1fa_1e_0v_newelstypes, 
+      refprism_1fa_1e_0v_newels
+    };
+
+//  HP_PRISM_2FA_1E_0V
+  int refprism_2fa_1e_0v_splitedges[][3] =
+    {
+      { 1, 4, 16 },
+      { 2, 5, 17 },
+      { 3, 6, 18 },
+      { 1, 2, 7}, 
+      { 1, 3, 12},
+      { 4, 6, 45},
+      { 4, 5, 40},
+      { 4, 1, 28},
+      { 5, 2, 29},
+      { 6, 3, 30},
+      { 0, 0, 0 }
+    };
+  int refprism_2fa_1e_0v_splitfaces[][4] =
+    {
+      {1,2,4,19},
+      {1,3,4,24},
+      {4,1,5,31},
+      {4,1,6,36},
+      {0,0,0,0}
+    }; 
+
+  HPREF_ELEMENT_TYPE refprism_2fa_1e_0v_newelstypes[] =
+    {
+      HP_PRISM_SINGEDGE,
+      HP_HEX,
+      HP_PRISM_1FA_1E_0V,
+      HP_HEX_1F_0E_0V,
+      HP_PRISM_1FA_1E_0V, 
+      HP_HEX_1F_0E_0V, 
+      HP_NONE,
+    };
+  int refprism_2fa_1e_0v_newels[][8] =
+    {
+      { 16, 19, 24, 28, 31, 36 }, 
+      { 24, 19,  17, 18, 36, 31, 29, 30 }, 
+      { 1, 7 , 12 , 16, 19, 24 }, 
+      { 12, 7, 2, 3, 24, 19, 17, 18 },
+      { 4, 45, 40, 28, 36, 31 }, 
+      { 40, 45, 6, 5, 31, 36, 30, 29,}
+    };
+  HPRef_Struct refprism_2fa_1e_0v =
+    {
+      HP_PRISM,
+      refprism_2fa_1e_0v_splitedges, 
+      refprism_2fa_1e_0v_splitfaces,
+      0,
+      refprism_2fa_1e_0v_newelstypes, 
+      refprism_2fa_1e_0v_newels
+    };
+
+//  HP_PRISM_1FB_0E_0V   ... quad face 1-2-4-5
+  int refprism_1fb_0e_0v_splitedges[][3] =
+    {
+      { 1, 3, 7 },
+      { 2, 3, 8 },
+      { 4, 6, 9 },
+      { 5, 6, 10 },
+      { 0, 0, 0 }
+    };
+  HPREF_ELEMENT_TYPE refprism_1fb_0e_0v_newelstypes[] =
+    {
+      HP_HEX_1F_0E_0V,
+      HP_PRISM,
+      HP_NONE,
+    };
+  int refprism_1fb_0e_0v_newels[][8] =
+    {
+      { 1, 4, 5, 2, 7, 9, 10, 8  },
+      { 7, 8, 3, 9, 10, 6 }
+    };
+  HPRef_Struct refprism_1fb_0e_0v =
+    {
+      HP_PRISM,
+      refprism_1fb_0e_0v_splitedges, 
+
+      0, 0,
+      refprism_1fb_0e_0v_newelstypes, 
+      refprism_1fb_0e_0v_newels
+    };
+
+
+//  HP_PRISM_1FB_1EA_0V   ... quad face 1-2-4-5
+  int refprism_1fb_1ea_0v_splitedges[][3] =
+    {
+      { 1, 3, 7 },
+      { 2, 3, 8 },
+      { 4, 6, 9 },
+      { 5, 6, 10 },
+      { 1, 2, 11 },
+      { 4, 5, 12 },
+      { 0, 0, 0 }
+    };
+  HPREF_ELEMENT_TYPE refprism_1fb_1ea_0v_newelstypes[] =
+    {
+      HP_HEX_1F_0E_0V,
+      HP_PRISM_1FB_1EA_0V,
+      HP_PRISM,
+      HP_NONE,
+    };
+  int refprism_1fb_1ea_0v_newels[][8] =
+    {
+      { 11, 12, 5, 2, 7, 9, 10, 8  },
+      { 1, 11, 7, 4, 12, 9 },
+      { 7, 8, 3, 9, 10, 6 }
+    };
+  HPRef_Struct refprism_1fb_1ea_0v =
+    {
+      HP_PRISM,
+      refprism_1fb_1ea_0v_splitedges, 
+      0, 0,
+      refprism_1fb_1ea_0v_newelstypes, 
+      refprism_1fb_1ea_0v_newels
+    };
+
+//  HP_PRISM_1FB_1EC_0V   ... quad face 1-2-4-5 with singular edge 3-6 
+  int refprism_1fb_1ec_0v_splitedges[][3] =
+    {
+      {2,3,9},
+      {1,3,12},
+      {3,2,10},
+      {3,1,11},
+      {5,6,42},
+      {4,6,45},
+      {6,5,43},
+      {6,4,44},
+      { 0, 0, 0 }
+    };
+  HPREF_ELEMENT_TYPE refprism_1fb_1ec_0v_newelstypes[] =
+    {
+      HP_PRISM_SINGEDGE, 
+      HP_HEX, 
+      HP_HEX_1F_0E_0V,
+      HP_NONE,
+    };
+  int refprism_1fb_1ec_0v_newels[][8] =
+    {
+      { 3, 11, 10, 6, 44, 43},
+      { 12, 9, 10, 11, 45, 42, 43, 44}, 
+      { 4, 5, 2, 1, 45, 42, 9, 12 } 
+    };
+  HPRef_Struct refprism_1fb_1ec_0v =
+    {
+      HP_PRISM,
+      refprism_1fb_1ec_0v_splitedges, 
+      0, 0,
+      refprism_1fb_1ec_0v_newelstypes, 
+      refprism_1fb_1ec_0v_newels
+    };
+
+//  HP_PRISM_1FA_1FB_1EC_0V   ... bot-trig face, quad face 1-2-4-5 with singular edge 3-6 
+  int refprism_1fa_1fb_1ec_0v_splitedges[][3] =
+    {
+      {2,3,9},
+      {1,3,12},
+      {3,2,10},
+      {3,1,11},
+      {5,6,42},
+      {4,6,45},
+      {6,5,43},
+      {6,4,44},
+      {1,4,16}, 
+      {2,5,17},
+      {3,6,18},
+      { 0, 0, 0 }
+    };
+
+ int refprism_1fa_1fb_1ec_0v_splitfaces[][4] =
+   {
+     {2,3,5,21},
+     {3,2,6,22},
+     {3,1,6,23},
+     {1,3,4,24},
+     {0,0,0,0}
+   }; 
+  HPREF_ELEMENT_TYPE refprism_1fa_1fb_1ec_0v_newelstypes[] =
+    {
+      HP_PRISM_SINGEDGE, 
+      HP_HEX, 
+      HP_HEX_1F_0E_0V,
+      HP_PRISM_1FA_1E_0V, 
+      HP_HEX_1F_0E_0V, 
+      HP_HEX_1FA_1FB_0E_0V,
+      HP_NONE,
+    };
+  int refprism_1fa_1fb_1ec_0v_newels[][8] =
+    {
+      { 18, 23, 22, 6, 44, 43},
+      { 24, 21, 22, 23, 45, 42, 43, 44}, 
+      { 4, 5, 17, 16, 45, 42, 21, 24}, 
+      { 3, 11, 10, 18, 23, 22}, 
+      { 12, 9, 10, 11, 24, 21, 22, 23},
+      { 1, 2, 9, 12, 16, 17, 21, 24}
+    };
+  HPRef_Struct refprism_1fa_1fb_1ec_0v =
+    {
+      HP_PRISM,
+      refprism_1fa_1fb_1ec_0v_splitedges,
+      refprism_1fa_1fb_1ec_0v_splitfaces, 0,
+      refprism_1fa_1fb_1ec_0v_newelstypes, 
+      refprism_1fa_1fb_1ec_0v_newels
+    };
+
+
+//  HP_PRISM_1FA_1FB_2EB_0V  
+  int refprism_1fa_1fb_2eb_0v_splitedges[][3] =
+    {
+      {2,3,9},
+      {1,3,12},
+      {3,2,10},
+      {3,1,11},
+      {5,6,42},
+      {4,6,45},
+      {6,5,43},
+      {6,4,44},
+      {1,4,16}, 
+      {2,5,17},
+      {3,6,18},
+      { 4, 5, 40},
+      { 4, 6, 45},
+      { 1, 2, 7},
+      { 0, 0, 0 }
+    };
+
+ int refprism_1fa_1fb_2eb_0v_splitfaces[][4] =
+   {
+     {2,3,5,21},
+     {3,2,6,22},
+     {3,1,6,23},
+     {1,3,4,24},
+     {1,2,4,19},
+     {0,0,0,0}
+   }; 
+  HPREF_ELEMENT_TYPE refprism_1fa_1fb_2eb_0v_newelstypes[] =
+    {
+      HP_PRISM_SINGEDGE, 
+      HP_HEX, 
+      HP_HEX_1F_0E_0V,
+      HP_PRISM_1FA_1E_0V, 
+      HP_HEX_1F_0E_0V, 
+      HP_HEX_1FA_1FB_0E_0V,
+      HP_PRISM_1FB_1EA_0V, 
+      HP_PRISM_1FA_1FB_1EA_0V, 
+      HP_NONE,
+    };
+  int refprism_1fa_1fb_2eb_0v_newels[][8] =
+    {
+      { 18, 23, 22, 6, 44, 43},
+      { 24, 21, 22, 23, 45, 42, 43, 44}, 
+      { 40, 5, 17, 19, 45, 42, 21, 24}, 
+      { 3, 11, 10, 18, 23, 22}, 
+      { 12, 9, 10, 11, 24, 21, 22, 23},
+      { 7, 2, 9, 12, 19, 17, 21, 24},
+      {16,19,24,4,40,45},
+      {1,7,12,16,19,24}
+    };
+  HPRef_Struct refprism_1fa_1fb_2eb_0v =
+    {
+      HP_PRISM,
+      refprism_1fa_1fb_2eb_0v_splitedges, 
+      refprism_1fa_1fb_2eb_0v_splitfaces, 0,
+      refprism_1fa_1fb_2eb_0v_newelstypes, 
+      refprism_1fa_1fb_2eb_0v_newels
+    };
+
+ //  HP_PRISM_1FA_1FB_2EC_0V 
+  int refprism_1fa_1fb_2ec_0v_splitedges[][3] =
+    {
+      {2,3,9},
+      {1,3,12},
+      {3,2,10},
+      {3,1,11},
+      {5,6,42},
+      {4,6,45},
+      {6,5,43},
+      {6,4,44},
+      {1,4,16}, 
+      {2,5,17},
+      {3,6,18},
+      {5,4,41},
+      {2,1,8},
+      { 0, 0, 0 }
+    };
+
+ int refprism_1fa_1fb_2ec_0v_splitfaces[][4] =
+   {
+     {2,3,5,21},
+     {3,2,6,22},
+     {3,1,6,23},
+     {1,3,4,24},
+     {2,1,5,20},
+     {0,0,0,0}
+   }; 
+  HPREF_ELEMENT_TYPE refprism_1fa_1fb_2ec_0v_newelstypes[] =
+    {
+      HP_PRISM_SINGEDGE, 
+      HP_HEX, 
+      HP_HEX_1F_0E_0V,
+      HP_PRISM_1FA_1E_0V, 
+      HP_HEX_1F_0E_0V, 
+      HP_HEX_1FA_1FB_0E_0V,
+      HP_PRISM_1FA_1FB_1EB_0V, 
+      HP_PRISM_1FB_1EA_0V,
+      HP_NONE,
+    };
+  int refprism_1fa_1fb_2ec_0v_newels[][8] =
+    {
+      { 18, 23, 22, 6, 44, 43},
+      { 24, 21, 22, 23, 45, 42, 43, 44}, 
+      { 4, 41, 20, 16, 45, 42, 21, 24}, 
+      { 3, 11, 10, 18, 23, 22}, 
+      { 12, 9, 10, 11, 24, 21, 22, 23},
+      { 1, 8, 9, 12, 16, 20, 21, 24}, 
+      {8,2,9,20,17,21}, 
+      {5,41,42,17,20,21}
+    };
+  HPRef_Struct refprism_1fa_1fb_2ec_0v =
+    {
+      HP_PRISM,
+      refprism_1fa_1fb_2ec_0v_splitedges, 
+      refprism_1fa_1fb_2ec_0v_splitfaces,
+      0,
+      refprism_1fa_1fb_2ec_0v_newelstypes, 
+      refprism_1fa_1fb_2ec_0v_newels
+    };
+
+
+
+
+
+
+
+//  HP_PRISM_2FA_1FB_1EC_0V   ... trig faces, quad face 1-2-4-5 with singular edge 3-6 
+  int refprism_2fa_1fb_1ec_0v_splitedges[][3] =
+    {
+      {2,3,9},
+      {1,3,12},
+      {3,2,10},
+      {3,1,11},
+      {5,6,42},
+      {4,6,45},
+      {6,5,43},
+      {6,4,44},
+      {1,4,16}, 
+      {2,5,17},
+      {3,6,18},
+      { 4, 1, 28},
+      { 5, 2, 29},
+      { 6, 3, 30},
+      { 0, 0, 0 }
+    };
+
+ int refprism_2fa_1fb_1ec_0v_splitfaces[][4] =
+   {
+     {2,3,5,21},
+     {3,2,6,22},
+     {3,1,6,23},
+     {1,3,4,24},
+     {5,2,6,33},
+     {6,5,3,34},
+     {6,4,3,35},
+     {4,1,6,36},
+     {0,0,0,0}
+   }; 
+  HPREF_ELEMENT_TYPE refprism_2fa_1fb_1ec_0v_newelstypes[] =
+    {
+      HP_PRISM_SINGEDGE, 
+      HP_HEX, 
+      HP_HEX_1F_0E_0V,
+      HP_PRISM_1FA_1E_0V, 
+      HP_HEX_1F_0E_0V, 
+      HP_HEX_1FA_1FB_0E_0V,
+      HP_PRISM_1FA_1E_0V, 
+      HP_HEX_1F_0E_0V, 
+      HP_HEX_1FA_1FB_0E_0V,
+      HP_NONE,
+    };
+  int refprism_2fa_1fb_1ec_0v_newels[][8] =
+    {
+      { 18, 23, 22, 30, 35, 34},
+      { 24, 21, 22, 23, 36, 33, 34, 35}, 
+      { 28, 29, 17, 16, 36, 33, 21, 24}, 
+      { 3, 11, 10, 18, 23, 22}, 
+      { 12, 9, 10, 11, 24, 21, 22, 23},
+      { 1, 2, 9, 12, 16, 17, 21, 24},
+      { 6, 43, 44, 30, 34, 35},
+      { 44, 43, 42, 45, 35, 34, 33, 36}, 
+      { 5, 4, 45, 42, 29, 28, 36, 33 }, 
+    };
+  HPRef_Struct refprism_2fa_1fb_1ec_0v =
+    {
+      HP_PRISM,
+      refprism_2fa_1fb_1ec_0v_splitedges, 
+      refprism_2fa_1fb_1ec_0v_splitfaces,
+      0,
+      refprism_2fa_1fb_1ec_0v_newelstypes, 
+      refprism_2fa_1fb_1ec_0v_newels
+    };
+
+//  HP_PRISM_2FA_1FB_2EB_0V  
+  int refprism_2fa_1fb_2eb_0v_splitedges[][3] =
+    {
+      {2,3,9},
+      {1,3,12},
+      {3,2,10},
+      {3,1,11},
+      {5,6,42},
+      {4,6,45},
+      {6,5,43},
+      {6,4,44},
+      {1,4,16}, 
+      {2,5,17},
+      {3,6,18},
+      { 4, 1, 28},
+      { 5, 2, 29},
+      { 6, 3, 30},
+      {4,5,40},
+      {1,2,7},
+      { 0, 0, 0 }
+    };
+
+ int refprism_2fa_1fb_2eb_0v_splitfaces[][4] =
+   {
+     {2,3,5,21},
+     {3,2,6,22},
+     {3,1,6,23},
+     {1,3,4,24},
+     {5,6,2,33},
+     {6,5,3,34},
+     {6,4,3,35},
+     {4,1,6,36},
+     {4,1,5,31},
+     {1,2,4,19},
+     {0,0,0,0}
+   }; 
+  HPREF_ELEMENT_TYPE refprism_2fa_1fb_2eb_0v_newelstypes[] =
+    {
+      HP_PRISM_SINGEDGE, 
+      HP_HEX, 
+      HP_HEX_1F_0E_0V,
+      HP_PRISM_1FA_1E_0V, 
+      HP_HEX_1F_0E_0V, 
+      HP_HEX_1FA_1FB_0E_0V,
+      HP_PRISM_1FA_1E_0V, 
+      HP_HEX_1F_0E_0V, 
+      HP_HEX_1FA_1FB_0E_0V,
+      HP_PRISM_1FA_1FB_1EA_0V, 
+      HP_PRISM_1FB_1EA_0V, 
+      HP_PRISM_1FA_1FB_1EB_0V, 
+      HP_NONE,
+    };
+  int refprism_2fa_1fb_2eb_0v_newels[][8] =
+    {
+      { 18, 23, 22, 30, 35, 34},
+      { 24, 21, 22, 23, 36, 33, 34, 35}, 
+      { 31, 29, 17, 19, 36, 33, 21, 24}, 
+      { 3, 11, 10, 18, 23, 22}, 
+      { 12, 9, 10, 11, 24, 21, 22, 23},
+      { 7, 2, 9, 12, 19, 17, 21, 24},
+      { 6, 43, 44, 30, 34, 35},
+      { 44, 43, 42, 45, 35, 34, 33, 36}, 
+      { 5, 40, 45, 42, 29, 31, 36, 33 }, 
+      { 1, 7, 12, 16, 19, 24 }, 
+      { 16, 19, 24, 28, 31, 36 }, 
+      { 40, 4, 45, 31, 28, 36 }, 
+    };
+  HPRef_Struct refprism_2fa_1fb_2eb_0v =
+    {
+      HP_PRISM,
+      refprism_2fa_1fb_2eb_0v_splitedges, 
+      refprism_2fa_1fb_2eb_0v_splitfaces, 0,
+      refprism_2fa_1fb_2eb_0v_newelstypes, 
+      refprism_2fa_1fb_2eb_0v_newels
+    };
+
+//  HP_PRISM_1FB_2EA_0V   ... quad face 1-2-4-5 with singular edges 1-4, 2-5
+  int refprism_1fb_2ea_0v_splitedges[][3] =
+    {
+      { 1, 3, 7 },
+      { 2, 3, 8 },
+      { 1, 2, 9 }, 
+      { 2, 1, 10 }, 
+      { 4, 6, 11 }, 
+      { 5, 6, 12 }, 
+      { 4, 5, 13 }, 
+      { 5, 4, 14 }, 
+      { 0, 0, 0 }
+    };
+  HPREF_ELEMENT_TYPE refprism_1fb_2ea_0v_newelstypes[] =
+    {
+      HP_PRISM, 
+      HP_PRISM_1FB_1EA_0V,
+      HP_HEX_1F_0E_0V, 
+      HP_PRISM_1FB_1EA_0V, 
+      HP_NONE,
+    };
+  int refprism_1fb_2ea_0v_newels[][8] =
+    {
+      { 7, 8, 3, 11, 12, 6 }, 
+      { 1, 9, 7, 4, 13, 11 }, 
+      { 13, 14, 10, 9, 11, 12, 8, 7 }, 
+      { 5, 14, 12, 2, 10, 8 }, 
+    };
+  HPRef_Struct refprism_1fb_2ea_0v =
+    {
+      HP_PRISM,
+      refprism_1fb_2ea_0v_splitedges, 
+      0, 0,
+      refprism_1fb_2ea_0v_newelstypes, 
+      refprism_1fb_2ea_0v_newels
+    };
+
+//  HP_PRISM_1FB_2EB_0V   ... quad face 1-2-4-5 with singular edges 1-4, 3-6 
+  int refprism_1fb_2eb_0v_splitedges[][3] =
+    {
+      { 1, 2, 7},
+      { 2, 3, 9},
+      { 3, 2, 10},
+      { 3, 1, 11},
+      { 1, 3, 12},
+      { 4, 5, 40},
+      { 5, 6, 42},
+      { 6, 5, 43},
+      { 6, 4, 44},
+      { 4, 6, 45},
+      { 0, 0, 0 }
+    };
+HPREF_ELEMENT_TYPE refprism_1fb_2eb_0v_newelstypes[] =
+    {
+      HP_PRISM_SINGEDGE,
+      HP_HEX, 
+      HP_PRISM_1FB_1EA_0V, 
+      HP_HEX_1F_0E_0V, 
+      HP_NONE,
+    };
+  int refprism_1fb_2eb_0v_newels[][8] =
+    {
+      { 3, 11, 10, 6, 44, 43 },  
+      { 12, 9, 10, 11, 45, 42, 43, 44}, 
+      { 1, 7, 12, 4, 40, 45}, 
+      { 40, 5, 2, 7, 45, 42, 9, 12}
+    };
+  HPRef_Struct refprism_1fb_2eb_0v =
+    {
+      HP_PRISM,
+      refprism_1fb_2eb_0v_splitedges, 
+      0, 0,
+      refprism_1fb_2eb_0v_newelstypes, 
+      refprism_1fb_2eb_0v_newels
+    };
+
+//  HP_PRISM_1FB_3E_0V   ... quad face 1-2-4-5 with singular edges 1-4, 3-6
+  int refprism_1fb_3e_0v_splitedges[][3] =
+    {
+      { 1, 2, 7},
+      { 2, 1, 8},
+      { 2, 3, 9},
+      { 3, 2, 10},
+      { 3, 1, 11},
+      { 1, 3, 12},
+      { 4, 5, 40},
+      { 5, 4, 41},
+      { 5, 6, 42},
+      { 6, 5, 43},
+      { 6, 4, 44},
+      { 4, 6, 45},
+      { 0, 0, 0 }
+    };
+  HPREF_ELEMENT_TYPE refprism_1fb_3e_0v_newelstypes[] =
+    { 
+      HP_PRISM_SINGEDGE,
+      HP_HEX, 
+      HP_PRISM_1FB_1EA_0V, 
+      HP_HEX_1F_0E_0V, 
+      HP_PRISM_1FB_1EA_0V, 
+      HP_NONE,
+    };
+  int refprism_1fb_3e_0v_newels[][8] =
+    {
+      { 3, 11, 10, 6, 44, 43 }, 
+      { 12, 9, 10, 11, 45, 42, 43, 44}, 
+      { 1, 7, 12, 4, 40, 45 }, 
+      { 40, 41, 8, 7, 45, 42, 9, 12}, 
+      { 5, 41, 42, 2, 8, 9}, 
+    };
+  HPRef_Struct refprism_1fb_3e_0v =
+    {
+      HP_PRISM,
+      refprism_1fb_3e_0v_splitedges, 
+      0, 0,
+      refprism_1fb_3e_0v_newelstypes, 
+      refprism_1fb_3e_0v_newels
+    };
+
+
+
+//  HP_PRISM_2FB    ... quad face 1-2-4-5 and quad face 1-4-6-3
+  int refprism_2fb_0e_0v_splitedges[][3] =
+    {
+      { 1, 3, 7 },
+      { 2, 3, 8 },
+      { 1, 2, 9 }, 
+      { 3, 2, 10 }, 
+      { 4, 6, 11 },
+      { 5, 6, 12 },
+      { 4, 5, 13 },
+      { 6, 5, 14 },
+      { 0, 0, 0 }
+    };
+ int refprism_2fb_0e_0v_splitfaces[][4] =
+    {
+      { 1, 2, 3, 15 },
+      { 4, 5, 6, 16 },
+      { 0, 0, 0, 0 },
+    };
+  HPREF_ELEMENT_TYPE refprism_2fb_0e_0v_newelstypes[] =
+    {
+      HP_PRISM,
+      HP_HEX_1F_0E_0V, 
+      HP_HEX_1F_0E_0V, 
+      HP_PRISM_1FB_1EA_0V,
+      HP_PRISM_1FB_1EA_0V,
+      HP_NONE,
+    };
+  int refprism_2fb_0e_0v_newels[][8] =
+    {
+      { 15, 8, 10, 16, 12, 14 }, 
+      { 13, 5, 2, 9, 16, 12, 8, 15}, 
+      { 11, 7, 3, 6, 16, 15, 10, 14 }, 
+      { 1, 9, 15, 4, 13, 16 }, 
+      { 4, 11, 16, 1,7, 15 }
+    };
+  HPRef_Struct refprism_2fb_0e_0v =
+    {
+      HP_PRISM,
+      refprism_2fb_0e_0v_splitedges, 
+      refprism_2fb_0e_0v_splitfaces,
+      0,
+      refprism_2fb_0e_0v_newelstypes, 
+      refprism_2fb_0e_0v_newels
+    };
+
+//  HP_PRISM_2FB    ... quad face 1-2-4-5 and quad face 1-4-6-3 and sing edge 3-6
+  int refprism_2fb_1ec_0v_splitedges[][3] =
+    {
+      { 1, 3, 7 },
+      { 2, 3, 8 },
+      { 1, 2, 9 }, 
+      { 3, 2, 10 }, 
+      { 4, 6, 11 },
+      { 5, 6, 12 },
+      { 4, 5, 13 },
+      { 6, 5, 14 },
+      { 3, 1, 17},
+      { 6, 4, 18}, 
+      { 0, 0, 0 }
+    };
+ int refprism_2fb_1ec_0v_splitfaces[][4] =
+    {
+      { 1, 2, 3, 15 },
+      { 4, 5, 6, 16 },
+      { 0, 0, 0, 0 },
+    };
+  HPREF_ELEMENT_TYPE refprism_2fb_1ec_0v_newelstypes[] =
+    {
+      HP_PRISM,
+      HP_HEX_1F_0E_0V, 
+      HP_HEX_1F_0E_0V, 
+      HP_PRISM_1FB_1EA_0V,
+      HP_PRISM_1FB_1EA_0V,
+      HP_PRISM_1FB_1EA_0V,
+      HP_NONE,
+    };
+  int refprism_2fb_1ec_0v_newels[][8] =
+    {
+      { 15, 8, 10, 16, 12, 14 }, 
+      { 13, 5, 2, 9, 16, 12, 8, 15}, 
+      { 11, 7, 17, 18, 16, 15, 10, 14 }, 
+      { 1, 9, 15, 4, 13, 16 }, 
+      { 4, 11, 16, 1,7, 15 }, 
+      { 3, 17, 10, 6, 18, 14 } 
+    };
+  HPRef_Struct refprism_2fb_1ec_0v =
+    {
+      HP_PRISM,
+      refprism_2fb_1ec_0v_splitedges, 
+      refprism_2fb_1ec_0v_splitfaces,
+      0,
+      refprism_2fb_1ec_0v_newelstypes, 
+      refprism_2fb_1ec_0v_newels
+    };
+
+
+
+//  HP_PRISM_2FB    ... quad face 1-2-4-5 and quad face 1-4-6-3 and 3 sing edges
+  int refprism_2fb_3e_0v_splitedges[][3] =
+    {
+      { 1, 3, 7 },
+      { 2, 3, 8 },
+      { 1, 2, 9 }, 
+      { 3, 2, 10 }, 
+      { 4, 6, 11 },
+      { 5, 6, 12 },
+      { 4, 5, 13 },
+      { 6, 5, 14 },
+      { 3, 1, 17},
+      { 6, 4, 18}, 
+      { 2, 1, 19},
+      { 5, 4, 20}, 
+      { 0, 0, 0 }
+    };
+ int refprism_2fb_3e_0v_splitfaces[][4] =
+    {
+      { 1, 2, 3, 15 },
+      { 4, 5, 6, 16 },
+      { 0, 0, 0, 0 },
+    };
+  HPREF_ELEMENT_TYPE refprism_2fb_3e_0v_newelstypes[] =
+    {
+      HP_PRISM,
+      HP_HEX_1F_0E_0V, 
+      HP_HEX_1F_0E_0V, 
+      HP_PRISM_1FB_1EA_0V,
+      HP_PRISM_1FB_1EA_0V,
+      HP_PRISM_1FB_1EA_0V,
+      HP_PRISM_1FB_1EA_0V,
+      HP_NONE,
+    };
+  int refprism_2fb_3e_0v_newels[][8] =
+    {
+      { 15, 8, 10, 16, 12, 14 }, 
+      { 13, 20, 19, 9, 16, 12, 8, 15}, 
+      { 11, 7, 17, 18, 16, 15, 10, 14 }, 
+      { 1, 9, 15, 4, 13, 16 }, 
+      { 4, 11, 16, 1,7, 15 }, 
+      { 3, 17, 10, 6, 18, 14 }, 
+      { 5, 20, 12, 2, 19, 8 }
+    };
+  HPRef_Struct refprism_2fb_3e_0v =
+    {
+      HP_PRISM,
+      refprism_2fb_3e_0v_splitedges, 
+      refprism_2fb_3e_0v_splitfaces, 0,
+      refprism_2fb_3e_0v_newelstypes, 
+      refprism_2fb_3e_0v_newels
+    };
+
+
+
+//  HP_PRISM_1FA_1FB_0E_0V   ... quad face 1-2-4-5 and trig face 1-2-3
+  int refprism_1fa_1fb_0e_0v_splitedges[][3] = 
+    {
+      {1,4,16}, 
+      {2,5,17},
+      {3,6,18},
+      {2,3,9},
+      {1,3,12},
+      {5,6,42},
+      {4,6,45},
+      {0,0,0}
+    };
+  int refprism_1fa_1fb_0e_0v_splitfaces[][4] = 
+    {
+      {2,3,5,21},
+      {1,3,4,24},
+      { 0, 0, 0, 0 }
+    };
+
+HPREF_ELEMENT_TYPE refprism_1fa_1fb_0e_0v_newelstypes[] =
+    {
+      HP_PRISM, 
+      HP_HEX_1F_0E_0V,
+      HP_PRISM_1FA_0E_0V, 
+      HP_HEX_1FA_1FB_0E_0V,
+      HP_NONE,
+    };
+  int refprism_1fa_1fb_0e_0v_newels[][8] =
+    {
+      { 24, 21, 18, 45, 42, 6 }, 
+      { 4, 5, 17, 16, 45, 42, 21, 24 },
+      { 12, 9, 3, 24, 21, 18 }, 
+      { 1, 2, 9, 12, 16, 17, 21, 24 } 
+    };
+  HPRef_Struct refprism_1fa_1fb_0e_0v =
+    {
+      HP_PRISM,
+      refprism_1fa_1fb_0e_0v_splitedges, 
+
+      refprism_1fa_1fb_0e_0v_splitfaces, 0,
+      refprism_1fa_1fb_0e_0v_newelstypes, 
+      refprism_1fa_1fb_0e_0v_newels
+    };
+
+/*
+//  HP_PRISM_1FA_1FB_1EC_0V   ... quad face 1-2-4-5 and trig face 1-2-3
+int refprism_1fa_1fb_1ec_0v_splitedges[][3] =
+    {
+      {1,4,16}, 
+      {2,5,17},
+      {3,6,18},
+      {2,3,9},
+      {1,3,12},
+      {5,6,42},
+      {4,6,45},
+      {6,5,43},
+      {6,4,44},
+      {3,2,10},
+      {3,1,11},
+      {0,0,0}
+    };
+  int refprism_1fa_1fb_1ec_0v_splitfaces[][4] = 
+    {
+      {2,3,5,21},
+      {1,3,4,24},
+      { 0, 0, 0, 0 }
+    };
+
+  HPREF_ELEMENT_TYPE refprism_1fa_1fb_1ec_0v_newelstypes[] =
+    {
+      HP_PRISM, 
+      HP_HEX_1F_0E_0V,
+      HP_PRISM_1FA_0E_0V, 
+      HP_HEX_1FA_1FB_0E_0V,
+      HP_PRISM_SINGEDGE,
+      HP_PRISM_1FA_1E_0V, 
+      HP_PRISM_
+      HP_NONE,
+    };
+  int refprism_1fa_1fb_0e_0v_newels[][8] =
+    {
+      { 24, 21, 18, 45, 42, 6 }, 
+      { 4, 5, 17, 16, 45, 42, 21, 24 },
+      { 12, 9, 3, 24, 21, 18 }, 
+      { 1, 2, 9, 12, 16, 17, 21, 24 } 
+    };
+  HPRef_Struct refprism_1fa_1fb_0e_0v =
+    {
+      HP_PRISM,
+      refprism_1fa_1fb_1ec_0v_splitedges, 
+
+      refprism_1fa_1fb_1ec_0v_splitfaces, 0,
+      refprism_1fa_1fb_1ec_0v_newelstypes, 
+      refprism_1fa_1fb_1ec_0v_newels
+    };
+
+
+*/
+
+
+
+
+//  HP_PRISM_2FA_1FB_0E_0V   ... quad face 1-2-4-5 and trig face 1-2-3 
+  int refprism_2fa_1fb_0e_0v_splitedges[][3] =
+    {
+      {2,3,9},
+      {1,3,12},
+      {1,4,16}, 
+      {2,5,17},
+      {3,6,18},
+      {5,6,42},
+      {4,6,45},
+      {4,1,28},
+      {5,2,29},
+      {6,3,30},
+      {0,0,0}
+      
+    };
+  int refprism_2fa_1fb_0e_0v_splitfaces[][4] = 
+    {
+      {2,3,5,21},
+      {1,3,4,24},
+      {5,6,2,33},
+      {4,1,6,36},
+      {0,0,0,0}
+    };
+
+  HPREF_ELEMENT_TYPE refprism_2fa_1fb_0e_0v_newelstypes[] =
+    {  
+      HP_HEX_1F_0E_0V,
+      HP_PRISM,
+      HP_PRISM_1FA_0E_0V, 
+      HP_HEX_1FA_1FB_0E_0V, 
+      HP_PRISM_1FA_0E_0V, 
+      HP_HEX_1FA_1FB_0E_0V,
+      HP_NONE,
+    };
+  int refprism_2fa_1fb_0e_0v_newels[][8] =
+    {
+      {28,29,17,16,36,33,21,24}, 
+      {24,21,18, 36, 33, 30}, 
+      {12,9,3,24,21,18},
+      {1,2,9,12,16,17,21,24}, 
+      {6,42,45,30,33,36},
+      {4,5,29,28,45,42,33,36}
+    };
+  HPRef_Struct refprism_2fa_1fb_0e_0v =
+    {
+      HP_PRISM,
+      refprism_2fa_1fb_0e_0v_splitedges, 
+
+      refprism_2fa_1fb_0e_0v_splitfaces, 0,
+      refprism_2fa_1fb_0e_0v_newelstypes, 
+      refprism_2fa_1fb_0e_0v_newels
+    };
+
+
+//  HP_PRISM_1FA_1FB_1EA_0V   ... quad face 1-2-4-5 and trig face 1-2-3 
+  int refprism_1fa_1fb_1ea_0v_splitedges[][3] =
+    {
+      {2,3,9},
+      {1,3,12},
+      {1,4,16}, 
+      {2,5,17},
+      {3,6,18},
+      {5,6,42},
+      {4,6,45},
+      {4,5,40},
+      {1,2,7},
+      {0,0,0}, 
+    };
+  int refprism_1fa_1fb_1ea_0v_splitfaces[][4] = 
+    {
+      {2,3,5,21},
+      {1,3,4,24},
+      {1,2,4,19},
+      {0,0,0,0}, 
+    };
+
+  HPREF_ELEMENT_TYPE refprism_1fa_1fb_1ea_0v_newelstypes[] =
+    {
+      HP_HEX_1F_0E_0V,
+      HP_PRISM,
+      HP_PRISM_1FA_0E_0V, 
+      HP_HEX_1FA_1FB_0E_0V, 
+      HP_PRISM_1FB_1EA_0V,
+      HP_PRISM_1FA_1FB_1EA_0V,
+      HP_NONE
+    };
+  int refprism_1fa_1fb_1ea_0v_newels[][8] =
+    {
+      {40,5,17,19,45,42,21,24}, 
+      {24,21,18,45,42,6},
+      {12,9,3,24,21,18},
+      {7,2,9,12,19,17,21,24}, 
+      {16,19,24,4,40,45},
+      {1,7,12,16,19,24}
+      
+    };
+  HPRef_Struct refprism_1fa_1fb_1ea_0v =
+    {
+      HP_PRISM,
+      refprism_1fa_1fb_1ea_0v_splitedges, 
+      refprism_1fa_1fb_1ea_0v_splitfaces, 0,
+      refprism_1fa_1fb_1ea_0v_newelstypes, 
+      refprism_1fa_1fb_1ea_0v_newels
+    };
+
+//  HP_PRISM_2FA_1FB_1EA_0V   
+  int refprism_2fa_1fb_1ea_0v_splitedges[][3] =
+    {
+      {2,3,9},
+      {1,3,12},
+      {1,4,16}, 
+      {2,5,17},
+      {3,6,18},
+      {5,6,42},
+      {4,6,45},
+      {4,1,28},
+      {5,2,29},
+      {6,3,30},
+      {4,5,40},
+      {1,2,7},
+      {0,0,0}, 
+    };
+  int refprism_2fa_1fb_1ea_0v_splitfaces[][4] = 
+    {
+      {2,3,5,21},
+      {1,3,4,24},
+      {1,2,4,19},
+      {4,1,6,36},
+      {4,1,5,31},
+      {5,6,2,33},
+      {0,0,0,0}, 
+    };
+
+  HPREF_ELEMENT_TYPE refprism_2fa_1fb_1ea_0v_newelstypes[] =
+    {
+      HP_PRISM, 
+      HP_HEX_1F_0E_0V, 
+      HP_PRISM_1FB_1EA_0V, 
+      HP_PRISM_1FA_0E_0V, 
+      HP_HEX_1FA_1FB_0E_0V, 
+      HP_PRISM_1FA_1FB_1EA_0V, 
+      HP_PRISM_1FA_0E_0V, 
+      HP_HEX_1FA_1FB_0E_0V, 
+      HP_PRISM_1FA_1FB_1EB_0V, 
+      HP_NONE
+    };
+  int refprism_2fa_1fb_1ea_0v_newels[][8] =
+    {
+      { 18, 24, 21, 30, 36, 33}, 
+      { 31, 29, 17, 19, 36, 33, 21, 24}, 
+      { 16,19, 24, 28, 31, 36 }, 
+      { 3, 12, 9, 18, 24, 21 }, 
+      { 7, 2, 9, 12, 19, 17, 21, 24},  
+      { 1, 7, 12, 16, 19, 24 }, 
+      { 6, 42, 45, 30, 33, 36 }, 
+      { 40, 5, 29, 31, 45, 42, 33, 36 },
+      { 40, 4, 45, 31, 28, 36} 
+    };
+  HPRef_Struct refprism_2fa_1fb_1ea_0v =
+    {
+      HP_PRISM,
+      refprism_2fa_1fb_1ea_0v_splitedges, 
+      refprism_2fa_1fb_1ea_0v_splitfaces, 0,
+      refprism_2fa_1fb_1ea_0v_newelstypes, 
+      refprism_2fa_1fb_1ea_0v_newels
+    };
+
+
+//  HP_PRISM_2FA_1FB_2EA_0V   
+  int refprism_2fa_1fb_2ea_0v_splitedges[][3] =
+    {
+      {2,3,9},
+      {1,3,12},
+      {1,4,16}, 
+      {2,5,17},
+      {3,6,18},
+      {5,6,42},
+      {4,6,45},
+      {4,1,28},
+      {5,2,29},
+      {6,3,30},
+      {4,5,40},
+      {1,2,7},
+      { 5, 4, 41},
+      { 2, 1, 8},
+      {0,0,0}, 
+    };
+  int refprism_2fa_1fb_2ea_0v_splitfaces[][4] = 
+    {
+      {2,3,5,21},
+      {1,3,4,24},
+      {1,2,4,19},
+      {4,1,6,36},
+      {4,1,5,31},
+      {5,6,2,33},
+      {5,4,2,32},
+      {2,1,5,20},
+      {0,0,0,0}, 
+    };
+
+  HPREF_ELEMENT_TYPE refprism_2fa_1fb_2ea_0v_newelstypes[] =
+    {
+      HP_PRISM, 
+      HP_HEX_1F_0E_0V, 
+      HP_PRISM_1FB_1EA_0V, 
+      HP_PRISM_1FA_0E_0V, 
+      HP_HEX_1FA_1FB_0E_0V, 
+      HP_PRISM_1FA_1FB_1EA_0V, 
+      HP_PRISM_1FA_0E_0V, 
+      HP_HEX_1FA_1FB_0E_0V, 
+      HP_PRISM_1FA_1FB_1EB_0V, 
+      HP_PRISM_1FA_1FB_1EB_0V, 
+      HP_PRISM_1FB_1EA_0V,
+      HP_PRISM_1FA_1FB_1EA_0V, 
+      HP_NONE
+    };
+  int refprism_2fa_1fb_2ea_0v_newels[][8] =
+    {
+      { 18, 24, 21, 30, 36, 33}, 
+      { 31, 32, 20, 19, 36, 33, 21, 24}, 
+      { 16,19, 24, 28, 31, 36 }, 
+      { 3, 12, 9, 18, 24, 21 }, 
+      {7,8,9,12,19,20,21,24},
+      { 1, 7, 12, 16, 19, 24 }, 
+      { 6, 42, 45, 30, 33, 36 }, 
+      { 40, 41, 32, 31, 45, 42, 33, 36}, 
+      { 40, 4, 45, 31, 28, 36}, 
+      { 8, 2, 9, 20, 17, 21 },  
+      { 29, 32, 33, 17, 20, 21 }, 
+      { 5, 41, 42, 29, 32, 33 }, 
+    };
+  HPRef_Struct refprism_2fa_1fb_2ea_0v =
+    {
+      HP_PRISM,
+      refprism_2fa_1fb_2ea_0v_splitedges, 
+      refprism_2fa_1fb_2ea_0v_splitfaces, 0,
+      refprism_2fa_1fb_2ea_0v_newelstypes, 
+      refprism_2fa_1fb_2ea_0v_newels
+    };
+
+//  HP_PRISM_2FA_1FB_3E_0V   
+  int refprism_2fa_1fb_3e_0v_splitedges[][3] =
+    {
+      { 1, 2, 7},
+      { 2, 1, 8},
+      { 2, 3, 9},
+      { 3, 2, 10},
+      { 3, 1, 11},
+      { 1, 3, 12},
+      { 1, 4, 16}, 
+      { 2, 5, 17},
+      { 3, 6, 18},
+      { 4, 1, 28},
+      { 5, 2, 29},
+      { 6, 3, 30},
+      { 4, 5, 40},
+      { 5, 4, 41},
+      { 5, 6, 42},
+      { 6, 5, 43},
+      { 6, 4, 44},
+      { 4, 6, 45},
+      {0,0,0}, 
+    };
+  int refprism_2fa_1fb_3e_0v_splitfaces[][4] = 
+    {
+      {1,2,4,19},
+      {2,1,5,20},
+      {2,3,5,21},
+      {3,2,6,22},
+      {3,1,6,23},
+      {1,3,4,24},
+      {4,1,5,31},
+      {5,4,2,32},
+      {5,6,2,33},
+      {6,5,3,34},
+      {6,4,3,35},
+      {4,1,6,36},
+      {0,0,0,0}, 
+    };
+
+  HPREF_ELEMENT_TYPE refprism_2fa_1fb_3e_0v_newelstypes[] =
+    {
+      HP_HEX,
+      HP_PRISM_SINGEDGE,
+      HP_HEX_1F_0E_0V, 
+      HP_PRISM_1FB_1EA_0V, 
+      HP_PRISM_1FB_1EA_0V, 
+
+      HP_HEX_1F_0E_0V,
+      HP_PRISM_1FA_1E_0V,
+      HP_PRISM_1FA_1FB_1EA_0V, 
+      HP_PRISM_1FA_1FB_1EB_0V, 
+      HP_HEX_1FA_1FB_0E_0V,
+      
+      HP_HEX_1F_0E_0V,
+      HP_PRISM_1FA_1E_0V,
+      HP_PRISM_1FA_1FB_1EB_0V,
+      HP_PRISM_1FA_1FB_1EA_0V,
+      HP_HEX_1FA_1FB_0E_0V,
+      
+      HP_NONE
+    };
+  int refprism_2fa_1fb_3e_0v_newels[][8] =
+    {
+      {24, 21, 22, 23, 36, 33, 34, 35},
+      {18, 23, 22, 30, 35, 34}, 
+      { 31, 32, 20, 19, 36, 33, 21, 24}, 
+      { 16,19, 24, 28, 31, 36 }, 
+      { 29, 32, 33, 17, 20, 21},
+      
+      
+      { 12, 9,10,11, 24, 21, 22, 23 }, 
+      { 3, 11, 10, 18,23,22}, 
+      { 1, 7, 12 , 16, 19, 24}, 
+      { 8,2,9, 20, 17,21}, 
+      { 7,8,9,12,19, 20, 21, 24}, 
+      
+      { 44, 43, 42, 45, 35, 34, 33, 36}, 
+      { 6, 43, 44, 30, 34, 35}, 
+      { 40, 4, 45, 31,28, 36}, 
+      { 5, 41,42, 29, 32, 33},  
+      { 40, 41, 32, 31, 45, 42, 33, 36}, 
+    };
+  HPRef_Struct refprism_2fa_1fb_3e_0v =
+    {
+      HP_PRISM,
+      refprism_2fa_1fb_3e_0v_splitedges, 
+
+      refprism_2fa_1fb_3e_0v_splitfaces, 0,
+      refprism_2fa_1fb_3e_0v_newelstypes, 
+      refprism_2fa_1fb_3e_0v_newels
+    };
+
+
+
+
+//  HP_PRISM_1FA_1FB_1EB_0V   ... quad face 1-2-4-5 and trig face 1-2-3 
+  int refprism_1fa_1fb_1eb_0v_splitedges[][3] =
+    {
+      {2,3,9},
+      {1,3,12},
+      {1,4,16}, 
+      {2,5,17},
+      {3,6,18},
+      {5,6,42},
+      {4,6,45},
+      {5,4,41},
+      {2,1,8},
+      {0,0,0}, 
+    };
+  int refprism_1fa_1fb_1eb_0v_splitfaces[][4] = 
+    {
+      {2,3,5,21},
+      {1,3,4,24},
+      {2,1,5,20},
+      {0,0,0,0}, 
+    };
+
+  HPREF_ELEMENT_TYPE refprism_1fa_1fb_1eb_0v_newelstypes[] =
+    {
+      HP_HEX_1F_0E_0V,
+      HP_PRISM,
+      HP_PRISM_1FA_0E_0V, 
+      HP_HEX_1FA_1FB_0E_0V,
+      HP_PRISM_1FB_1EA_0V,
+      HP_PRISM_1FA_1FB_1EB_0V ,
+      HP_NONE
+    };
+  int refprism_1fa_1fb_1eb_0v_newels[][8] =
+    {
+      {4,41,20,16,45,42,21,24}, 
+      {24,21,18,45,42,6},
+      {12,9,3,24,21,18},
+      {1,8,9,12,16,20,21,24},
+      {5,41,42,17,20,21},
+      {8,2,9,20,17,21}
+    };
+  HPRef_Struct refprism_1fa_1fb_1eb_0v =
+    {
+      HP_PRISM,
+      refprism_1fa_1fb_1eb_0v_splitedges, 
+
+       refprism_1fa_1fb_1eb_0v_splitfaces, 0,
+      refprism_1fa_1fb_1eb_0v_newelstypes, 
+      refprism_1fa_1fb_1eb_0v_newels
+    };
+
+
+//  HP_PRISM_1FA_1FB_2EA_0V   ... quad face 1-2-4-5 and trig face 1-2-3 
+  int refprism_1fa_1fb_2ea_0v_splitedges[][3] =
+    {
+      {2,3,9},
+      {1,3,12},
+      {1,4,16}, 
+      {2,5,17},
+      {3,6,18},
+      {5,6,42},
+      {4,6,45},
+      {5,4,41},
+      {2,1,8},
+      {4,5,40},
+      {1,2,7},
+      {0,0,0},
+
+    };
+  int refprism_1fa_1fb_2ea_0v_splitfaces[][4] = 
+    {
+      {2,3,5,21},
+      {1,3,4,24},
+      {2,1,5,20},
+      {1,2,4,19},
+      {0,0,0,0},
+    };
+
+  HPREF_ELEMENT_TYPE refprism_1fa_1fb_2ea_0v_newelstypes[] =
+    {
+      HP_HEX_1F_0E_0V,
+      HP_PRISM,
+      HP_PRISM_1FA_0E_0V, 
+      HP_HEX_1FA_1FB_0E_0V,
+      HP_PRISM_1FB_1EA_0V,
+      HP_PRISM_1FA_1FB_1EB_0V ,
+      HP_PRISM_1FB_1EA_0V,
+      HP_PRISM_1FA_1FB_1EA_0V,
+      HP_NONE
+    };
+  int refprism_1fa_1fb_2ea_0v_newels[][8] =
+    {
+      {40,41,20,19,45,42,21,24}, 
+      {24,21,18,45,42,6},
+      {12,9,3,24,21,18},
+      {7,8,9,12,19,20,21,24},
+      {5,41,42,17,20,21},
+      {8,2,9,20,17,21},
+      {16,19,24,4,40,45},
+      {1,7,12,16,19,24}
+    };
+  HPRef_Struct refprism_1fa_1fb_2ea_0v =
+    {
+      HP_PRISM,
+      refprism_1fa_1fb_2ea_0v_splitedges, 
+
+      refprism_1fa_1fb_2ea_0v_splitfaces, 0,
+      refprism_1fa_1fb_2ea_0v_newelstypes, 
+      refprism_1fa_1fb_2ea_0v_newels
+    };
+
+
+//  HP_PRISM_1FA_1FB_3E_0V   
+  int refprism_1fa_1fb_3e_0v_splitedges[][3] =
+    {
+      {2,3,9},
+      {1,3,12},
+      {1,4,16}, 
+      {2,5,17},
+      {3,6,18},
+      {5,6,42},
+      {4,6,45},
+      {5,4,41},
+      {2,1,8},
+      {4,5,40},
+      {1,2,7},
+      { 3, 2, 10},
+      { 3, 1, 11},
+      { 6, 5, 43},
+      { 6, 4, 44},
+      {0,0,0},
+
+    };
+  int refprism_1fa_1fb_3e_0v_splitfaces[][4] = 
+    {
+      {2,3,5,21},
+      {1,3,4,24},
+      {2,1,5,20},
+      {1,2,4,19},
+      {3,2,6,22},
+      {3,1,6,23},
+      {0,0,0,0},
+    };
+
+  HPREF_ELEMENT_TYPE refprism_1fa_1fb_3e_0v_newelstypes[] =
+    {
+      HP_HEX_1F_0E_0V,
+      HP_HEX,
+      HP_PRISM_SINGEDGE,
+      HP_HEX_1F_0E_0V,
+      HP_PRISM_1FA_1E_0V,
+      HP_HEX_1FA_1FB_0E_0V,
+      HP_PRISM_1FB_1EA_0V,
+      HP_PRISM_1FA_1FB_1EB_0V ,
+      HP_PRISM_1FB_1EA_0V,
+      HP_PRISM_1FA_1FB_1EA_0V,
+      HP_NONE
+    };
+  int refprism_1fa_1fb_3e_0v_newels[][8] =
+    {
+      {40,41,20,19,45,42,21,24}, 
+      {24, 21, 22, 23, 45, 42, 43, 44},
+      {18, 23, 22, 6, 44, 43}, 
+      {12, 9, 10, 11, 24, 21, 22, 23}, 
+      {3, 11, 10, 18, 23, 22}, 
+      {7,8,9,12,19,20,21,24},
+      {5,41,42,17,20,21},
+      {8,2,9,20,17,21},
+      {16,19,24,4,40,45},
+      {1,7,12,16,19,24}
+    };
+  HPRef_Struct refprism_1fa_1fb_3e_0v =
+    {
+      HP_PRISM,
+      refprism_1fa_1fb_3e_0v_splitedges, 
+
+      refprism_1fa_1fb_3e_0v_splitfaces, 0,
+      refprism_1fa_1fb_3e_0v_newelstypes, 
+      refprism_1fa_1fb_3e_0v_newels
+    };
+
+
+
+
+
+
+
+
+//  HP_PRISM_2FA_0E_0V  singular trig faces
+  int refprism_2fa_0e_0v_splitedges[][3] =
+    {
+      {1,4,16}, 
+      {2,5,17},
+      {3,6,18},
+      {4,1,28},
+      {5,2,29},
+      {6,3,30},
+      {0,0,0}
+    };
+  
+HPREF_ELEMENT_TYPE refprism_2fa_0e_0v_newelstypes[] =
+    {
+      HP_PRISM,
+      HP_PRISM_1FA_0E_0V,
+      HP_PRISM_1FA_0E_0V,
+      HP_NONE
+    };
+  int refprism_2fa_0e_0v_newels[][8] =
+    {
+      {16,17,18,28,29,30},
+      {1,2,3,16,17,18},
+      {4,6,5,28,30,29}, 
+    };
+
+HPRef_Struct refprism_2fa_0e_0v = 
+
+    {
+      HP_PRISM,
+      refprism_2fa_0e_0v_splitedges, 
+      0, 0,
+      refprism_2fa_0e_0v_newelstypes, 
+      refprism_2fa_0e_0v_newels
+    };
+
+
+
+
+
+//  HP_PRISM_1FA_2FB    ... quad face 1-2-4-5 and quad face 1-4-6-3
+int refprism_1fa_2fb_0e_0v_splitedges[][3] =
+    {
+      { 1, 2, 7},
+      { 2, 3, 9},
+      { 3, 2, 10},
+      { 1, 3, 12},
+      { 1, 4, 16}, 
+      { 2, 5, 17},
+      { 3, 6, 18},
+      { 4, 5, 40},
+      { 5, 6, 42},
+      { 6, 5, 43},
+      { 4, 6, 45},
+      { 0, 0, 0 }
+    };
+int refprism_1fa_2fb_0e_0v_splitfaces[][4] =
+    {
+      {1,2,3,13},
+      {1,2,4,19},
+      {2,3,5,21},
+      {3,2,6,22},
+      {1,3,4,24},
+      {4,5,6,46},
+      { 0, 0, 0, 0 }
+    };
+int refprism_1fa_2fb_0e_0v_splitelement[][5] = 
+  {
+    {1,2,3,4,25}, 
+    {0,0,0,0,0} 
+  };
+  
+HPREF_ELEMENT_TYPE refprism_1fa_2fb_0e_0v_newelstypes[] =
+    {
+      HP_PRISM,
+      HP_HEX_1F_0E_0V, 
+      HP_HEX_1F_0E_0V, 
+      HP_PRISM_1FB_1EA_0V,
+      HP_PRISM_1FB_1EA_0V,
+      HP_PRISM_1FA_0E_0V, 
+      HP_HEX_1FA_1FB_0E_0V,
+      HP_HEX_1FA_1FB_0E_0V, 
+      HP_PRISM_1FA_1FB_1EA_0V,
+      HP_PRISM_1FA_1FB_1EB_0V,
+      HP_NONE,
+    };
+  int refprism_1fa_2fb_0e_0v_newels[][8] =
+    {
+      { 25, 21, 22, 46, 42, 43 }, 
+      { 40, 5, 17, 19, 46, 42, 21, 25 }, 
+      { 24, 18, 6, 45, 25, 22, 43, 46}, 
+      { 16, 19, 25, 4, 40, 46 }, 
+      { 4, 45, 46, 16, 24, 25 }, 
+      { 13, 9, 10, 25, 21, 22 }, 
+      { 7, 2, 9, 13, 19, 17, 21, 25 }, 
+      { 3, 12, 13, 10, 18, 24, 25, 22 }, 
+      { 1, 7, 13, 16, 19, 25 }, 
+      { 12, 1, 13, 24, 16, 25 }
+      
+    };
+  HPRef_Struct refprism_1fa_2fb_0e_0v =
+    {
+      HP_PRISM,
+      refprism_1fa_2fb_0e_0v_splitedges, 
+      refprism_1fa_2fb_0e_0v_splitfaces, 
+      refprism_1fa_2fb_0e_0v_splitelement, 
+      refprism_1fa_2fb_0e_0v_newelstypes, 
+      refprism_1fa_2fb_0e_0v_newels
+    };
+
+//  HP_PRISM_1FA_2FB_1EC    ... quad face 1-2-4-5 and quad face 1-4-6-3
+int refprism_1fa_2fb_1ec_0v_splitedges[][3] =
+    {
+      { 1, 2, 7},
+      { 2, 3, 9},
+      { 3, 2, 10},
+      { 3, 1, 11},
+      { 1, 3, 12},
+      { 1, 4, 16}, 
+      { 2, 5, 17},
+      { 3, 6, 18},
+      { 4, 5, 40},
+      { 5, 6, 42},
+      { 6, 5, 43},
+      { 6, 4, 44},
+      { 4, 6, 45},
+      { 0, 0, 0 }
+    };
+int refprism_1fa_2fb_1ec_0v_splitfaces[][4] =
+    {
+      {1,2,3,13},
+      {1,2,4,19},
+      {2,3,5,21},
+      {3,2,6,22},
+      {3,1,6,23},
+      {1,3,4,24},
+      {4,5,6,46},
+      { 0, 0, 0, 0 }
+    };
+int refprism_1fa_2fb_1ec_0v_splitelement[][5] = 
+  {
+    {1,2,3,4,25}, 
+    {0,0,0,0,0} 
+  };
+  
+HPREF_ELEMENT_TYPE refprism_1fa_2fb_1ec_0v_newelstypes[] =
+    {
+      HP_PRISM,
+      HP_HEX_1F_0E_0V, 
+      HP_HEX_1F_0E_0V, 
+      HP_PRISM_1FB_1EA_0V,
+      HP_PRISM_1FB_1EA_0V,
+      HP_PRISM_1FB_1EA_0V, 
+      
+      HP_PRISM_1FA_0E_0V, 
+      HP_HEX_1FA_1FB_0E_0V,
+      HP_HEX_1FA_1FB_0E_0V, 
+      HP_PRISM_1FA_1FB_1EA_0V,
+      HP_PRISM_1FA_1FB_1EB_0V,
+      HP_PRISM_1FA_1FB_1EA_0V, 
+      
+      HP_NONE,
+    };
+  int refprism_1fa_2fb_1ec_0v_newels[][8] =
+    {
+      { 25, 21, 22, 46, 42, 43 }, 
+      { 40, 5, 17, 19, 46, 42, 21, 25 }, 
+      { 24, 23, 44, 45, 25, 22, 43, 46}, 
+      { 16, 19, 25, 4, 40, 46 }, 
+      { 4, 45, 46, 16, 24, 25 }, 
+      { 18, 23, 22, 6, 44, 43}, 
+
+
+      { 13, 9, 10, 25, 21, 22 }, 
+      { 7, 2, 9, 13, 19, 17, 21, 25 }, 
+      { 11, 12, 13, 10, 23, 24, 25, 22 }, 
+      { 1, 7, 13, 16, 19, 25 }, 
+      { 12, 1, 13, 24, 16, 25 }, 
+      { 3, 11, 10, 18, 23, 22},
+      
+    };
+  HPRef_Struct refprism_1fa_2fb_1ec_0v =
+    {
+      HP_PRISM,
+      refprism_1fa_2fb_1ec_0v_splitedges, 
+      refprism_1fa_2fb_1ec_0v_splitfaces, 
+      refprism_1fa_2fb_1ec_0v_splitelement, 
+      refprism_1fa_2fb_1ec_0v_newelstypes, 
+      refprism_1fa_2fb_1ec_0v_newels
+    };
+
+
+//  HP_PRISM_1FA_2FB_3E    ... quad face 1-2-4-5 and quad face 1-4-6-3
+int refprism_1fa_2fb_3e_0v_splitedges[][3] =
+    {
+      { 1, 2, 7},
+      { 2, 1, 8},
+      { 2, 3, 9},
+      { 3, 2, 10},
+      { 3, 1, 11},
+      { 1, 3, 12},
+      { 1, 4, 16}, 
+      { 2, 5, 17},
+      { 3, 6, 18},
+      { 4, 5, 40},
+      { 5, 4, 41},
+      { 5, 6, 42},
+      { 6, 5, 43},
+      { 6, 4, 44},
+      { 4, 6, 45},
+      { 0, 0, 0 }
+    };
+int refprism_1fa_2fb_3e_0v_splitfaces[][4] =
+    {
+      {1,2,3,13},
+      {1,2,4,19},
+      {2,1,5,20},
+      {2,3,5,21},
+      {3,2,6,22},
+      {3,1,6,23},
+      {1,3,4,24},
+      {4,5,6,46},
+      { 0, 0, 0, 0 }
+    };
+int refprism_1fa_2fb_3e_0v_splitelement[][5] = 
+  {
+    {1,2,3,4,25}, 
+    {0,0,0,0,0} 
+  };
+  
+HPREF_ELEMENT_TYPE refprism_1fa_2fb_3e_0v_newelstypes[] =
+    {
+      HP_PRISM,
+      HP_HEX_1F_0E_0V, 
+      HP_HEX_1F_0E_0V, 
+      HP_PRISM_1FB_1EA_0V,
+      HP_PRISM_1FB_1EA_0V,
+      HP_PRISM_1FB_1EA_0V, 
+      HP_PRISM_1FB_1EA_0V,
+      
+      
+      HP_PRISM_1FA_0E_0V, 
+      HP_HEX_1FA_1FB_0E_0V,
+      HP_HEX_1FA_1FB_0E_0V, 
+      HP_PRISM_1FA_1FB_1EA_0V,
+      HP_PRISM_1FA_1FB_1EB_0V,
+      HP_PRISM_1FA_1FB_1EA_0V, 
+      HP_PRISM_1FA_1FB_1EB_0V,
+      
+      HP_NONE,
+    };
+  int refprism_1fa_2fb_3e_0v_newels[][8] =
+    {
+      { 25, 21, 22, 46, 42, 43 }, 
+      { 40, 41, 20, 19, 46, 42, 21, 25 }, 
+      { 24, 23, 44, 45, 25, 22, 43, 46}, 
+      { 16, 19, 25, 4, 40, 46 }, 
+      { 4, 45, 46, 16, 24, 25 }, 
+      { 18, 23, 22, 6, 44, 43}, 
+      { 5, 41, 42, 17, 20, 21}, 
+      
+
+      { 13, 9, 10, 25, 21, 22 }, 
+      { 7, 8, 9, 13, 19, 20, 21, 25 }, 
+      { 11, 12, 13, 10, 23, 24, 25, 22 }, 
+      { 1, 7, 13, 16, 19, 25 }, 
+      
+      { 12, 1, 13, 24, 16, 25 }, 
+      { 3, 11, 10, 18, 23, 22},
+      { 8, 2, 9, 20, 17, 21}, 
+      
+    };
+  HPRef_Struct refprism_1fa_2fb_3e_0v =
+    {
+      HP_PRISM,
+      refprism_1fa_2fb_3e_0v_splitedges, 
+      refprism_1fa_2fb_3e_0v_splitfaces, 
+      refprism_1fa_2fb_3e_0v_splitelement, 
+      refprism_1fa_2fb_3e_0v_newelstypes, 
+      refprism_1fa_2fb_3e_0v_newels
+    };
+
+
+
+
+
+
+
+
+
+//  HP_PRISM_1FA_2FB_1eb    ... quad face 1-2-4-5 and quad face 1-4-6-3
+int refprism_1fa_2fb_1eb_0v_splitedges[][3] =
+    {
+      { 1, 2, 7},
+      { 2, 1, 8},
+      { 2, 3, 9},
+      { 3, 2, 10},
+      { 1, 3, 12},
+      { 1, 4, 16}, 
+      { 2, 5, 17},
+      { 3, 6, 18},
+      { 4, 5, 40},
+      { 5, 4, 41},
+      { 5, 6, 42},
+      { 6, 5, 43},
+      { 4, 6, 45},
+      { 0, 0, 0 }
+    };
+int refprism_1fa_2fb_1eb_0v_splitfaces[][4] =
+    {
+      {1,2,3,13},
+      {1,2,4,19},
+      {2,1,5,20},
+      {2,3,5,21},
+      {3,2,6,22},
+      {1,3,4,24},
+      {4,5,6,46},
+      { 0, 0, 0, 0 }
+    };
+int refprism_1fa_2fb_1eb_0v_splitelement[][5] = 
+  {
+    {1,2,3,4,25}, 
+    {0,0,0,0,0} 
+  };
+
+
+HPREF_ELEMENT_TYPE refprism_1fa_2fb_1eb_0v_newelstypes[] =
+    {
+      HP_PRISM,
+      HP_HEX_1F_0E_0V, 
+      HP_HEX_1F_0E_0V, 
+      HP_PRISM_1FB_1EA_0V,
+      HP_PRISM_1FB_1EA_0V, 
+      HP_PRISM_1FB_1EA_0V,
+      
+      HP_PRISM_1FA_0E_0V, 
+      HP_HEX_1FA_1FB_0E_0V,
+      HP_HEX_1FA_1FB_0E_0V, 
+      HP_PRISM_1FA_1FB_1EA_0V,
+      HP_PRISM_1FA_1FB_1EB_0V, 
+      HP_PRISM_1FA_1FB_1EB_0V,
+      
+      HP_NONE,
+    };
+
+  int refprism_1fa_2fb_1eb_0v_newels[][8] =
+    {
+      { 25, 21, 22, 46, 42, 43 }, 
+      { 40, 41, 20, 19, 46, 42, 21, 25 }, 
+      { 24, 18, 6, 45, 25, 22, 43, 46}, 
+      { 16, 19, 25, 4, 40, 46 },
+      { 4, 45, 46, 16, 24, 25 }, 
+      { 5, 41, 42, 17, 20, 21 },
+
+
+      { 13, 9, 10, 25, 21, 22 }, 
+      { 7, 8, 9, 13, 19, 20, 21, 25 }, 
+      { 3, 12, 13, 10, 18, 24, 25, 22 }, 
+      { 1, 7, 13, 16, 19, 25 },  
+      { 12, 1, 13, 24, 16, 25 }, 
+      { 8, 2, 9, 20, 17, 21}, 
+      
+    };
+  HPRef_Struct refprism_1fa_2fb_1eb_0v =
+    {
+      HP_PRISM,
+      refprism_1fa_2fb_1eb_0v_splitedges, 
+      refprism_1fa_2fb_1eb_0v_splitfaces, 
+      refprism_1fa_2fb_1eb_0v_splitelement, 
+      refprism_1fa_2fb_1eb_0v_newelstypes, 
+      refprism_1fa_2fb_1eb_0v_newels
+    };
+
+
+
+
+
+
+//  HP_PRISM_2FA_2FB 
+int refprism_2fa_2fb_0e_0v_splitedges[][3] =
+    {
+      { 1, 2, 7},
+      { 2, 3, 9},
+      { 3, 2, 10},
+      { 1, 3, 12},
+      { 1, 4, 16}, 
+      { 2, 5, 17},
+      { 3, 6, 18},
+      { 4, 5, 40},
+      { 5, 6, 42},
+      { 6, 5, 43},
+      { 4, 6, 45},
+      { 4, 1, 28},
+      { 5, 2, 29},
+      { 6, 3, 30},
+      { 0, 0, 0 }
+    };
+int refprism_2fa_2fb_0e_0v_splitfaces[][4] =
+    {
+      {1,2,3,13},
+      {1,2,4,19},
+      {2,3,5,21},
+      {3,2,6,22},
+      {1,3,4,24},
+      {4,5,6,46},  
+      {4,1,5,31},
+      {5,6,2,33},
+      {6,5,3,34},
+      {4,1,6,36},
+      { 0, 0, 0, 0 }
+    };
+int refprism_2fa_2fb_0e_0v_splitelement[][5] = 
+  {
+    {1,2,3,4,25}, 
+    {4,1,6,5,37},
+    {0,0,0,0,0} 
+  };
+  
+HPREF_ELEMENT_TYPE refprism_2fa_2fb_0e_0v_newelstypes[] =
+    {
+      HP_PRISM,
+      HP_HEX_1F_0E_0V, 
+      HP_HEX_1F_0E_0V, 
+      HP_PRISM_1FB_1EA_0V,
+      HP_PRISM_1FB_1EA_0V,
+      
+      HP_PRISM_1FA_0E_0V, 
+      HP_HEX_1FA_1FB_0E_0V,
+      HP_HEX_1FA_1FB_0E_0V, 
+      HP_PRISM_1FA_1FB_1EA_0V,
+      HP_PRISM_1FA_1FB_1EB_0V,
+      
+      HP_PRISM_1FA_0E_0V, 
+      HP_HEX_1FA_1FB_0E_0V,
+      HP_HEX_1FA_1FB_0E_0V, 
+      HP_PRISM_1FA_1FB_1EB_0V,
+      HP_PRISM_1FA_1FB_1EA_0V,
+      
+      HP_NONE,
+    };
+  int refprism_2fa_2fb_0e_0v_newels[][8] =
+    {
+      { 25, 21, 22, 37, 33, 34}, 
+      { 31, 29, 17, 19, 37, 33, 21, 25}, 
+      { 36, 24, 18, 30, 37, 25, 22, 34}, 
+      { 16, 19, 25, 28, 31, 37}, 
+      { 28, 36, 37, 16, 24, 25},
+      
+      { 13, 9, 10, 25, 21, 22 }, 
+      { 7, 2, 9, 13, 19, 17, 21, 25 }, 
+      { 3, 12, 13, 10, 18, 24, 25, 22 }, 
+      { 1, 7, 13, 16, 19, 25 }, 
+      { 12, 1, 13, 24, 16, 25 }, 
+
+      {  46, 43, 42 ,37, 34, 33},
+      { 40, 5, 29, 31, 46, 42, 33, 37 }, 
+      { 6, 45, 36, 30, 43, 46, 37, 34 }, 
+      { 40, 4, 46, 31, 28, 37 }, 
+      { 4, 45, 46, 28, 36, 37},  
+      
+    };
+  HPRef_Struct refprism_2fa_2fb_0e_0v =
+    {
+      HP_PRISM,
+      refprism_2fa_2fb_0e_0v_splitedges, 
+      refprism_2fa_2fb_0e_0v_splitfaces, 
+      refprism_2fa_2fb_0e_0v_splitelement, 
+      refprism_2fa_2fb_0e_0v_newelstypes, 
+      refprism_2fa_2fb_0e_0v_newels
+    };
+
+
+//  HP_PRISM_2FA_2FB_1EC 
+int refprism_2fa_2fb_1ec_0v_splitedges[][3] =
+    {
+      { 1, 2, 7},
+      { 2, 3, 9},
+      { 3, 2, 10},
+      { 3, 1, 11},
+      { 1, 3, 12},
+      { 1, 4, 16}, 
+      { 2, 5, 17},
+      { 3, 6, 18},
+      { 4, 1, 28},
+      { 5, 2, 29},
+      { 6, 3, 30},
+      { 4, 5, 40},
+      { 5, 6, 42},
+      { 6, 5, 43},
+      { 6, 4, 44},
+      { 4, 6, 45},
+      { 0, 0, 0 }
+    };
+int refprism_2fa_2fb_1ec_0v_splitfaces[][4] =
+    {
+      {1,2,3,13},
+      {1,2,4,19},
+      {2,3,5,21},
+      {3,2,6,22},
+      {3,1,6,23},
+      {1,3,4,24},
+      {4,5,6,46},  
+      {4,1,5,31},
+      {5,6,2,33},
+      {6,5,3,34},
+      {6,4,3,35},
+      {4,1,6,36},
+      { 0, 0, 0, 0 }
+    };
+int refprism_2fa_2fb_1ec_0v_splitelement[][5] = 
+  {
+    {1,2,3,4,25}, 
+    {4,1,6,5,37},
+    {0,0,0,0,0} 
+  };
+  
+HPREF_ELEMENT_TYPE refprism_2fa_2fb_1ec_0v_newelstypes[] =
+    {
+      HP_PRISM,
+      HP_HEX_1F_0E_0V, 
+      HP_HEX_1F_0E_0V, 
+      HP_PRISM_1FB_1EA_0V,
+      HP_PRISM_1FB_1EA_0V,
+      HP_PRISM_1FB_1EA_0V,
+      
+      HP_PRISM_1FA_0E_0V, 
+      HP_HEX_1FA_1FB_0E_0V,
+      HP_HEX_1FA_1FB_0E_0V, 
+      HP_PRISM_1FA_1FB_1EA_0V,
+      HP_PRISM_1FA_1FB_1EB_0V,
+      HP_PRISM_1FA_1FB_1EA_0V, 
+      
+      HP_PRISM_1FA_0E_0V, 
+      HP_HEX_1FA_1FB_0E_0V,
+      HP_HEX_1FA_1FB_0E_0V, 
+      HP_PRISM_1FA_1FB_1EB_0V,
+      HP_PRISM_1FA_1FB_1EA_0V,
+      HP_PRISM_1FA_1FB_1EB_0V, 
+      
+      HP_NONE,
+    };
+  int refprism_2fa_2fb_1ec_0v_newels[][8] =
+    {
+      { 25, 21, 22, 37, 33, 34}, 
+      { 31, 29, 17, 19, 37, 33, 21, 25}, 
+      { 36, 24, 23, 35, 37, 25, 22, 34}, 
+      { 16, 19, 25, 28, 31, 37}, 
+      { 28, 36, 37, 16, 24, 25},
+      { 18, 23, 22, 30, 35, 34}, 
+            
+      { 13, 9, 10, 25, 21, 22 }, 
+      { 7, 2, 9, 13, 19, 17, 21, 25 }, 
+      { 11, 12, 13, 10, 23, 24, 25, 22 }, 
+      { 1, 7, 13, 16, 19, 25 }, 
+      { 12, 1, 13, 24, 16, 25 }, 
+      { 3, 11, 10, 18, 23, 22 }, 
+
+      { 46, 43, 42 ,37, 34, 33},
+      { 40, 5, 29, 31, 46, 42, 33, 37 }, 
+      { 44, 45, 36, 35, 43, 46, 37, 34 }, 
+      { 40, 4, 46, 31, 28, 37 }, 
+      { 4, 45, 46, 28, 36, 37},  
+      { 44, 6, 43, 35, 30, 34}, 
+      
+    };
+  HPRef_Struct refprism_2fa_2fb_1ec_0v =
+    {
+      HP_PRISM,
+      refprism_2fa_2fb_1ec_0v_splitedges, 
+      refprism_2fa_2fb_1ec_0v_splitfaces, 
+      refprism_2fa_2fb_1ec_0v_splitelement, 
+      refprism_2fa_2fb_1ec_0v_newelstypes, 
+      refprism_2fa_2fb_1ec_0v_newels
+    };
+
+
+
+//  HP_PRISM_2FA_2FB_3E 
+int refprism_2fa_2fb_3e_0v_splitedges[][3] =
+    {
+      { 1, 2, 7},
+      { 2, 1, 8},
+      { 2, 3, 9},
+      { 3, 2, 10},
+      { 3, 1, 11},
+      { 1, 3, 12},
+      { 1, 4, 16}, 
+      { 2, 5, 17},
+      { 3, 6, 18},
+      { 4, 1, 28},
+      { 5, 2, 29},
+      { 6, 3, 30},
+      { 4, 5, 40},
+      { 5, 4, 41},
+      { 5, 6, 42},
+      { 6, 5, 43},
+      { 6, 4, 44},
+      { 4, 6, 45},
+      { 0, 0, 0 }
+    };
+int refprism_2fa_2fb_3e_0v_splitfaces[][4] =
+    {
+      {1,2,3,13},
+      {1,2,4,19},
+      {2,1,5,20},
+      {2,3,5,21},
+      {3,2,6,22},
+      {3,1,6,23},
+      {1,3,4,24},
+      {4,5,6,46},  
+      {4,1,5,31},
+      {5,4,2,32},
+      {5,6,2,33},
+      {6,5,3,34},
+      {6,4,3,35},
+      {4,1,6,36},
+      { 0, 0, 0, 0 }
+    };
+int refprism_2fa_2fb_3e_0v_splitelement[][5] = 
+  {
+    {1,2,3,4,25}, 
+    {4,1,6,5,37},
+    {0,0,0,0,0} 
+  };
+  
+HPREF_ELEMENT_TYPE refprism_2fa_2fb_3e_0v_newelstypes[] =
+    {
+      HP_PRISM,
+      HP_HEX_1F_0E_0V, 
+      HP_HEX_1F_0E_0V, 
+      HP_PRISM_1FB_1EA_0V,
+      HP_PRISM_1FB_1EA_0V,
+      HP_PRISM_1FB_1EA_0V,
+      HP_PRISM_1FB_1EA_0V, 
+      
+      HP_PRISM_1FA_0E_0V, 
+      HP_HEX_1FA_1FB_0E_0V,
+      HP_HEX_1FA_1FB_0E_0V, 
+      HP_PRISM_1FA_1FB_1EA_0V,
+      HP_PRISM_1FA_1FB_1EB_0V,
+      HP_PRISM_1FA_1FB_1EA_0V, 
+      HP_PRISM_1FA_1FB_1EB_0V, 
+      
+      HP_PRISM_1FA_0E_0V, 
+      HP_HEX_1FA_1FB_0E_0V,
+      HP_HEX_1FA_1FB_0E_0V, 
+      HP_PRISM_1FA_1FB_1EB_0V,
+      HP_PRISM_1FA_1FB_1EA_0V,
+      HP_PRISM_1FA_1FB_1EB_0V, 
+      HP_PRISM_1FA_1FB_1EA_0V, 
+      
+      HP_NONE,
+    };
+  int refprism_2fa_2fb_3e_0v_newels[][8] =
+    {
+      { 25, 21, 22, 37, 33, 34}, 
+      { 31, 32, 20, 19, 37, 33, 21, 25}, 
+      { 36, 24, 23, 35, 37, 25, 22, 34}, 
+      { 16, 19, 25, 28, 31, 37}, 
+      { 28, 36, 37, 16, 24, 25},
+      { 18, 23, 22, 30, 35, 34}, 
+      { 29, 32, 33, 17, 20, 21}, 
+            
+      { 13, 9, 10, 25, 21, 22 }, 
+      { 7, 8, 9, 13, 19, 20, 21, 25 }, 
+      { 11, 12, 13, 10, 23, 24, 25, 22 }, 
+      { 1, 7, 13, 16, 19, 25 }, 
+      { 12, 1, 13, 24, 16, 25 }, 
+      { 3, 11, 10, 18, 23, 22 }, 
+      { 8, 2, 9, 20, 17, 21 }, 
+
+      { 46, 43, 42 ,37, 34, 33},
+      { 40, 41, 32, 31, 46, 42, 33, 37 }, 
+      { 44, 45, 36, 35, 43, 46, 37, 34 }, 
+      { 40, 4, 46, 31, 28, 37 }, 
+      { 4, 45, 46, 28, 36, 37},  
+      { 44, 6, 43, 35, 30, 34},
+      { 5, 41, 42, 29, 32, 33}, 
+      
+    };
+  HPRef_Struct refprism_2fa_2fb_3e_0v =
+    {
+      HP_PRISM,
+      refprism_2fa_2fb_3e_0v_splitedges, 
+      refprism_2fa_2fb_3e_0v_splitfaces, 
+      refprism_2fa_2fb_3e_0v_splitelement, 
+      refprism_2fa_2fb_3e_0v_newelstypes, 
+      refprism_2fa_2fb_3e_0v_newels
+    };
+
+
+
+
+//  HP_PRISM_1FA_2E_0V  
+  int refprism_1fa_2e_0v_splitedges[][3] =
+    {
+      {2,3,9},
+      {1,3,12},
+      {1,4,16}, 
+      {2,5,17},
+      {3,6,18},
+      {5,6,42},
+      {4,6,45},
+      {5,4,41},
+      {2,1,8},
+      {4,5,40},
+      {1,2,7},
+      {0,0,0},
+
+    };
+  int refprism_1fa_2e_0v_splitfaces[][4] = 
+    {
+      {2,3,5,21},
+      {1,3,4,24},
+      {2,1,5,20},
+      {1,2,4,19},
+      {0,0,0,0},
+    };
+
+  HPREF_ELEMENT_TYPE refprism_1fa_2e_0v_newelstypes[] =
+    {
+      HP_HEX,
+      HP_PRISM,
+      HP_PRISM_1FA_0E_0V, 
+      HP_HEX_1F_0E_0V,
+      HP_PRISM_SINGEDGE, 
+      HP_PRISM_1FA_1E_0V,
+      HP_PRISM_SINGEDGE,
+      HP_PRISM_1FA_1E_0V,
+      HP_NONE
+    };
+  int refprism_1fa_2e_0v_newels[][8] =
+    {
+      {40,41,20,19,45,42,21,24}, 
+      {24,21,18,45,42,6},
+      {12,9,3,24,21,18},
+      {9, 12, 7, 8, 21, 24, 19, 20}, 
+      { 17, 21, 20, 5, 42, 41},
+      {2, 9, 8, 17, 21, 20},
+      {16,19,24,4,40,45},
+      {1,7,12,16,19,24}
+    };
+  HPRef_Struct refprism_1fa_2e_0v =
+    {
+      HP_PRISM,
+      refprism_1fa_2e_0v_splitedges, 
+
+      refprism_1fa_2e_0v_splitfaces, 0,
+      refprism_1fa_2e_0v_newelstypes, 
+      refprism_1fa_2e_0v_newels
+    };
+    
+//  HP_PRISM_2FA_2E_0V   
+  int refprism_2fa_2e_0v_splitedges[][3] =
+    {
+      {2,3,9},
+      {1,3,12},
+      {1,4,16}, 
+      {2,5,17},
+      {3,6,18},
+      {5,6,42},
+      {4,6,45},
+      {4,1,28},
+      {5,2,29},
+      {6,3,30},
+      {4,5,40},
+      {1,2,7},
+      { 5, 4, 41},
+      { 2, 1, 8},
+      {0,0,0}, 
+    };
+  int refprism_2fa_2e_0v_splitfaces[][4] = 
+    {
+      {2,3,5,21},
+      {1,3,4,24},
+      {1,2,4,19},
+      {4,1,6,36},
+      {4,1,5,31},
+      {5,6,2,33},
+      {5,4,2,32},
+      {2,1,5,20},
+      {0,0,0,0}, 
+    };
+
+  HPREF_ELEMENT_TYPE refprism_2fa_2e_0v_newelstypes[] =
+    {
+      HP_PRISM, 
+      HP_HEX, 
+      HP_PRISM_SINGEDGE,
+      HP_PRISM_SINGEDGE, 
+      
+      HP_PRISM_1FA_0E_0V,
+      HP_HEX_1F_0E_0V, 
+      HP_PRISM_1FA_1E_0V, 
+      HP_PRISM_1FA_1E_0V, 
+
+      HP_PRISM_1FA_0E_0V,
+      HP_HEX_1F_0E_0V, 
+      HP_PRISM_1FA_1E_0V, 
+      HP_PRISM_1FA_1E_0V, 
+      HP_NONE,
+      
+    };
+  int refprism_2fa_2e_0v_newels[][8] =
+    {
+      { 24, 21, 18, 36, 33, 30}, 
+      { 19, 20, 21, 24, 31, 32, 33, 36}, 
+      { 16, 19, 24, 28, 31, 36}, 
+      { 17, 21, 20, 29, 33, 32}, 
+      
+      { 12, 9, 3, 24, 21, 18}, 
+      { 7, 8, 9, 12, 19, 20, 21, 24}, 
+      { 1, 7, 12, 16, 19, 24},
+      { 2, 9, 8, 17, 21, 20}, 
+      
+      { 45, 6, 42, 36, 30, 33}, 
+      { 40, 45, 42, 41, 31, 36, 33, 32}, 
+      { 4, 45, 40, 28, 36, 31 }, 
+      { 5, 41, 42, 29, 32, 33 },
+    };
+  HPRef_Struct refprism_2fa_2e_0v =
+    {
+      HP_PRISM,
+      refprism_2fa_2e_0v_splitedges, 
+      refprism_2fa_2e_0v_splitfaces, 0,
+      refprism_2fa_2e_0v_newelstypes, 
+      refprism_2fa_2e_0v_newels
+    };
+
+
+ 
+//  HP_PRISM_3E_0V   
+  int refprism_3e_0v_splitedges[][3] =
+    {
+      { 1, 2, 7},
+      { 2, 1, 8},
+      { 2, 3, 9},
+      { 3, 2, 10},
+      { 3, 1, 11},
+      { 1, 3, 12},
+      { 4, 5, 40},
+      { 5, 4, 41},
+      { 5, 6, 42},
+      { 6, 5, 43},
+      { 6, 4, 44},
+      { 4, 6, 45},
+      { 0, 0, 0}, 
+    };
+  int refprism_3e_0v_splitfaces[][4] = 
+    {
+      {1,2,3,13},
+      {2,3,1,14},
+      {3,1,2,15},
+      {4,5,6,46},
+      {5,4,6,47},
+      {6,4,5,48},
+      {0,0,0,0}, 
+    };
+
+  HPREF_ELEMENT_TYPE refprism_3e_0v_newelstypes[] =
+    {
+      HP_PRISM,
+      HP_HEX,
+      HP_HEX,
+      HP_HEX,
+      HP_PRISM,
+      HP_PRISM,
+      HP_PRISM,
+      HP_PRISM_SINGEDGE,
+      HP_PRISM_SINGEDGE,
+      HP_PRISM_SINGEDGE,
+      HP_NONE
+    };
+  int refprism_3e_0v_newels[][8] =
+    {
+      { 13, 14, 15, 46, 47, 48}, 
+      { 7, 8, 14, 13, 40, 41, 47, 46}, 
+      { 15, 14, 9, 10, 48, 47, 42, 43}, 
+      { 12, 13, 15, 11, 45, 46, 48, 44}, 
+      { 14, 8, 9, 47, 41, 42 }, 
+      { 11, 15, 10, 44, 48, 43 }, 
+      { 7, 13, 12, 40, 46, 45}, 
+      { 1, 7, 12, 4, 40, 45}, 
+      { 2, 9, 8, 5, 42, 41 }, 
+      { 3, 11, 10, 6, 44, 43 }
+    };
+  HPRef_Struct refprism_3e_0v =
+    {
+      HP_PRISM,
+      refprism_3e_0v_splitedges, 
+      refprism_3e_0v_splitfaces, 0,
+      refprism_3e_0v_newelstypes, 
+      refprism_3e_0v_newels
+    };
+
+
+//  HP_PRISM_3E_0V   
+int refprism_1fa_3e_0v_splitedges[][3] =
+    {
+      { 1, 2, 7},
+      { 2, 1, 8},
+      { 2, 3, 9},
+      { 3, 2, 10},
+      { 3, 1, 11},
+      { 1, 3, 12},
+      { 1, 4, 16}, 
+      { 2, 5, 17},
+      { 3, 6, 18},
+      { 4, 5, 40},
+      { 5, 4, 41},
+      { 5, 6, 42},
+      { 6, 5, 43},
+      { 6, 4, 44},
+      { 4, 6, 45},
+      
+      { 0, 0, 0}, 
+    };
+int refprism_1fa_3e_0v_splitfaces[][4] = 
+    {
+      {1,2,3,13},
+      {2,3,1,14},
+      {3,1,2,15},
+      {1,2,4,19},
+      {2,1,5,20},
+      {2,3,5,21},
+      {3,2,6,22},
+      {3,1,6,23},
+      {1,3,4,24},
+      {4,5,6,46},
+      {5,4,6,47},
+      {6,4,5,48}, 
+      {0,0,0,0}, 
+    };
+
+int refprism_1fa_3e_0v_splitelements[][5] = 
+  {
+      {1,2,3,4,25},
+      {2,1,3,5,26},
+      {3,1,2,6,27}, 
+      {0,0,0,0,0},
+  };
+
+  HPREF_ELEMENT_TYPE refprism_1fa_3e_0v_newelstypes[] =
+    {
+      HP_PRISM,
+      HP_HEX,
+      HP_HEX,
+      HP_HEX,
+      HP_PRISM,
+      HP_PRISM,
+      HP_PRISM,
+      HP_PRISM_SINGEDGE,
+      HP_PRISM_SINGEDGE,
+      HP_PRISM_SINGEDGE,
+
+      HP_PRISM_1FA_0E_0V,
+      HP_HEX_1F_0E_0V, 
+      HP_HEX_1F_0E_0V, 
+      HP_HEX_1F_0E_0V, 
+      HP_PRISM_1FA_0E_0V,
+      HP_PRISM_1FA_0E_0V,
+      HP_PRISM_1FA_0E_0V,
+      HP_PRISM_1FA_1E_0V,
+      HP_PRISM_1FA_1E_0V,
+      HP_PRISM_1FA_1E_0V,
+      HP_NONE
+    };
+int refprism_1fa_3e_0v_newels[][8] =
+    {
+      { 25, 26, 27, 46, 47, 48}, 
+      { 19, 20, 26, 25, 40, 41, 47, 46},  
+      { 27, 26, 21, 22, 48, 47, 42, 43}, 
+      { 23, 24, 25, 27, 44, 45, 46, 48}, 
+      { 19, 25, 24, 40, 46, 45}, 
+      { 26, 20, 21, 47, 41, 42},
+      { 23, 27, 22, 44, 48, 43}, 
+      { 16, 19, 24, 4, 40, 45}, 
+      { 17, 21, 20, 5, 42, 41}, 
+      { 18, 23, 22, 6, 44, 43}, 
+
+      { 13, 14, 15, 25, 26, 27}, 
+      { 7, 8, 14, 13, 19, 20, 26, 25},
+      { 15, 14, 9, 10, 27, 26, 21, 22}, 
+      { 12, 13, 15, 11, 24, 25, 27, 23}, 
+      { 14, 8, 9, 26, 20, 21}, 
+      { 11, 15, 10, 23, 27, 22}, 
+      { 7, 13 , 12, 19, 25, 24}, 
+      { 2, 9, 8, 17, 21, 20}, 
+      { 3, 11, 10, 18, 23, 22}, 
+      { 1, 7, 12, 16, 19, 24}, 
+    };
+  HPRef_Struct refprism_1fa_3e_0v =
+    {
+      HP_PRISM,
+      refprism_1fa_3e_0v_splitedges, 
+      refprism_1fa_3e_0v_splitfaces, 
+      refprism_1fa_3e_0v_splitelements, 
+      refprism_1fa_3e_0v_newelstypes, 
+      refprism_1fa_3e_0v_newels
+    };
+
+
+
+//  HP_PRISM_2FA_3E_0V   
+int refprism_2fa_3e_0v_splitedges[][3] =
+    {
+      { 1, 2, 7},
+      { 2, 1, 8},
+      { 2, 3, 9},
+      { 3, 2, 10},
+      { 3, 1, 11},
+      { 1, 3, 12},
+      { 1, 4, 16}, 
+      { 2, 5, 17},
+      { 3, 6, 18},
+      { 4, 1, 28},
+      { 5, 2, 29},
+      { 6, 3, 30},
+      { 4, 5, 40},
+      { 5, 4, 41},
+      { 5, 6, 42},
+      { 6, 5, 43},
+      { 6, 4, 44},
+      { 4, 6, 45},
+      { 0, 0, 0}, 
+    };
+int refprism_2fa_3e_0v_splitfaces[][4] = 
+    {
+      {1,2,3,13},
+      {2,3,1,14},
+      {3,1,2,15},
+      {1,2,4,19},
+      {2,1,5,20},
+      {2,3,5,21},
+      {3,2,6,22},
+      {3,1,6,23},
+      {1,3,4,24},
+      {4,1,5,31},
+      {5,4,2,32},
+      {5,6,2,33},
+      {6,5,3,34},
+      {6,4,3,35},
+      {4,1,6,36},
+      {4,5,6,46},
+      {5,4,6,47},
+      {6,4,5,48}, 
+      {0,0,0,0}, 
+    };
+
+int refprism_2fa_3e_0v_splitelements[][5] = 
+  {
+      {1,2,3,4,25},
+      {2,1,3,5,26},
+      {3,1,2,6,27}, 
+      {4,1,6,5,37},
+      {5,2,4,6,38},
+      {6,4,5,3,39}, 
+      {0,0,0,0,0},
+  };
+
+  HPREF_ELEMENT_TYPE refprism_2fa_3e_0v_newelstypes[] =
+    {
+      HP_PRISM,
+      HP_HEX,
+      HP_HEX,
+      HP_HEX,
+      HP_PRISM,
+      HP_PRISM,
+      HP_PRISM,
+      HP_PRISM_SINGEDGE,
+      HP_PRISM_SINGEDGE,
+      HP_PRISM_SINGEDGE,
+
+      HP_PRISM_1FA_0E_0V,
+      HP_HEX_1F_0E_0V, 
+      HP_HEX_1F_0E_0V, 
+      HP_HEX_1F_0E_0V, 
+      HP_PRISM_1FA_0E_0V,
+      HP_PRISM_1FA_0E_0V,
+      HP_PRISM_1FA_0E_0V,
+      HP_PRISM_1FA_1E_0V,
+      HP_PRISM_1FA_1E_0V,
+      HP_PRISM_1FA_1E_0V,
+
+      HP_PRISM_1FA_0E_0V,
+      HP_HEX_1F_0E_0V, 
+      HP_HEX_1F_0E_0V, 
+      HP_HEX_1F_0E_0V, 
+      HP_PRISM_1FA_0E_0V,
+      HP_PRISM_1FA_0E_0V,
+      HP_PRISM_1FA_0E_0V,
+      HP_PRISM_1FA_1E_0V,
+      HP_PRISM_1FA_1E_0V,
+      HP_PRISM_1FA_1E_0V,
+
+      HP_NONE
+    };
+
+  int refprism_2fa_3e_0v_newels[][8] =
+    {
+      { 25, 26, 27, 37, 38, 39}, 
+      { 19, 20, 26, 25, 31, 32, 38, 37},  
+      { 27, 26, 21, 22, 39, 38, 33, 34}, 
+      { 23, 24, 25, 27, 35, 36, 37, 39}, 
+      { 19, 25, 24, 31, 37, 36}, 
+      { 26, 20, 21, 38, 32, 33},
+      { 23, 27, 22, 35, 39, 34}, 
+      { 16, 19, 24, 28, 31, 36}, 
+      { 17, 21, 20, 29, 33, 32}, 
+      { 18, 23, 22, 30, 35, 34}, 
+
+      { 13, 14, 15, 25, 26, 27}, 
+      { 7, 8, 14, 13, 19, 20, 26, 25},
+      { 15, 14, 9, 10, 27, 26, 21, 22}, 
+      { 12, 13, 15, 11, 24, 25, 27, 23}, 
+      { 14, 8, 9, 26, 20, 21}, 
+      { 11, 15, 10, 23, 27, 22}, 
+      { 7, 13 , 12, 19, 25, 24}, 
+      { 2, 9, 8, 17, 21, 20}, 
+      { 3, 11, 10, 18, 23, 22}, 
+      { 1, 7, 12, 16, 19, 24}, 
+
+      { 48, 47, 46, 39, 38, 37 }, 
+      { 48, 43, 42, 47, 39, 34, 33, 38}, 
+      { 45, 44, 48, 46, 36, 35, 39, 37},
+      { 46, 47, 41, 40, 37, 38, 32, 31}, 
+      { 47, 42, 41, 38, 33, 32}, 
+      { 45, 46, 40, 36, 37, 31}, 
+      { 44, 43, 48, 35, 34, 39},
+      { 6, 43, 44, 30, 34, 35}, 
+      { 5, 41, 42, 29, 32, 33}, 
+      { 4, 45, 40, 28, 36, 31},
+    };
+
+HPRef_Struct refprism_2fa_3e_0v =
+  {
+    HP_PRISM,
+    refprism_2fa_3e_0v_splitedges, 
+    refprism_2fa_3e_0v_splitfaces, 
+    refprism_2fa_3e_0v_splitelements, 
+    refprism_2fa_3e_0v_newelstypes, 
+    refprism_2fa_3e_0v_newels
+  };
+
+
+
+//  HP_PRISM_3FB_0V   
+  int refprism_3fb_0v_splitedges[][3] =
+    {
+      { 1, 2, 7},
+      { 2, 1, 8},
+      { 2, 3, 9},
+      { 3, 2, 10},
+      { 3, 1, 11},
+      { 1, 3, 12},
+      { 4, 5, 40},
+      { 5, 4, 41},
+      { 5, 6, 42},
+      { 6, 5, 43},
+      { 6, 4, 44},
+      { 4, 6, 45},
+      { 0, 0, 0}, 
+    };
+  int refprism_3fb_0v_splitfaces[][4] = 
+    {
+      {1,2,3,13},
+      {2,3,1,14},
+      {3,1,2,15},
+      {4,5,6,46},
+      {5,4,6,47},
+      {6,4,5,48},
+      {0,0,0,0}, 
+    };
+
+  HPREF_ELEMENT_TYPE refprism_3fb_0v_newelstypes[] =
+    {
+      HP_PRISM,
+      HP_HEX_1F_0E_0V,
+      HP_HEX_1F_0E_0V,
+      HP_HEX_1F_0E_0V,
+      HP_PRISM_1FB_1EA_0V,
+      HP_PRISM_1FB_1EA_0V,
+      HP_PRISM_1FB_1EA_0V,
+      HP_PRISM_1FB_1EA_0V,
+      HP_PRISM_1FB_1EA_0V,
+      HP_PRISM_1FB_1EA_0V,
+      HP_NONE
+    };
+  int refprism_3fb_0v_newels[][8] =
+    {
+      { 13, 14, 15, 46, 47, 48}, 
+      { 8, 7, 40, 41, 14,13, 46, 47 }, 
+      { 10, 9, 42, 43, 15, 14, 47, 48 }, 
+      { 44, 45, 12, 11, 48, 46, 13, 15}, 
+      { 1, 7, 13, 4, 40, 46 }, 
+      { 4, 45, 46, 1, 12, 13}, 
+      { 2, 9, 14, 5, 42, 47 }, 
+      { 5, 41, 47, 2, 8, 14 }, 
+      { 3, 11, 15, 6, 44, 48}, 
+      { 6, 43, 48, 3, 10, 15},
+
+    };
+  HPRef_Struct refprism_3fb_0v =
+    {
+      HP_PRISM,
+      refprism_3fb_0v_splitedges, 
+      refprism_3fb_0v_splitfaces, 0,
+      refprism_3fb_0v_newelstypes, 
+      refprism_3fb_0v_newels
+    };
+
+
+//  HP_PRISM_3FB_0V   
+int refprism_1fa_3fb_0v_splitedges[][3] =
+    {
+      { 1, 2, 7},
+      { 2, 1, 8},
+      { 2, 3, 9},
+      { 3, 2, 10},
+      { 3, 1, 11},
+      { 1, 3, 12},
+      { 1, 4, 16}, 
+      { 2, 5, 17},
+      { 3, 6, 18},
+      { 4, 5, 40},
+      { 5, 4, 41},
+      { 5, 6, 42},
+      { 6, 5, 43},
+      { 6, 4, 44},
+      { 4, 6, 45},
+      { 0, 0, 0}, 
+    };
+int refprism_1fa_3fb_0v_splitfaces[][4] = 
+    {
+      {1,2,3,13},
+      {2,3,1,14},
+      {3,1,2,15},
+      {1,2,4,19},
+      {2,1,5,20},
+      {2,3,5,21},
+      {3,2,6,22},
+      {3,1,6,23},
+      {1,3,4,24},
+      {4,5,6,46},
+      {5,4,6,47},
+      {6,4,5,48}, 
+      {0,0,0,0}, 
+    };
+
+int refprism_1fa_3fb_0v_splitelements[][5] = 
+  {
+      {1,2,3,4,25},
+      {2,1,3,5,26},
+      {3,1,2,6,27}, 
+      {0,0,0,0,0},
+  };
+
+  HPREF_ELEMENT_TYPE refprism_1fa_3fb_0v_newelstypes[] =
+    {
+      HP_PRISM,
+      HP_HEX_1F_0E_0V,
+      HP_HEX_1F_0E_0V,
+      HP_HEX_1F_0E_0V,
+      
+      HP_PRISM_1FB_1EA_0V,
+      HP_PRISM_1FB_1EA_0V,
+      HP_PRISM_1FB_1EA_0V,
+      HP_PRISM_1FB_1EA_0V,
+      HP_PRISM_1FB_1EA_0V,
+      HP_PRISM_1FB_1EA_0V,
+
+      HP_PRISM_1FA_0E_0V,
+      HP_HEX_1FA_1FB_0E_0V, 
+      HP_HEX_1FA_1FB_0E_0V, 
+      HP_HEX_1FA_1FB_0E_0V, 
+      HP_PRISM_1FA_1FB_1EA_0V, 
+      HP_PRISM_1FA_1FB_1EB_0V, 
+      HP_PRISM_1FA_1FB_1EA_0V, 
+      HP_PRISM_1FA_1FB_1EB_0V, 
+      HP_PRISM_1FA_1FB_1EA_0V, 
+      HP_PRISM_1FA_1FB_1EB_0V, 
+      
+      HP_NONE
+    };
+  int refprism_1fa_3fb_0v_newels[][8] =
+    {
+      { 25, 26, 27, 46, 47, 48}, 
+      { 19, 40, 41, 20, 25, 46, 47, 26}, 
+      { 22, 21, 42, 43, 27, 26, 47, 48}, 
+      { 24, 23, 44, 45, 25, 27, 48, 46},
+      
+      { 16, 19, 25, 4, 40, 46 }, 
+      { 4, 45, 46, 16, 24, 25 }, 
+      { 17, 21, 26, 5, 42, 47 }, 
+      { 5, 41, 47, 17, 20, 26}, 
+      { 18, 23, 27, 6, 44, 48}, 
+      { 6, 43, 48, 18, 22, 27},
+
+      { 13, 14, 15, 25, 26, 27}, 
+      { 7, 8, 14, 13, 19, 20, 26, 25}, 
+      { 9, 10, 15, 14, 21, 22, 27, 26},
+      { 11, 12, 13, 15, 23, 24, 25, 27},
+
+      { 2, 9, 14, 17, 21, 26}, 
+      { 8, 2, 14, 20, 17, 26}, 
+      { 1, 7, 13, 16, 19, 25}, 
+      { 12, 1, 13, 24, 16, 25 }, 
+      { 3, 11, 15, 18, 23, 27 },
+      { 10, 3, 15, 22, 18, 27}, 
+      
+      };
+  HPRef_Struct refprism_1fa_3fb_0v =
+    {
+      HP_PRISM,
+      refprism_1fa_3fb_0v_splitedges, 
+      refprism_1fa_3fb_0v_splitfaces, 
+      refprism_1fa_3fb_0v_splitelements, 
+      refprism_1fa_3fb_0v_newelstypes, 
+      refprism_1fa_3fb_0v_newels
+    };
+     
+
+
+//  HP_PRISM_2FA_3E_0V   
+int refprism_2fa_3fb_0v_splitedges[][3] =
+    {
+      { 1, 2, 7},
+      { 2, 1, 8},
+      { 2, 3, 9},
+      { 3, 2, 10},
+      { 3, 1, 11},
+      { 1, 3, 12},
+      { 1, 4, 16}, 
+      { 2, 5, 17},
+      { 3, 6, 18},
+      { 4, 1, 28},
+      { 5, 2, 29},
+      { 6, 3, 30},
+      { 4, 5, 40},
+      { 5, 4, 41},
+      { 5, 6, 42},
+      { 6, 5, 43},
+      { 6, 4, 44},
+      { 4, 6, 45},
+      { 0, 0, 0}, 
+    };
+int refprism_2fa_3fb_0v_splitfaces[][4] = 
+    {
+      {1,2,3,13},
+      {2,3,1,14},
+      {3,1,2,15},
+      {1,2,4,19},
+      {2,1,5,20},
+      {2,3,5,21},
+      {3,2,6,22},
+      {3,1,6,23},
+      {1,3,4,24},
+      {4,1,5,31},
+      {5,4,2,32},
+      {5,6,2,33},
+      {6,5,3,34},
+      {6,4,3,35},
+      {4,1,6,36},
+      {4,5,6,46},
+      {5,4,6,47},
+      {6,4,5,48}, 
+      {0,0,0,0}, 
+    };
+
+int refprism_2fa_3fb_0v_splitelements[][5] = 
+  {
+      {1,2,3,4,25},
+      {2,1,3,5,26},
+      {3,1,2,6,27}, 
+      {4,1,6,5,37},
+      {5,2,4,6,38},
+      {6,4,5,3,39}, 
+      {0,0,0,0,0},
+  };
+
+  HPREF_ELEMENT_TYPE refprism_2fa_3fb_0v_newelstypes[] =
+    {
+
+      HP_PRISM,
+      HP_HEX_1F_0E_0V,
+      HP_HEX_1F_0E_0V,
+      HP_HEX_1F_0E_0V,
+      HP_PRISM_1FB_1EA_0V,
+      HP_PRISM_1FB_1EA_0V,
+      HP_PRISM_1FB_1EA_0V,
+      HP_PRISM_1FB_1EA_0V,
+      HP_PRISM_1FB_1EA_0V,
+      HP_PRISM_1FB_1EA_0V,
+
+      HP_PRISM_1FA_0E_0V,
+      HP_HEX_1FA_1FB_0E_0V, 
+      HP_HEX_1FA_1FB_0E_0V, 
+      HP_HEX_1FA_1FB_0E_0V,
+      HP_PRISM_1FA_1FB_1EA_0V, 
+      HP_PRISM_1FA_1FB_1EB_0V, 
+      HP_PRISM_1FA_1FB_1EA_0V, 
+      HP_PRISM_1FA_1FB_1EB_0V, 
+      HP_PRISM_1FA_1FB_1EA_0V, 
+      HP_PRISM_1FA_1FB_1EB_0V, 
+
+      HP_PRISM_1FA_0E_0V,
+      HP_HEX_1FA_1FB_0E_0V, 
+      HP_HEX_1FA_1FB_0E_0V, 
+      HP_HEX_1FA_1FB_0E_0V,
+      HP_PRISM_1FA_1FB_1EA_0V, 
+      HP_PRISM_1FA_1FB_1EB_0V, 
+      HP_PRISM_1FA_1FB_1EA_0V, 
+      HP_PRISM_1FA_1FB_1EB_0V, 
+      HP_PRISM_1FA_1FB_1EA_0V, 
+      HP_PRISM_1FA_1FB_1EB_0V, 
+
+      HP_NONE
+    };
+  int refprism_2fa_3fb_0v_newels[][8] =
+    {
+      { 25, 26, 27, 37, 38, 39}, 
+      { 19, 31, 32, 20, 25, 37, 38, 26}, 
+      { 33, 34, 22, 21, 38, 39, 27, 26}, 
+      { 35, 36, 24, 23, 39, 37, 25, 27}, 
+
+      { 16, 19, 25, 28, 31, 37}, 
+      { 28, 36, 37, 16, 24, 25 }, 
+      { 17, 21, 26, 29, 33, 38 }, 
+      { 29, 32, 38, 17, 20, 26}, 
+      { 18, 23, 27, 30, 35, 39}, 
+      { 30, 34, 39, 18, 22, 27},
+
+ 
+      { 13, 14, 15, 25, 26, 27}, 
+      { 7, 8, 14, 13, 19, 20, 26, 25}, 
+      { 9, 10, 15, 14, 21, 22, 27, 26},
+      { 11, 12, 13, 15, 23, 24, 25, 27},
+
+      { 2, 9, 14, 17, 21, 26}, 
+      { 8, 2, 14, 20, 17, 26}, 
+      { 1, 7, 13, 16, 19, 25}, 
+      { 12, 1, 13, 24, 16, 25 }, 
+      { 3, 11, 15, 18, 23, 27 },
+      { 10, 3, 15, 22, 18, 27}, 
+
+      
+      { 48, 47, 46, 39, 38, 37 }, 
+      { 44, 45, 36, 35, 48, 46, 37, 39}, 
+      { 40, 41, 32, 31, 46, 47, 38, 37}, 
+      { 42, 43, 34, 33, 47, 48, 39, 38}, 
+      
+      { 6, 43, 48, 30, 34, 39}, 
+      { 44, 6, 48, 35, 30, 39}, 
+      { 4, 45, 46, 28, 36, 37}, 
+      { 40, 4, 46, 31, 28, 37}, 
+      { 5, 41, 47, 29, 32, 38}, 
+      { 42, 5, 47, 33, 29, 38},
+    };
+
+HPRef_Struct refprism_2fa_3fb_0v =
+  {
+    HP_PRISM,
+    refprism_2fa_3fb_0v_splitedges, 
+    refprism_2fa_3fb_0v_splitfaces, 
+    refprism_2fa_3fb_0v_splitelements, 
+    refprism_2fa_3fb_0v_newelstypes, 
+    refprism_2fa_3fb_0v_newels
+  };
+
+
+/* 
+
+
+//  HP_PRISM_3E_4EH
+int refprism_3e_4eh_splitedges[][3] =
+    {
+      { 1, 2, 7},
+      { 2, 1, 8},
+      { 2, 3, 9},
+      { 3, 2, 10},
+      { 3, 1, 11},
+      { 1, 3, 12},
+      { 4, 5, 40},
+      { 5, 4, 41},
+      { 5, 6, 42},
+      { 6, 5, 43},
+      { 6, 4, 44},
+      { 4, 6, 45},
+      { 0, 0, 0},
+
+    };
+int refprism_3e_4eh_splitfaces[][4] = 
+    {
+      {3,1,2,15},
+      {6,4,5,48}, 
+      {0,0,0,0}, 
+    };
+
+HPREF_ELEMENT_TYPE refprism_2fa_3fb_0v_newelstypes[] =
+  {
+    HP_PRISM, 
+    HP_HEX_2EH_0V,
+    HP_HEX_2EH_0V,
+    HP_TET_2E,
+    HP_TET_2E,
+    HP_PRISM_1E_2EH_0V, 
+    HP_PRISM_1E_2EH_0V, 
+    HP_NONE
+    };
+  int refprism_2fa_3fb_0v_newels[][8] =
+    {
+      {15, 7, 8, 48, 40, 41 }, 
+      
+    };
+
+HPRef_Struct refprism_2fa_3fb_0v =
+  {
+    HP_PRISM,
+    refprism_2fa_3fb_0v_splitedges, 
+    refprism_2fa_3fb_0v_splitfaces, 
+    refprism_2fa_3fb_0v_splitelements, 
+    refprism_2fa_3fb_0v_newelstypes, 
+    refprism_2fa_3fb_0v_newels
+  };
+*/ 
+
+/*
+//  HP_PRISM_2FA_3E_0V   
+int refprism_3e_4_0v_splitedges[][3] =
+    {
+      { 1, 2, 7},
+      { 2, 1, 8},
+      { 2, 3, 9},
+      { 3, 2, 10},
+      { 3, 1, 11},
+      { 1, 3, 12},
+      { 1, 4, 16}, 
+      { 2, 5, 17},
+      { 3, 6, 18},
+      { 4, 1, 28},
+      { 5, 2, 29},
+      { 6, 3, 30},
+      { 4, 5, 40},
+      { 5, 4, 41},
+      { 5, 6, 42},
+      { 6, 5, 43},
+      { 6, 4, 44},
+      { 4, 6, 45},
+      { 0, 0, 0}, 
+    };
+int refprism_2fa_3e_0v_splitfaces[][4] = 
+    {
+      {1,2,3,13},
+      {2,3,1,14},
+      {3,1,2,15},
+      {1,2,4,19},
+      {2,1,5,20},
+      {2,3,5,21},
+      {3,2,6,22},
+      {3,1,6,23},
+      {1,3,4,24},
+      {4,1,5,31},
+      {5,4,2,32},
+      {5,6,2,33},
+      {6,5,3,34},
+      {6,4,3,35},
+      {4,1,6,36},
+      {4,5,6,46},
+      {5,4,6,47},
+      {6,4,5,48}, 
+      {0,0,0,0}, 
+    };
+
+int refprism_2fa_3e_0v_splitelements[][5] = 
+  {
+      {1,2,3,4,25},
+      {2,1,3,5,26},
+      {3,1,2,6,27}, 
+      {4,1,6,5,37},
+      {5,2,4,6,38},
+      {6,4,5,3,39}, 
+      {0,0,0,0,0},
+  };
+
+  HPREF_ELEMENT_TYPE refprism_2fa_3e_0v_newelstypes[] =
+    {
+      HP_PRISM,
+      HP_HEX,
+      HP_HEX,
+      HP_HEX,
+      HP_PRISM,
+      HP_PRISM,
+      HP_PRISM,
+      HP_PRISM_SINGEDGE,
+      HP_PRISM_SINGEDGE,
+      HP_PRISM_SINGEDGE,
+
+      HP_PRISM_1FA_0E_0V,
+      HP_HEX_1F_0E_0V, 
+      HP_HEX_1F_0E_0V, 
+      HP_HEX_1F_0E_0V, 
+      HP_PRISM_1FA_0E_0V,
+      HP_PRISM_1FA_0E_0V,
+      HP_PRISM_1FA_0E_0V,
+      HP_PRISM_1FA_1E_0V,
+      HP_PRISM_1FA_1E_0V,
+      HP_PRISM_1FA_1E_0V,
+
+      HP_PRISM_1FA_0E_0V,
+      HP_HEX_1F_0E_0V, 
+      HP_HEX_1F_0E_0V, 
+      HP_HEX_1F_0E_0V, 
+      HP_PRISM_1FA_0E_0V,
+      HP_PRISM_1FA_0E_0V,
+      HP_PRISM_1FA_0E_0V,
+      HP_PRISM_1FA_1E_0V,
+      HP_PRISM_1FA_1E_0V,
+      HP_PRISM_1FA_1E_0V,
+
+      HP_NONE
+    };
+
+  int refprism_2fa_3e_0v_newels[][8] =
+    {
+      { 25, 26, 27, 37, 38, 39}, 
+      { 19, 20, 26, 25, 31, 32, 38, 37},  
+      { 27, 26, 21, 22, 39, 38, 33, 34}, 
+      { 23, 24, 25, 27, 35, 36, 37, 39}, 
+      { 19, 25, 24, 31, 37, 36}, 
+      { 26, 20, 21, 38, 32, 33},
+      { 23, 27, 22, 35, 39, 34}, 
+      { 16, 19, 24, 28, 31, 36}, 
+      { 17, 21, 20, 29, 33, 32}, 
+      { 18, 23, 22, 30, 35, 34}, 
+
+      { 13, 14, 15, 25, 26, 27}, 
+      { 7, 8, 14, 13, 19, 20, 26, 25},
+      { 15, 14, 9, 10, 27, 26, 21, 22}, 
+      { 12, 13, 15, 11, 24, 25, 27, 23}, 
+      { 14, 8, 9, 26, 20, 21}, 
+      { 11, 15, 10, 23, 27, 22}, 
+      { 7, 13 , 12, 19, 25, 24}, 
+      { 2, 9, 8, 17, 21, 20}, 
+      { 3, 11, 10, 18, 23, 22}, 
+      { 1, 7, 12, 16, 19, 24}, 
+
+      { 48, 47, 46, 39, 38, 37 }, 
+      { 48, 43, 42, 47, 39, 34, 33, 38}, 
+      { 45, 44, 48, 46, 36, 35, 39, 37},
+      { 46, 47, 41, 40, 37, 38, 32, 31}, 
+      { 47, 42, 41, 38, 33, 32}, 
+      { 45, 46, 40, 36, 37, 31}, 
+      { 44, 43, 48, 35, 34, 39},
+      { 6, 43, 44, 30, 34, 35}, 
+      { 5, 41, 42, 29, 32, 33}, 
+      { 4, 45, 40, 28, 36, 31},
+    };
+
+HPRef_Struct refprism_2fa_3e_0v =
+  {
+    HP_PRISM,
+    refprism_2fa_3e_0v_splitedges, 
+    refprism_2fa_3e_0v_splitfaces, 
+    refprism_2fa_3e_0v_splitelements, 
+    refprism_2fa_3e_0v_newelstypes, 
+    refprism_2fa_3e_0v_newels
+  };
+
+*/
+/*
+
+//  HP_PRISM_1FB_1EB_0V   ... quad face 1-2-4-5
+  int refprism_1fb_1eb_0v_splitedges[][3] =
+    {
+      { 1, 3, 7 },
+      { 2, 3, 8 },
+      { 4, 6, 9 },
+      { 5, 6, 10 },
+      { 2, 1, 11 },
+      { 5, 4, 12 },
+      { 0, 0, 0 }
+    };
+  HPREF_ELEMENT_TYPE refprism_1fb_1eb_0v_newelstypes[] =
+    {
+      HP_HEX_1F_0E_0V,
+      HP_PRISM_1FB_1EB_0V,
+      HP_PRISM,
+      HP_NONE,
+    };
+  int refprism_1fb_1eb_0v_newels[][8] =
+    {
+      { 1, 4, 12, 11, 7, 9, 10, 8  },
+      { 11, 2, 8, 12, 5, 10 },
+      { 7, 8, 3, 9, 10, 6 }
+    };
+  HPRef_Struct refprism_1fb_1eb_0v =
+    {
+      HP_PRISM,
+      refprism_1fb_1eb_0v_splitedges, 
+      0, 0,
+      refprism_1fb_1eb_0v_newelstypes, 
+      refprism_1fb_1eb_0v_newels
+    };
+
+
+
+
+
+
+
+
+
+
+  // HP_PRISM_2F_0E_0V
+  int refprism_2f_0e_0v_splitedges[][3] =
+    {
+      { 1, 3, 7 },
+      { 2, 1, 8 },
+      { 2, 3, 9 },
+      { 3, 1, 10 },
+
+      { 4, 6, 12 },
+      { 5, 4, 13 },
+      { 5, 6, 14 },
+      { 6, 4, 15 },
+
+      { 0, 0, 0 }
+    };
+
+  int refprism_2f_0e_0v_splitfaces[][4] =
+    {
+      { 2, 1, 3, 11 },
+      { 5, 4, 6, 16 },
+      { 0, 0, 0, 0 },
+    };
+
+  HPREF_ELEMENT_TYPE refprism_2f_0e_0v_newelstypes[] =
+    {
+      HP_HEX_1F_0E_0V,
+      HP_HEX_1F_0E_0V,
+      HP_PRISM_1FB_1EA_0V,
+      HP_PRISM_1FB_1EA_0V,
+      HP_PRISM,
+      HP_NONE,
+    };
+  int refprism_2f_0e_0v_newels[][8] =
+    {
+      //{ 1, 8, 11, 7, 4, 13, 16, 12 },
+      // { 9, 3, 10, 11, 14, 6, 15, 16 },
+      { 1, 4, 13, 8, 7, 12, 16, 11 },
+      { 9, 14, 6, 3, 11, 16, 15, 10 },
+      { 2, 9, 11, 5, 14, 16 },
+      // { 8, 2, 11, 13, 5, 16 },
+      { 5, 13, 16, 2, 8, 11 },
+      { 7, 11, 10, 12, 16, 15 }
+    };
+  HPRef_Struct refprism_2f_0e_0v =
+    {
+      HP_PRISM,
+      refprism_2f_0e_0v_splitedges, 
+      refprism_2f_0e_0v_splitfaces, 
+      0,
+      refprism_2f_0e_0v_newelstypes, 
+      refprism_2f_0e_0v_newels
+    };
+
+*/
diff --git a/contrib/Netgen/libsrc/meshing/hpref_pyramid.hpp b/contrib/Netgen/libsrc/meshing/hpref_pyramid.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..521daf5081e84bf11891b835a8af358cd2af5c84
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/hpref_pyramid.hpp
@@ -0,0 +1,118 @@
+
+  // HP_PYRAMID
+  int refpyramid_splitedges[][3] =
+    {
+      { 0, 0, 0 }
+    };
+  HPREF_ELEMENT_TYPE refpyramid_newelstypes[] =
+    {
+      HP_PYRAMID,
+      HP_NONE,
+    };
+  int refpyramid_newels[][8] =
+    {
+      { 1, 2, 3, 4, 5 }
+    };
+  HPRef_Struct refpyramid =
+    {
+      HP_PYRAMID,
+      refpyramid_splitedges, 
+      0, 0,
+      refpyramid_newelstypes, 
+      refpyramid_newels
+    };
+
+
+// singular point 1      
+  // HP_PYRAMID_0E_1V
+  int refpyramid_0e_1v_splitedges[][3] =
+    {
+      { 0, 0, 0 }
+    };
+  HPREF_ELEMENT_TYPE refpyramid_0e_1v_newelstypes[] =
+    {
+      HP_TET_0E_1V,
+      HP_TET,
+      HP_NONE,
+    };
+  int refpyramid_0e_1v_newels[][8] =
+    {
+      { 1, 2, 4, 5 },
+      { 2, 3, 4, 5 },
+    };
+  HPRef_Struct refpyramid_0e_1v =
+    {
+      HP_PYRAMID,
+      refpyramid_0e_1v_splitedges, 
+      0, 0,
+      refpyramid_0e_1v_newelstypes, 
+      refpyramid_0e_1v_newels
+    };
+
+
+// singular edges 1-2 1-4 singular point 1 
+  // HP_PYRAMID_EDGES
+  int refpyramid_edges_splitedges[][3] =
+    {
+      { 0, 0, 0 }
+    };
+  HPREF_ELEMENT_TYPE refpyramid_edges_newelstypes[] =
+    {
+      HP_TET_1E_1VA,
+      HP_TET_1E_1VA,
+      HP_NONE,
+    };
+  int refpyramid_edges_newels[][8] =
+    {
+      { 1, 2, 3, 5 },
+      { 1, 4, 5, 3 },
+    };
+  HPRef_Struct refpyramid_edges =
+    {
+      HP_PYRAMID,
+      refpyramid_edges_splitedges, 
+      0, 0,
+      refpyramid_edges_newelstypes, 
+      refpyramid_edges_newels
+    };
+
+
+
+// singular face 1-2-5 singular point 5
+  // HP_PYRAMID_1FB_0E_1VA
+  int refpyramid_1fb_0e_1va_splitedges[][3] =
+    {
+      { 1, 4, 6 },
+      { 2, 3, 7 },
+      { 5, 1, 8 },
+      { 5, 2, 9 },
+      { 5, 3, 10 },
+      { 5, 4, 11 },
+      { 0, 0, 0 },
+    };
+
+  HPREF_ELEMENT_TYPE refpyramid_1fb_0e_1va_newelstypes[] =
+    {
+      HP_HEX_1F_0E_0V,
+      HP_PYRAMID_1FB_0E_1VA,
+      HP_PRISM,
+      HP_NONE,
+    };
+  int refpyramid_1fb_0e_1va_newels[][8] =
+    {
+      { 1, 8, 9, 2, 6, 11, 10, 7 },
+      { 8, 9, 10, 11, 5 },
+      { 3, 7, 10, 4, 6, 11 }
+    };
+  HPRef_Struct refpyramid_1fb_0e_1va =
+    {
+      HP_PYRAMID,
+      refpyramid_1fb_0e_1va_splitedges, 
+      0, 0,
+      refpyramid_1fb_0e_1va_newelstypes, 
+      refpyramid_1fb_0e_1va_newels
+    };
+
+
+
+
diff --git a/contrib/Netgen/libsrc/meshing/hpref_quad.hpp b/contrib/Netgen/libsrc/meshing/hpref_quad.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..2a23156d1c66e7bc1efeb637a60de8756e77946f
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/hpref_quad.hpp
@@ -0,0 +1,2082 @@
+// HP_QUAD
+int refquad_splitedges[][3] =
+{
+  { 0, 0, 0 }
+};
+HPREF_ELEMENT_TYPE refquad_newelstypes[] =
+{
+  HP_QUAD,
+  HP_NONE,
+};
+int refquad_newels[][8] =
+{
+  { 1, 2, 3, 4 },
+};
+HPRef_Struct refquad =
+{
+  HP_QUAD,
+  refquad_splitedges, 
+  0, 0,
+  refquad_newelstypes, 
+  refquad_newels
+};
+
+
+
+
+
+
+
+// HP_QUAD_SINGCORNER
+int refquad_singcorner_splitedges[][3] =
+{
+  { 1, 2, 5 },
+  { 1, 4, 6 },
+  { 0, 0, 0 }
+};
+HPREF_ELEMENT_TYPE refquad_singcorner_newelstypes[] =
+{
+  HP_TRIG_SINGCORNER,
+  HP_QUAD,
+  HP_TRIG,
+  HP_NONE,
+};
+int refquad_singcorner_newels[][8] =
+{
+  { 1, 5, 6 },
+  { 2, 4, 6, 5 },
+  { 2, 3, 4 },
+};
+HPRef_Struct refquad_singcorner =
+{
+  HP_QUAD,
+  refquad_singcorner_splitedges, 
+  0, 0,
+  refquad_singcorner_newelstypes, 
+  refquad_singcorner_newels
+};
+
+
+
+
+
+// HP_DUMMY_QUAD_SINGCORNER
+int refdummyquad_singcorner_splitedges[][3] =
+{
+  { 0, 0, 0 }
+};
+HPREF_ELEMENT_TYPE refdummyquad_singcorner_newelstypes[] =
+{
+  HP_TRIG_SINGCORNER,
+  HP_TRIG,
+  HP_NONE,
+};
+int refdummyquad_singcorner_newels[][8] =
+{
+  { 1, 2, 4 },
+  { 4, 2, 3 },
+};
+HPRef_Struct refdummyquad_singcorner =
+{
+  HP_QUAD,
+  refdummyquad_singcorner_splitedges, 
+  0, 0,
+  refdummyquad_singcorner_newelstypes, 
+  refdummyquad_singcorner_newels
+};
+
+
+
+
+
+
+
+// HP_QUAD_SINGEDGE
+int refquad_singedge_splitedges[][3] =
+{
+  { 1, 4, 5 },
+  { 2, 3, 6 },
+  { 0, 0, 0 }
+};
+HPREF_ELEMENT_TYPE refquad_singedge_newelstypes[] =
+{
+  HP_QUAD_SINGEDGE,
+  HP_QUAD,
+  HP_NONE,
+};
+int refquad_singedge_newels[][8] =
+{
+  { 1, 2, 6, 5 },
+  { 5, 6, 3, 4 },
+};
+HPRef_Struct refquad_singedge =
+{
+  HP_QUAD,
+  refquad_singedge_splitedges, 
+  0, 0,
+  refquad_singedge_newelstypes, 
+  refquad_singedge_newels
+};
+
+
+
+
+
+
+// HP_QUAD_0E_2VA
+int refquad_0e_2va_splitedges[][3] =
+{
+  { 1, 2, 5 },
+  { 1, 4, 6 },
+  { 2, 1, 7 },
+  { 2, 3, 8 },
+  { 0, 0, 0 }
+};
+HPREF_ELEMENT_TYPE refquad_0e_2va_newelstypes[] =
+{
+  HP_TRIG_SINGCORNER,
+  HP_TRIG_SINGCORNER,
+  HP_QUAD,
+  HP_QUAD,
+  HP_NONE,
+};
+int refquad_0e_2va_newels[][8] =
+{
+  { 1, 5, 6 },
+  { 2, 8, 7 },
+  { 5, 7, 8, 6 },
+  { 6, 8, 3, 4 },
+};
+HPRef_Struct refquad_0e_2va =
+{
+  HP_QUAD,
+  refquad_0e_2va_splitedges, 
+  0, 0,
+  refquad_0e_2va_newelstypes, 
+  refquad_0e_2va_newels
+};
+
+
+
+// HP_QUAD_0E_2VB
+int refquad_0e_2vb_splitedges[][3] =
+{
+  { 1, 2, 5 },
+  { 1, 4, 6 },
+  { 3, 4, 7 },
+  { 3, 2, 8 },
+  { 0, 0, 0 }
+};
+HPREF_ELEMENT_TYPE refquad_0e_2vb_newelstypes[] =
+{
+  HP_TRIG_SINGCORNER,
+  HP_TRIG_SINGCORNER,
+  HP_QUAD,
+  HP_QUAD,
+  HP_NONE,
+};
+int refquad_0e_2vb_newels[][8] =
+{
+  { 1, 5, 6 },
+  { 3, 7, 8 },
+  { 5, 2, 4, 6 },
+  { 2, 8, 7, 4 },
+};
+HPRef_Struct refquad_0e_2vb =
+{
+  HP_QUAD,
+  refquad_0e_2vb_splitedges, 
+  0, 0,
+  refquad_0e_2vb_newelstypes, 
+  refquad_0e_2vb_newels
+};
+
+
+
+
+// HP_QUAD_0E_3V
+int refquad_0e_3v_splitedges[][3] =
+{
+  { 1, 2, 5 },
+  { 1, 4, 6 },
+  { 2, 1, 7 },
+  { 2, 3, 8 },
+  { 3, 2, 9 },
+  { 3, 4, 10 },
+  { 0, 0, 0 }
+};
+
+int refquad_0e_3v_splitfaces[][4] =
+{
+  { 2, 3, 1, 14 },
+  { 0, 0, 0, 0 },
+};
+
+HPREF_ELEMENT_TYPE refquad_0e_3v_newelstypes[] =
+{
+  HP_TRIG_SINGCORNER,
+  HP_DUMMY_QUAD_SINGCORNER,
+  HP_TRIG_SINGCORNER,
+  HP_QUAD,
+  HP_QUAD,
+  HP_QUAD,
+  HP_NONE,
+};
+int refquad_0e_3v_newels[][8] =
+{
+  { 1, 5, 6 },
+  { 2, 8, 14, 7 },
+  { 3, 10, 9 },
+  { 5, 7, 14, 6 },
+  { 8, 9, 10, 14 },
+  { 6, 14, 10, 4 },
+};
+HPRef_Struct refquad_0e_3v =
+{
+  HP_QUAD,
+  refquad_0e_3v_splitedges, 
+  refquad_0e_3v_splitfaces, 
+  0,
+  refquad_0e_3v_newelstypes, 
+  refquad_0e_3v_newels
+};
+
+
+
+
+// HP_QUAD_0E_4V
+int refquad_0e_4v_splitedges[][3] =
+{
+  { 1, 2, 5 },
+  { 1, 4, 6 },
+  { 2, 1, 7 },
+  { 2, 3, 8 },
+  { 3, 2, 9 },
+  { 3, 4, 10 },
+  { 4, 1, 11 },
+  { 4, 3, 12 },
+  { 0, 0, 0 }
+};
+
+int refquad_0e_4v_splitfaces[][4] =
+{
+  { 1, 2, 4, 13 },
+  { 2, 3, 1, 14 },
+  { 3, 4, 2, 15 },
+  { 4, 1, 3, 16 },
+  { 0, 0, 0, 0 },
+};
+
+HPREF_ELEMENT_TYPE refquad_0e_4v_newelstypes[] =
+{
+  HP_DUMMY_QUAD_SINGCORNER,
+  HP_DUMMY_QUAD_SINGCORNER,
+  HP_DUMMY_QUAD_SINGCORNER,
+  HP_DUMMY_QUAD_SINGCORNER,
+
+  HP_QUAD,
+  HP_QUAD,
+  HP_QUAD,
+  HP_QUAD,
+
+  HP_QUAD,
+  HP_NONE,
+};
+int refquad_0e_4v_newels[][8] =
+{
+  { 1, 5, 13, 6 },
+  { 2, 8, 14, 7 },
+  { 3, 10, 15, 9 },
+  { 4, 11, 16, 12 },
+  { 5, 7, 14, 13 },
+  { 8, 9, 15, 14 },
+  { 10, 12, 16, 15 },
+  { 11, 6, 13, 16 },
+  { 13, 14, 15, 16 }
+};
+HPRef_Struct refquad_0e_4v =
+{
+  HP_QUAD,
+  refquad_0e_4v_splitedges, 
+  refquad_0e_4v_splitfaces, 
+  0,
+  refquad_0e_4v_newelstypes, 
+  refquad_0e_4v_newels
+};
+
+
+
+
+
+
+
+
+// HP_QUAD_1E_1VA
+int refquad_1e_1va_splitedges[][3] =
+{
+  { 1, 4, 5 },
+  { 2, 3, 6 },
+  { 1, 2, 7 },
+  { 0, 0, 0 }
+};
+HPREF_ELEMENT_TYPE refquad_1e_1va_newelstypes[] =
+{
+  HP_QUAD_SINGEDGE,
+  HP_QUAD,
+  HP_TRIG_SINGEDGECORNER1,
+  HP_NONE,
+};
+int refquad_1e_1va_newels[][8] =
+{
+  { 7, 2, 6, 5 },
+  { 5, 6, 3, 4 },
+  { 1, 7, 5 },
+};
+HPRef_Struct refquad_1e_1va =
+{
+  HP_QUAD,
+  refquad_1e_1va_splitedges, 
+  0, 0,
+  refquad_1e_1va_newelstypes, 
+  refquad_1e_1va_newels
+};
+
+
+
+
+// HP_QUAD_1E_1VB
+int refquad_1e_1vb_splitedges[][3] =
+{
+  { 1, 4, 5 },
+  { 2, 3, 6 },
+  { 2, 1, 7 },
+  { 0, 0, 0 }
+};
+HPREF_ELEMENT_TYPE refquad_1e_1vb_newelstypes[] =
+{
+  HP_QUAD_SINGEDGE,
+  HP_QUAD,
+  HP_TRIG_SINGEDGECORNER2,
+  HP_NONE,
+};
+int refquad_1e_1vb_newels[][8] =
+{
+  { 1, 7, 6, 5 },
+  { 5, 6, 3, 4 },
+  { 7, 2, 6 },
+};
+HPRef_Struct refquad_1e_1vb =
+{
+  HP_QUAD,
+  refquad_1e_1vb_splitedges, 
+  0, 0,
+  refquad_1e_1vb_newelstypes, 
+  refquad_1e_1vb_newels
+};
+
+
+
+// HP_QUAD_1E_1VC
+int refquad_1e_1vc_splitedges[][3] =
+{
+  { 1, 4, 5 },
+  { 2, 3, 6 },
+  { 3, 2, 7 },
+  { 3, 4, 8 },
+  { 0, 0, 0 }
+};
+HPREF_ELEMENT_TYPE refquad_1e_1vc_newelstypes[] =
+{
+  HP_QUAD_SINGEDGE,
+  HP_TRIG,
+  HP_QUAD,
+  HP_TRIG_SINGCORNER,
+  HP_NONE,
+};
+int refquad_1e_1vc_newels[][8] =
+{
+  { 1, 2, 6, 5 },
+  { 5, 6, 4 },
+  { 4, 6, 7, 8 },
+  { 3, 8, 7 }
+};
+HPRef_Struct refquad_1e_1vc =
+{
+  HP_QUAD,
+  refquad_1e_1vc_splitedges, 
+  0, 0,
+  refquad_1e_1vc_newelstypes, 
+  refquad_1e_1vc_newels
+};
+
+
+
+// HP_QUAD_1E_1VD
+int refquad_1e_1vd_splitedges[][3] =
+{
+  { 1, 4, 5 },
+  { 2, 3, 6 },
+  { 4, 1, 7 },
+  { 4, 3, 8 },
+  { 0, 0, 0 }
+};
+HPREF_ELEMENT_TYPE refquad_1e_1vd_newelstypes[] =
+{
+  HP_QUAD_SINGEDGE,
+  HP_TRIG,
+  HP_QUAD,
+  HP_TRIG_SINGCORNER,
+  HP_NONE,
+};
+int refquad_1e_1vd_newels[][8] =
+{
+  { 1, 2, 6, 5 },
+  { 5, 6, 3 },
+  { 5, 3, 8, 7 },
+  { 4, 7, 8 }
+};
+HPRef_Struct refquad_1e_1vd =
+{
+  HP_QUAD,
+  refquad_1e_1vd_splitedges, 
+  0, 0,
+  refquad_1e_1vd_newelstypes, 
+  refquad_1e_1vd_newels
+};
+
+
+
+
+
+
+
+// HP_QUAD_1E_2VA
+int refquad_1e_2va_splitedges[][3] =
+{
+  { 1, 4, 5 },
+  { 2, 3, 6 },
+  { 1, 2, 7 },
+  { 2, 1, 8 },
+  { 0, 0, 0 }
+};
+HPREF_ELEMENT_TYPE refquad_1e_2va_newelstypes[] =
+{
+  HP_QUAD_SINGEDGE,
+  HP_QUAD,
+  HP_TRIG_SINGEDGECORNER1,
+  HP_TRIG_SINGEDGECORNER2,
+  HP_NONE,
+};
+int refquad_1e_2va_newels[][8] =
+{
+  { 7, 8, 6, 5 },
+  { 5, 6, 3, 4 },
+  { 1, 7, 5 },
+  { 8, 2, 6 }
+};
+HPRef_Struct refquad_1e_2va =
+{
+  HP_QUAD,
+  refquad_1e_2va_splitedges, 
+  0, 0,
+  refquad_1e_2va_newelstypes, 
+  refquad_1e_2va_newels
+};
+
+
+
+
+// HP_QUAD_1E_2VB
+int refquad_1e_2vb_splitedges[][3] =
+{
+  { 1, 4, 5 },
+  { 2, 3, 6 },
+  { 1, 2, 7 },
+  { 3, 2, 8 },
+  { 3, 4, 9 },
+  { 0, 0, 0 }
+};
+HPREF_ELEMENT_TYPE refquad_1e_2vb_newelstypes[] =
+{
+  HP_QUAD_SINGEDGE,
+  HP_TRIG_SINGEDGECORNER1,
+  HP_TRIG,
+  HP_QUAD,
+  HP_TRIG_SINGCORNER,
+  HP_NONE,
+};
+int refquad_1e_2vb_newels[][8] =
+{
+  { 7, 2, 6, 5 },
+  { 1, 7, 5 },
+  { 5, 6, 4 },
+  { 4, 6, 8, 9 },
+  { 3, 9, 8 }
+};
+HPRef_Struct refquad_1e_2vb =
+{
+  HP_QUAD,
+  refquad_1e_2vb_splitedges, 
+  0, 0,
+  refquad_1e_2vb_newelstypes, 
+  refquad_1e_2vb_newels
+};
+
+
+
+
+// HP_QUAD_1E_2VC
+int refquad_1e_2vc_splitedges[][3] =
+{
+  { 1, 4, 5 },
+  { 2, 3, 6 },
+  { 1, 2, 7 },
+  { 4, 1, 8 },
+  { 4, 3, 9 },
+  { 0, 0, 0 }
+};
+HPREF_ELEMENT_TYPE refquad_1e_2vc_newelstypes[] =
+{
+  HP_QUAD_SINGEDGE,
+  HP_TRIG_SINGEDGECORNER1,
+  HP_TRIG,
+  HP_QUAD,
+  HP_TRIG_SINGCORNER,
+  HP_NONE,
+};
+int refquad_1e_2vc_newels[][8] =
+{
+  { 7, 2, 6, 5 },
+  { 1, 7, 5 },
+  { 5, 6, 3 },
+  { 5, 3, 9, 8 },
+  { 4, 8, 9 }
+};
+HPRef_Struct refquad_1e_2vc =
+{
+  HP_QUAD,
+  refquad_1e_2vc_splitedges, 
+  0, 0,
+  refquad_1e_2vc_newelstypes, 
+  refquad_1e_2vc_newels
+};
+
+
+
+
+// HP_QUAD_1E_2VD
+int refquad_1e_2vd_splitedges[][3] =
+{
+  { 1, 4, 5 },
+  { 2, 3, 6 },
+  { 2, 1, 7 },
+  { 3, 2, 8 },
+  { 3, 4, 9 },
+  { 0, 0, 0 }
+};
+HPREF_ELEMENT_TYPE refquad_1e_2vd_newelstypes[] =
+{
+  HP_QUAD_SINGEDGE,
+  HP_TRIG_SINGEDGECORNER2,
+  HP_TRIG,
+  HP_QUAD,
+  HP_TRIG_SINGCORNER,
+  HP_NONE,
+};
+int refquad_1e_2vd_newels[][8] =
+{
+  { 1, 7, 6, 5 },
+  { 7, 2, 6 },
+  { 5, 6, 4 },
+  { 4, 6, 8, 9 },
+  { 3, 9, 8 }
+};
+HPRef_Struct refquad_1e_2vd =
+{
+  HP_QUAD,
+  refquad_1e_2vd_splitedges, 
+  0, 0,
+  refquad_1e_2vd_newelstypes, 
+  refquad_1e_2vd_newels
+};
+
+
+
+
+
+// HP_QUAD_1E_2VE
+int refquad_1e_2ve_splitedges[][3] =
+{
+  { 1, 4, 5 },
+  { 2, 3, 6 },
+  { 2, 1, 7 },
+  { 4, 1, 8 },
+  { 4, 3, 9 },
+  { 0, 0, 0 }
+};
+HPREF_ELEMENT_TYPE refquad_1e_2ve_newelstypes[] =
+{
+  HP_QUAD_SINGEDGE,
+  HP_TRIG_SINGEDGECORNER2,
+  HP_TRIG,
+  HP_QUAD,
+  HP_TRIG_SINGCORNER,
+  HP_NONE,
+};
+int refquad_1e_2ve_newels[][8] =
+{
+  { 1, 7, 6, 5 },
+  { 7, 2, 6 },
+  { 5, 6, 3 },
+  { 5, 3, 9, 8 },
+  { 4, 8, 9 }
+};
+HPRef_Struct refquad_1e_2ve =
+{
+  HP_QUAD,
+  refquad_1e_2ve_splitedges, 
+  0, 0,
+  refquad_1e_2ve_newelstypes, 
+  refquad_1e_2ve_newels
+};
+
+
+
+
+
+
+// HP_QUAD_1E_2VF
+int refquad_1e_2vf_splitedges[][3] =
+{
+  { 1, 4, 5 },
+  { 2, 3, 6 },
+  { 4, 1, 7 },
+  { 4, 3, 8 },
+  { 3, 2, 9 },
+  { 3, 4, 10 },
+  { 0, 0, 0 }
+};
+HPREF_ELEMENT_TYPE refquad_1e_2vf_newelstypes[] =
+{
+  HP_QUAD_SINGEDGE,
+  HP_QUAD,
+  HP_QUAD,
+  HP_TRIG_SINGCORNER,
+  HP_TRIG_SINGCORNER,
+  HP_NONE,
+};
+int refquad_1e_2vf_newels[][8] =
+{
+  { 1, 2, 6, 5 },
+  { 5, 6, 9, 7 },
+  { 7, 9, 10, 8 },
+  { 4, 7, 8 },
+  { 3, 10, 9 },
+};
+HPRef_Struct refquad_1e_2vf =
+{
+  HP_QUAD,
+  refquad_1e_2vf_splitedges, 
+  0, 0,
+  refquad_1e_2vf_newelstypes, 
+  refquad_1e_2vf_newels
+};
+
+
+
+
+
+// HP_QUAD_1E_3VA
+int refquad_1e_3va_splitedges[][3] =
+{
+  { 1, 4, 5 },
+  { 2, 3, 6 },
+  { 1, 2, 7 },
+  { 2, 1, 8 },
+  { 3, 2, 9 },
+  { 3, 4, 10 },
+  { 0, 0, 0 }
+};
+HPREF_ELEMENT_TYPE refquad_1e_3va_newelstypes[] =
+{
+  HP_TRIG_SINGEDGECORNER1,
+  HP_TRIG_SINGEDGECORNER2,
+  HP_TRIG_SINGCORNER,
+  HP_QUAD_SINGEDGE,
+  HP_QUAD,
+  HP_TRIG,
+  HP_NONE,
+};
+int refquad_1e_3va_newels[][8] =
+{
+  { 1, 7, 5 },
+  { 8, 2, 6 },
+  { 3, 10, 9 },
+  { 7, 8, 6, 5 },
+  { 4, 6, 9, 10 },
+  { 5, 6, 4 }
+};
+HPRef_Struct refquad_1e_3va =
+{
+  HP_QUAD,
+  refquad_1e_3va_splitedges, 
+  0, 0,
+  refquad_1e_3va_newelstypes, 
+  refquad_1e_3va_newels
+};
+
+
+
+
+
+// HP_QUAD_1E_3VB
+int refquad_1e_3vb_splitedges[][3] =
+{
+  { 1, 4, 5 },
+  { 2, 3, 6 },
+  { 1, 2, 7 },
+  { 2, 1, 8 },
+  { 4, 1, 9 },
+  { 4, 3, 10 },
+  { 0, 0, 0 }
+};
+HPREF_ELEMENT_TYPE refquad_1e_3vb_newelstypes[] =
+{
+  HP_TRIG_SINGEDGECORNER1,
+  HP_TRIG_SINGEDGECORNER2,
+  HP_TRIG_SINGCORNER,
+  HP_QUAD_SINGEDGE,
+  HP_QUAD,
+  HP_TRIG,
+  HP_NONE,
+};
+int refquad_1e_3vb_newels[][8] =
+{
+  { 1, 7, 5 },
+  { 8, 2, 6 },
+  { 4, 9, 10 },
+  { 7, 8, 6, 5 },
+  { 5, 3, 10, 9 },
+  { 5, 6, 3 }
+};
+HPRef_Struct refquad_1e_3vb =
+{
+  HP_QUAD,
+  refquad_1e_3vb_splitedges, 
+  0, 0,
+  refquad_1e_3vb_newelstypes, 
+  refquad_1e_3vb_newels
+};
+
+
+
+
+
+// HP_QUAD_1E_3VC
+int refquad_1e_3vc_splitedges[][3] =
+{
+  { 1, 4, 5 },
+  { 2, 3, 6 },
+  { 1, 2, 7 },
+  { 3, 2, 8 },
+  { 3, 4, 9 },
+  { 4, 3, 10 },
+  { 4, 1, 11 },
+  { 0, 0, 0 }
+};
+HPREF_ELEMENT_TYPE refquad_1e_3vc_newelstypes[] =
+{
+  HP_TRIG_SINGEDGECORNER1,
+  HP_TRIG_SINGCORNER,
+  HP_TRIG_SINGCORNER,
+  HP_QUAD_SINGEDGE,
+  HP_QUAD,
+  HP_QUAD,
+  HP_NONE,
+};
+int refquad_1e_3vc_newels[][8] =
+{
+  { 1, 7, 5 },
+  { 3, 9, 8 },
+  { 4, 11, 10 },
+  { 7, 2, 6, 5 },
+  { 5, 6, 8, 11 },
+  { 11, 8, 9, 10 }
+};
+HPRef_Struct refquad_1e_3vc =
+{
+  HP_QUAD,
+  refquad_1e_3vc_splitedges, 
+  0, 0,
+  refquad_1e_3vc_newelstypes, 
+  refquad_1e_3vc_newels
+};
+
+
+
+
+// HP_QUAD_1E_3VD
+int refquad_1e_3vd_splitedges[][3] =
+{
+  { 1, 4, 5 },
+  { 2, 3, 6 },
+  { 2, 1, 7 },
+  { 3, 2, 8 },
+  { 3, 4, 9 },
+  { 4, 3, 10 },
+  { 4, 1, 11 },
+  { 0, 0, 0 }
+};
+HPREF_ELEMENT_TYPE refquad_1e_3vd_newelstypes[] =
+{
+  HP_TRIG_SINGEDGECORNER2,
+  HP_TRIG_SINGCORNER,
+  HP_TRIG_SINGCORNER,
+  HP_QUAD_SINGEDGE,
+  HP_QUAD,
+  HP_QUAD,
+  HP_NONE,
+};
+int refquad_1e_3vd_newels[][8] =
+{
+  { 7, 2, 6 },
+  { 3, 9, 8 },
+  { 4, 11, 10 },
+  { 1, 7, 6, 5 },
+  { 5, 6, 8, 11 },
+  { 11, 8, 9, 10 }
+};
+HPRef_Struct refquad_1e_3vd =
+{
+  HP_QUAD,
+  refquad_1e_3vd_splitedges, 
+  0, 0,
+  refquad_1e_3vd_newelstypes, 
+  refquad_1e_3vd_newels
+};
+
+
+
+
+
+
+// HP_QUAD_1E_4V
+int refquad_1e_4v_splitedges[][3] =
+{
+  { 1, 4, 5 },
+  { 2, 3, 6 },
+  { 1, 2, 7 },
+  { 2, 1, 8 },
+  { 4, 1, 9 },
+  { 3, 2, 10 },
+  { 4, 3, 11 },
+  { 3, 4, 12 },
+  { 0, 0, 0 }
+};
+HPREF_ELEMENT_TYPE refquad_1e_4v_newelstypes[] =
+{
+  HP_TRIG_SINGEDGECORNER1,
+  HP_TRIG_SINGEDGECORNER2,
+  HP_TRIG_SINGCORNER,
+  HP_TRIG_SINGCORNER,
+  HP_QUAD_SINGEDGE,
+  HP_QUAD,
+  HP_QUAD,
+  HP_NONE,
+};
+int refquad_1e_4v_newels[][8] =
+{
+  { 1, 7, 5 },
+  { 8, 2, 6 },
+  { 3, 12, 10 },
+  { 4, 9, 11 },
+  { 7, 8, 6, 5 },
+  { 5, 6, 10, 9 },
+  { 9, 10, 12, 11 }
+};
+HPRef_Struct refquad_1e_4v =
+{
+  HP_QUAD,
+  refquad_1e_4v_splitedges, 
+  0, 0,
+  refquad_1e_4v_newelstypes, 
+  refquad_1e_4v_newels
+};
+
+////////////////////////////////////////////////////////////////////////////////
+
+// HP_QUAD_2E
+int refquad_2e_splitedges[][3] =
+{
+  { 1, 2, 5 },
+  { 1, 4, 6 },
+  { 2, 3, 7 },
+  { 4, 3, 8 },
+  { 0, 0, 0 }
+};
+int refquad_2e_splitfaces[][4] =
+{
+  { 1, 2, 4, 9 },
+  { 0, 0, 0, 0 },
+};
+
+
+/* 
+   HPREF_ELEMENT_TYPE refquad_2e_newelstypes[] =
+{
+  HP_TRIG_SINGEDGECORNER1,
+  HP_TRIG_SINGEDGECORNER2,
+  HP_QUAD_SINGEDGE,
+  HP_QUAD_SINGEDGE,
+  HP_QUAD,
+  HP_NONE,
+};
+int refquad_2e_newels[][8] =
+{
+  { 1, 5, 9 },
+  { 6, 1, 9 },
+  { 5, 2, 7, 9 },
+  { 4, 6, 9, 8 },
+  { 9, 7, 3, 8 },
+};
+*/ 
+
+// SZ refine to 4 quads 
+HPREF_ELEMENT_TYPE refquad_2e_newelstypes[] =
+{
+  HP_QUAD_2E,
+  HP_QUAD_SINGEDGE,
+  HP_QUAD_SINGEDGE,
+  HP_QUAD,
+  HP_NONE,
+};
+int refquad_2e_newels[][8] =
+{
+  { 1, 5, 9, 6 },
+  { 5, 2, 7, 9 },
+  { 4, 6, 9, 8 },
+  { 9, 7, 3, 8 },
+};
+
+HPRef_Struct refquad_2e =
+{
+  HP_QUAD,
+  refquad_2e_splitedges, 
+  refquad_2e_splitfaces, 
+  0,
+  refquad_2e_newelstypes, 
+  refquad_2e_newels
+};
+
+
+// HP_QUAD_2E_1VA
+int refquad_2e_1va_splitedges[][3] =
+{
+  { 1, 2, 5 },
+  { 1, 4, 6 },
+  { 2, 3, 7 },
+  { 4, 3, 8 },
+  { 2, 1, 10 },
+  { 0, 0, 0 }
+};
+int refquad_2e_1va_splitfaces[][4] =
+{
+  { 1, 2, 4, 9 },
+  { 0, 0, 0, 0 },
+};
+
+/* 
+HPREF_ELEMENT_TYPE refquad_2e_1va_newelstypes[] =
+{
+  HP_TRIG_SINGEDGECORNER1,
+  HP_TRIG_SINGEDGECORNER2,
+  HP_QUAD_SINGEDGE,
+  HP_QUAD_SINGEDGE,
+  HP_QUAD,
+  HP_TRIG_SINGEDGECORNER2,
+  HP_NONE,
+};
+int refquad_2e_1va_newels[][8] =
+{
+  { 1, 5, 9 },
+  { 6, 1, 9 },
+  { 5, 10, 7, 9 },
+  { 4, 6, 9, 8 },
+  { 9, 7, 3, 8 },
+  { 10, 2, 7 },
+};
+*/ 
+// SZ Quad_2e refinement 
+HPREF_ELEMENT_TYPE refquad_2e_1va_newelstypes[] =
+{
+  HP_QUAD_2E,
+  HP_QUAD_SINGEDGE,
+  HP_QUAD_SINGEDGE,
+  HP_QUAD,
+  HP_TRIG_SINGEDGECORNER2,
+  HP_NONE,
+};
+int refquad_2e_1va_newels[][8] =
+{
+  { 1, 5, 9, 6 },
+  { 5, 10, 7, 9 },
+  { 4, 6, 9, 8 },
+  { 9, 7, 3, 8 },
+  { 10, 2, 7 },
+};
+
+HPRef_Struct refquad_2e_1va =
+{
+  HP_QUAD,
+  refquad_2e_1va_splitedges, 
+  refquad_2e_1va_splitfaces, 
+  0,
+  refquad_2e_1va_newelstypes, 
+  refquad_2e_1va_newels
+};
+
+
+
+// HP_QUAD_2E_1VB
+int refquad_2e_1vb_splitedges[][3] =
+{
+  { 1, 2, 5 },
+  { 1, 4, 6 },
+  { 2, 3, 7 },
+  { 4, 3, 8 },
+  { 3, 2, 10 },
+  { 3, 4, 11 },
+  { 0, 0, 0 }
+};
+int refquad_2e_1vb_splitfaces[][4] =
+{
+  { 1, 2, 4, 9 },
+  { 0, 0, 0, 0 },
+};
+HPREF_ELEMENT_TYPE refquad_2e_1vb_newelstypes[] =
+{
+  // HP_TRIG_SINGEDGECORNER1,
+  // HP_TRIG_SINGEDGECORNER2,
+  // SZ QUAD_2E 
+  HP_QUAD_2E,
+  HP_QUAD_SINGEDGE,
+  HP_QUAD_SINGEDGE,
+  HP_TRIG,
+  HP_QUAD,
+  HP_TRIG_SINGCORNER,
+  HP_NONE,
+};
+int refquad_2e_1vb_newels[][8] =
+{
+  //{ 1, 5, 9 },
+  //{ 6, 1, 9 },
+  { 1, 5, 9, 6 },
+  { 5, 2, 7, 9 },
+  { 4, 6, 9, 8 },
+  { 7, 8, 9 },
+  { 8, 7, 10, 11 },
+  { 3, 11, 10 }
+};
+HPRef_Struct refquad_2e_1vb =
+{
+  HP_QUAD,
+  refquad_2e_1vb_splitedges, 
+  refquad_2e_1vb_splitfaces, 
+  0,
+  refquad_2e_1vb_newelstypes, 
+  refquad_2e_1vb_newels
+}
+;
+
+// HP_QUAD_2E_1VC
+int refquad_2e_1vc_splitedges[][3] =
+{
+  { 1, 2, 5 },
+  { 1, 4, 6 },
+  { 2, 3, 7 },
+  { 4, 1, 8 },
+  { 4, 3, 9 },
+  { 0, 0, 0 }
+};
+int refquad_2e_1vc_splitfaces[][4] =
+{
+  { 1, 2, 4, 10 },
+  { 0, 0, 0, 0 },
+};
+HPREF_ELEMENT_TYPE refquad_2e_1vc_newelstypes[] =
+{
+  //  HP_TRIG_SINGEDGECORNER1,
+  // HP_TRIG_SINGEDGECORNER2,
+  HP_QUAD_2E, 
+  HP_TRIG_SINGEDGECORNER1,
+  HP_QUAD_SINGEDGE,
+  HP_QUAD_SINGEDGE,
+  HP_QUAD,
+  HP_NONE,
+};
+int refquad_2e_1vc_newels[][8] =
+{
+  //{ 1, 5, 10 },
+  //{ 6, 1, 10 },
+  { 1, 5, 10, 6}, 
+  { 4, 8, 9 },
+  { 5, 2, 7, 10 },
+  { 8, 6, 10, 9 },
+  { 10, 7, 3, 9 },
+};
+HPRef_Struct refquad_2e_1vc =
+{
+  HP_QUAD,
+  refquad_2e_1vc_splitedges, 
+  refquad_2e_1vc_splitfaces, 
+  0,
+  refquad_2e_1vc_newelstypes, 
+  refquad_2e_1vc_newels
+};
+
+// HP_QUAD_2E_2VA
+int refquad_2e_2va_splitedges[][3] =
+{
+  { 1, 2, 5 },
+  { 1, 4, 6 },
+  { 2, 3, 7 },
+  { 4, 3, 8 },
+  { 3, 2, 10 },
+  { 3, 4, 11 },
+  { 2, 1, 12 },
+  { 0, 0, 0 }
+};
+int refquad_2e_2va_splitfaces[][4] =
+{
+  { 1, 2, 4, 9 },
+  { 0, 0, 0, 0 },
+};
+HPREF_ELEMENT_TYPE refquad_2e_2va_newelstypes[] =
+{
+  //HP_TRIG_SINGEDGECORNER1,
+  //HP_TRIG_SINGEDGECORNER2,
+  HP_QUAD_2E,
+  HP_QUAD_SINGEDGE,
+  HP_QUAD_SINGEDGE,
+  HP_TRIG,
+  HP_QUAD,
+  HP_TRIG_SINGCORNER,
+  HP_TRIG_SINGEDGECORNER2,
+  HP_NONE,
+};
+int refquad_2e_2va_newels[][8] =
+{
+  // { 1, 5, 9 },
+  // { 6, 1, 9 },
+  { 1, 5, 9, 6 }, 
+  { 5, 12, 7, 9 },
+  { 4, 6, 9, 8 },
+  { 7, 8, 9 },
+  { 8, 7, 10, 11 },
+  { 3, 11, 10 },
+  { 12, 2, 7 }
+};
+HPRef_Struct refquad_2e_2va =
+{
+  HP_QUAD,
+  refquad_2e_2va_splitedges, 
+  refquad_2e_2va_splitfaces, 
+  0,
+  refquad_2e_2va_newelstypes, 
+  refquad_2e_2va_newels
+};
+
+
+
+
+
+
+// HP_QUAD_2E_2VB
+int refquad_2e_2vb_splitedges[][3] =
+{
+  { 1, 2, 5 },
+  { 1, 4, 6 },
+  { 2, 1, 7 },
+  { 2, 3, 8 },
+  { 4, 1, 9 },
+  { 4, 3, 10 },
+  { 0, 0, 0 }
+};
+int refquad_2e_2vb_splitfaces[][4] =
+{
+  { 1, 2, 4, 11 },
+  { 0, 0, 0, 0 },
+};
+HPREF_ELEMENT_TYPE refquad_2e_2vb_newelstypes[] =
+{
+  // HP_TRIG_SINGEDGECORNER1,
+  // HP_TRIG_SINGEDGECORNER2,
+  HP_QUAD_2E, 
+  HP_TRIG_SINGEDGECORNER1,
+  HP_TRIG_SINGEDGECORNER2,
+  HP_QUAD_SINGEDGE,
+  HP_QUAD_SINGEDGE,
+  HP_QUAD,
+  HP_NONE,
+};
+int refquad_2e_2vb_newels[][8] =
+{
+  //{ 1, 5, 11 },
+  //{ 6, 1, 11 },
+  { 1, 5, 11, 6 }, 
+  { 4, 9, 10 },
+  { 7, 2, 8 },
+  { 5, 7, 8, 11 },
+  { 9, 6, 11, 10 },
+  { 3, 10, 11, 8 },
+};
+HPRef_Struct refquad_2e_2vb =
+{
+  HP_QUAD,
+  refquad_2e_2vb_splitedges, 
+  refquad_2e_2vb_splitfaces, 
+  0,
+  refquad_2e_2vb_newelstypes, 
+  refquad_2e_2vb_newels
+};
+
+// HP_QUAD_2E_2VC
+int refquad_2e_2vc_splitedges[][3] =
+{
+  { 1, 2, 5 },
+  { 1, 4, 6 },
+  { 2, 3, 7 },
+  { 4, 3, 8 },
+  { 3, 2, 10 },
+  { 3, 4, 11 },
+  { 4, 1, 12 },
+  { 0, 0, 0 }
+};
+int refquad_2e_2vc_splitfaces[][4] =
+{
+  { 1, 2, 4, 9 },
+  { 0, 0, 0, 0 },
+};
+HPREF_ELEMENT_TYPE refquad_2e_2vc_newelstypes[] =
+{
+  // HP_TRIG_SINGEDGECORNER1,
+  // HP_TRIG_SINGEDGECORNER2,
+  HP_QUAD_2E, 
+  HP_QUAD_SINGEDGE,
+  HP_QUAD_SINGEDGE,
+  HP_TRIG,
+  HP_QUAD,
+  HP_TRIG_SINGCORNER,
+  HP_TRIG_SINGEDGECORNER1, //SZ (vorher: SINGEDGECORNER2) 
+  HP_NONE,
+};
+int refquad_2e_2vc_newels[][8] =
+{
+  { 1, 5, 9 },
+  { 6, 1, 9 },
+  { 5, 2, 7, 9 },
+  { 12, 6, 9, 8 },
+  { 7, 8, 9 },
+  { 8, 7, 10, 11 },
+  { 3, 11, 10 },
+  { 4, 12, 8 }
+};
+HPRef_Struct refquad_2e_2vc =
+{
+  HP_QUAD,
+  refquad_2e_2vc_splitedges, 
+  refquad_2e_2vc_splitfaces, 
+  0,
+  refquad_2e_2vc_newelstypes, 
+  refquad_2e_2vc_newels
+};
+
+// HP_QUAD_2E_3V  
+int refquad_2e_3v_splitedges[][3] =
+{
+  { 1, 2, 5 },
+  { 1, 4, 6 },
+  { 2, 3, 7 },
+  { 4, 3, 8 },
+  { 3, 2, 10 },
+  { 3, 4, 11 },
+  { 2, 1, 12 },
+  { 4, 1, 13 },
+  { 0, 0, 0 }
+};
+int refquad_2e_3v_splitfaces[][4] =
+{
+  { 1, 2, 4, 9 },
+  { 0, 0, 0, 0 },
+};
+HPREF_ELEMENT_TYPE refquad_2e_3v_newelstypes[] =
+{
+  // HP_TRIG_SINGEDGECORNER1,
+  // HP_TRIG_SINGEDGECORNER2,
+  HP_QUAD_2E, 
+  HP_QUAD_SINGEDGE,
+  HP_QUAD_SINGEDGE,
+  HP_TRIG,
+  HP_QUAD,
+  HP_TRIG_SINGCORNER,
+  HP_TRIG_SINGEDGECORNER2,
+  HP_TRIG_SINGEDGECORNER1,
+  HP_NONE,
+};
+int refquad_2e_3v_newels[][8] =
+{
+  //{ 1, 5, 9 },
+  //{ 6, 1, 9 },
+  { 1, 5, 9, 6 }, 
+  { 5, 12, 7, 9 },
+  { 13, 6, 9, 8 },
+  { 7, 8, 9 },
+  { 8, 7, 10, 11 },
+  { 3, 11, 10 },
+  { 12, 2, 7 },
+  { 4, 13, 8 }
+};
+HPRef_Struct refquad_2e_3v =
+{
+  HP_QUAD,
+  refquad_2e_3v_splitedges, 
+  refquad_2e_3v_splitfaces, 
+  0,
+  refquad_2e_3v_newelstypes, 
+  refquad_2e_3v_newels
+};
+
+// HP_QUAD_2EB_0V
+int refquad_2eb_0v_splitedges[][3] =
+{
+  { 1, 4, 5 },
+  { 2, 3, 6 },
+  { 3, 2, 7 },
+  { 4, 1, 8 },
+  { 0, 0, 0 }
+};
+int refquad_2eb_0v_splitfaces[][4] =
+{
+  { 0, 0, 0, 0 },
+};
+HPREF_ELEMENT_TYPE refquad_2eb_0v_newelstypes[] =
+{
+  HP_QUAD_SINGEDGE,
+  HP_QUAD_SINGEDGE,
+  HP_QUAD,
+  HP_NONE,
+};
+int refquad_2eb_0v_newels[][8] =
+{
+  { 1, 2, 6, 5 },
+  { 3, 4, 8, 7 },
+  { 5, 6, 7, 8 }
+};
+HPRef_Struct refquad_2eb_0v =
+{
+  HP_QUAD,
+  refquad_2eb_0v_splitedges, 
+  refquad_2eb_0v_splitfaces, 
+  0,
+  refquad_2eb_0v_newelstypes, 
+  refquad_2eb_0v_newels
+};
+
+
+// HP_QUAD_2EB_1VA
+int refquad_2eb_1va_splitedges[][3] =
+{
+  { 1, 4, 5 },
+  { 2, 3, 6 },
+  { 3, 2, 7 },
+  { 4, 1, 8 },
+  { 1, 2, 9 },
+  { 0, 0, 0 }
+};
+int refquad_2eb_1va_splitfaces[][4] =
+{
+  { 0, 0, 0, 0 },
+};
+HPREF_ELEMENT_TYPE refquad_2eb_1va_newelstypes[] =
+{
+  HP_QUAD_SINGEDGE,
+  HP_QUAD_SINGEDGE,
+  HP_TRIG_SINGEDGECORNER1,
+  HP_QUAD,
+  HP_NONE,
+};
+int refquad_2eb_1va_newels[][8] =
+{
+  { 9, 2, 6, 5 },
+  { 3, 4, 8, 7 },
+  { 1, 9, 5 },
+  { 5, 6, 7, 8 }
+};
+HPRef_Struct refquad_2eb_1va =
+{
+  HP_QUAD,
+  refquad_2eb_1va_splitedges, 
+  refquad_2eb_1va_splitfaces, 
+  0,
+  refquad_2eb_1va_newelstypes, 
+  refquad_2eb_1va_newels
+};
+
+// HP_QUAD_2EB_1VB
+int refquad_2eb_1vb_splitedges[][3] =
+{
+  { 1, 4, 5 },
+  { 2, 3, 6 },
+  { 3, 2, 7 },
+  { 4, 1, 8 },
+  { 2, 1, 9 },
+  { 0, 0, 0 }
+};
+int refquad_2eb_1vb_splitfaces[][4] =
+{
+  { 0, 0, 0, 0 },
+};
+HPREF_ELEMENT_TYPE refquad_2eb_1vb_newelstypes[] =
+{
+  HP_QUAD_SINGEDGE,
+  HP_QUAD_SINGEDGE,
+  HP_TRIG_SINGEDGECORNER2,
+  HP_QUAD,
+  HP_NONE,
+};
+int refquad_2eb_1vb_newels[][8] =
+{
+  { 1, 9, 6, 5 },
+  { 3, 4, 8, 7 },
+  { 9, 2, 6 },
+  { 5, 6, 7, 8 }
+};
+HPRef_Struct refquad_2eb_1vb =
+{
+  HP_QUAD,
+  refquad_2eb_1vb_splitedges, 
+  refquad_2eb_1vb_splitfaces, 
+  0,
+  refquad_2eb_1vb_newelstypes, 
+  refquad_2eb_1vb_newels
+};
+
+// HP_QUAD_2EB_2VA
+int refquad_2eb_2va_splitedges[][3] =
+{
+  { 1, 4, 5 },
+  { 2, 3, 6 },
+  { 3, 2, 7 },
+  { 4, 1, 8 },
+  { 1, 2, 9 },
+  { 2, 1, 10 },
+  { 0, 0, 0 }
+};
+HPREF_ELEMENT_TYPE refquad_2eb_2va_newelstypes[] =
+{
+  HP_QUAD_SINGEDGE,
+  HP_QUAD_SINGEDGE,
+  HP_TRIG_SINGEDGECORNER1,
+  HP_TRIG_SINGEDGECORNER2,
+  HP_QUAD,
+  HP_NONE,
+};
+int refquad_2eb_2va_newels[][8] =
+{
+  { 9, 10, 6, 5 },
+  { 3, 4, 8, 7 },
+  { 1, 9, 5 },
+  { 10, 2, 6 },
+  { 5, 6, 7, 8 }
+};
+HPRef_Struct refquad_2eb_2va =
+{
+  HP_QUAD,
+  refquad_2eb_2va_splitedges, 
+  0, 0,
+  refquad_2eb_2va_newelstypes, 
+  refquad_2eb_2va_newels
+};
+
+
+
+// HP_QUAD_2EB_2VB
+int refquad_2eb_2vb_splitedges[][3] =
+{
+  { 1, 4, 5 },
+  { 2, 3, 6 },
+  { 3, 2, 7 },
+  { 4, 1, 8 },
+  { 1, 2, 9 },
+  { 3, 4, 10 },
+  { 0, 0, 0 }
+};
+HPREF_ELEMENT_TYPE refquad_2eb_2vb_newelstypes[] =
+{
+  HP_QUAD_SINGEDGE,
+  HP_QUAD_SINGEDGE,
+  HP_TRIG_SINGEDGECORNER1,
+  HP_TRIG_SINGEDGECORNER1,
+  HP_QUAD,
+  HP_NONE,
+};
+int refquad_2eb_2vb_newels[][8] =
+{
+  { 9, 2, 6, 5 },
+  { 10, 4, 8, 7 },
+  { 1, 9, 5 },
+  { 3, 10, 7 },
+  { 5, 6, 7, 8 }
+};
+HPRef_Struct refquad_2eb_2vb =
+{
+  HP_QUAD,
+  refquad_2eb_2vb_splitedges, 
+  0, 0,
+  refquad_2eb_2vb_newelstypes, 
+  refquad_2eb_2vb_newels
+};
+
+
+
+// HP_QUAD_2EB_2VC
+int refquad_2eb_2vc_splitedges[][3] =
+{
+  { 1, 4, 5 },
+  { 2, 3, 6 },
+  { 3, 2, 7 },
+  { 4, 1, 8 },
+  { 1, 2, 9 },
+  { 4, 3, 10 },
+  { 0, 0, 0 }
+};
+int refquad_2eb_2vc_splitfaces[][4] =
+{
+  { 0, 0, 0, 0 },
+};
+HPREF_ELEMENT_TYPE refquad_2eb_2vc_newelstypes[] =
+{
+  HP_QUAD_SINGEDGE,
+  HP_QUAD_SINGEDGE,
+  HP_TRIG_SINGEDGECORNER1,
+  HP_TRIG_SINGEDGECORNER2,
+  HP_QUAD,
+  HP_NONE,
+};
+int refquad_2eb_2vc_newels[][8] =
+{
+  { 9, 2, 6, 5 },
+  { 3, 10, 8, 7 },
+  { 1, 9, 5 },
+  { 10, 4, 8 },
+  { 5, 6, 7, 8 }
+};
+HPRef_Struct refquad_2eb_2vc =
+{
+  HP_QUAD,
+  refquad_2eb_2vc_splitedges, 
+  refquad_2eb_2vc_splitfaces, 
+  0,
+  refquad_2eb_2vc_newelstypes, 
+  refquad_2eb_2vc_newels
+};
+
+
+// HP_QUAD_2EB_2VD
+int refquad_2eb_2vd_splitedges[][3] =
+{
+  { 1, 4, 5 },
+  { 2, 3, 6 },
+  { 3, 2, 7 },
+  { 4, 1, 8 },
+  { 2, 1, 9 },
+  { 4, 3, 10 },
+  { 0, 0, 0 }
+};
+HPREF_ELEMENT_TYPE refquad_2eb_2vd_newelstypes[] =
+{
+  HP_QUAD_SINGEDGE,
+  HP_QUAD_SINGEDGE,
+  HP_TRIG_SINGEDGECORNER2,
+  HP_TRIG_SINGEDGECORNER2,
+  HP_QUAD,
+  HP_NONE,
+};
+int refquad_2eb_2vd_newels[][8] =
+{
+  { 1, 9, 6, 5 },
+  { 3, 10, 8, 7 },
+  { 9, 2, 6 },
+  { 10, 4, 8 },
+  { 5, 6, 7, 8 }
+};
+HPRef_Struct refquad_2eb_2vd =
+{
+  HP_QUAD,
+  refquad_2eb_2vd_splitedges, 
+  0, 0,
+  refquad_2eb_2vd_newelstypes, 
+  refquad_2eb_2vd_newels
+};
+
+
+// HP_QUAD_2EB_3VA
+int refquad_2eb_3va_splitedges[][3] =
+{
+  { 1, 4, 5 },
+  { 2, 3, 6 },
+  { 1, 2, 7 },
+  { 2, 1, 8 },
+  { 3, 2, 9 },
+  { 4, 1, 10 },
+  { 3, 4, 11 },
+  { 0, 0, 0 }
+};
+HPREF_ELEMENT_TYPE refquad_2eb_3va_newelstypes[] =
+{
+  HP_TRIG_SINGEDGECORNER1,
+  HP_TRIG_SINGEDGECORNER2,
+  HP_TRIG_SINGEDGECORNER1,
+  HP_QUAD_SINGEDGE,
+  HP_QUAD_SINGEDGE,
+  HP_QUAD,
+  HP_NONE,
+};
+int refquad_2eb_3va_newels[][8] =
+{
+  { 1, 7, 5 },
+  { 8, 2, 6 },
+  { 3, 11, 9},
+  { 7, 8, 6, 5 },
+  { 11, 4, 10, 9 },
+  { 5, 6, 9, 10 }
+};
+HPRef_Struct refquad_2eb_3va =
+{
+  HP_QUAD,
+  refquad_2eb_3va_splitedges, 
+  0, 0,
+  refquad_2eb_3va_newelstypes, 
+  refquad_2eb_3va_newels
+};
+
+
+// HP_QUAD_2EB_3VB
+int refquad_2eb_3vb_splitedges[][3] =
+{
+  { 1, 4, 5 },
+  { 2, 3, 6 },
+  { 1, 2, 7 },
+  { 2, 1, 8 },
+  { 3, 2, 9 },
+  { 4, 1, 10 },
+  { 4, 3, 11 },
+  { 0, 0, 0 }
+};
+HPREF_ELEMENT_TYPE refquad_2eb_3vb_newelstypes[] =
+{
+  HP_TRIG_SINGEDGECORNER1,
+  HP_TRIG_SINGEDGECORNER2,
+  HP_TRIG_SINGEDGECORNER2,
+  HP_QUAD_SINGEDGE,
+  HP_QUAD_SINGEDGE,
+  HP_QUAD,
+  HP_NONE,
+};
+int refquad_2eb_3vb_newels[][8] =
+{
+  { 1, 7, 5 },
+  { 8, 2, 6 },
+  { 11, 4, 10 },
+  { 7, 8, 6, 5 },
+  { 3, 11, 10, 9 },
+  { 5, 6, 9, 10 }
+};
+HPRef_Struct refquad_2eb_3vb =
+{
+  HP_QUAD,
+  refquad_2eb_3vb_splitedges, 
+  0, 0,
+  refquad_2eb_3vb_newelstypes, 
+  refquad_2eb_3vb_newels
+};
+
+
+// HP_QUAD_2EB_4V
+int refquad_2eb_4v_splitedges[][3] =
+{
+  { 1, 4, 5 },
+  { 2, 3, 6 },
+  { 3, 2, 7 },
+  { 4, 1, 8 },
+  { 1, 2, 9 },
+  { 2, 1, 10 },
+  { 3, 4, 11 },
+  { 4, 3, 12 },
+  { 0, 0, 0 }
+};
+int refquad_2eb_4v_splitfaces[][4] =
+{
+  { 0, 0, 0, 0 },
+};
+HPREF_ELEMENT_TYPE refquad_2eb_4v_newelstypes[] =
+{
+  HP_QUAD_SINGEDGE,
+  HP_QUAD_SINGEDGE,
+  HP_QUAD,
+  HP_TRIG_SINGEDGECORNER1,
+  HP_TRIG_SINGEDGECORNER2,
+  HP_TRIG_SINGEDGECORNER1,
+  HP_TRIG_SINGEDGECORNER2,
+  HP_NONE,
+};
+int refquad_2eb_4v_newels[][8] =
+{
+  { 9, 10, 6, 5 },
+  { 11, 12, 8, 7 },
+  { 5, 6, 7, 8 },
+  { 1, 9, 5 },
+  { 10, 2, 6 },
+  { 3, 11, 7 },
+  { 12, 4, 8 },
+};
+HPRef_Struct refquad_2eb_4v =
+{
+  HP_QUAD,
+  refquad_2eb_4v_splitedges, 
+  refquad_2eb_4v_splitfaces, 
+  0,
+  refquad_2eb_4v_newelstypes, 
+  refquad_2eb_4v_newels
+};
+
+
+
+// HP_QUAD_3E
+int refquad_3e_splitedges[][3] =
+{
+  { 1, 2, 5 },
+  { 1, 4, 6 },
+  { 2, 1, 7 },
+  { 2, 3, 8 },
+  { 3, 4, 10 },
+  { 4, 3, 12 },
+  { 0, 0, 0 }
+};
+
+int refquad_3e_splitfaces[][4] =
+{
+  { 1, 2, 4, 13 },
+  { 2, 3, 1, 14 },
+  { 0, 0, 0, 0 },
+};
+
+HPREF_ELEMENT_TYPE refquad_3e_newelstypes[] =
+{
+  HP_QUAD_2E,
+  HP_QUAD_2E,
+//   HP_TRIG_SINGEDGECORNER1,
+//   HP_TRIG_SINGEDGECORNER2,
+//   HP_TRIG_SINGEDGECORNER2,
+//   HP_TRIG_SINGEDGECORNER1,
+
+  HP_QUAD_SINGEDGE,
+  HP_QUAD_SINGEDGE,
+  HP_QUAD_SINGEDGE,
+
+  HP_QUAD,
+  HP_NONE,
+};
+int refquad_3e_newels[][8] =
+{
+//   { 1, 5, 13 },
+//   { 6, 1, 13 },
+//   { 7, 2, 14 },
+//   { 2, 8, 14 },
+  { 1, 5, 13, 6 },
+  { 2, 8, 14, 7 },
+  { 5, 7, 14, 13 },
+  { 8, 3, 10, 14 },
+  { 4, 6, 13, 12 },
+  { 13, 14, 10, 12 }
+};
+HPRef_Struct refquad_3e =
+{
+  HP_QUAD,
+  refquad_3e_splitedges, 
+  refquad_3e_splitfaces, 
+  0,
+  refquad_3e_newelstypes, 
+  refquad_3e_newels
+};
+
+
+
+
+
+
+
+// HP_QUAD_3E_3VA
+int refquad_3e_3va_splitedges[][3] =
+{
+  { 1, 2, 5 },
+  { 1, 4, 6 },
+  { 2, 1, 7 },
+  { 2, 3, 8 },
+  { 3, 4, 10 },
+  { 3, 2, 11 },
+  { 4, 3, 12 },
+  { 0, 0, 0 }
+};
+
+int refquad_3e_3va_splitfaces[][4] =
+{
+  { 1, 2, 4, 13 },
+  { 2, 3, 1, 14 },
+  { 0, 0, 0, 0 },
+};
+
+HPREF_ELEMENT_TYPE refquad_3e_3va_newelstypes[] =
+{
+  HP_QUAD_2E,
+  HP_QUAD_2E,
+
+//   HP_TRIG_SINGEDGECORNER1,
+//   HP_TRIG_SINGEDGECORNER2,
+//   HP_TRIG_SINGEDGECORNER2,
+//   HP_TRIG_SINGEDGECORNER1,
+  HP_TRIG_SINGEDGECORNER2,
+
+  HP_QUAD_SINGEDGE,
+  HP_QUAD_SINGEDGE,
+  HP_QUAD_SINGEDGE,
+
+  HP_QUAD,
+  HP_NONE,
+};
+int refquad_3e_3va_newels[][8] =
+{
+//   { 1, 5, 13 },
+//   { 6, 1, 13 },
+//   { 7, 2, 14 },
+//   { 2, 8, 14 },
+  { 1, 5, 13, 6 },
+  { 2, 8, 14, 7 },
+  { 11, 3, 10 },
+  { 5, 7, 14, 13 },
+  { 8, 11, 10, 14 },
+  { 4, 6, 13, 12 },
+  { 13, 14, 10, 12 }
+};
+HPRef_Struct refquad_3e_3va =
+{
+  HP_QUAD,
+  refquad_3e_3va_splitedges, 
+  refquad_3e_3va_splitfaces, 
+  0,
+  refquad_3e_3va_newelstypes, 
+  refquad_3e_3va_newels
+};
+
+// HP_QUAD_3E_3VB
+int refquad_3e_3vb_splitedges[][3] =
+{
+  { 1, 2, 5 },
+  { 1, 4, 6 },
+  { 2, 1, 7 },
+  { 2, 3, 8 },
+  { 3, 4, 10 },
+  { 4, 1, 11 },
+  { 4, 3, 12 },
+  { 0, 0, 0 }
+};
+
+int refquad_3e_3vb_splitfaces[][4] =
+{
+  { 1, 2, 4, 13 },
+  { 2, 3, 1, 14 },
+  { 0, 0, 0, 0 },
+};
+
+HPREF_ELEMENT_TYPE refquad_3e_3vb_newelstypes[] =
+{
+  HP_QUAD_2E,
+  HP_QUAD_2E,
+
+//   HP_TRIG_SINGEDGECORNER1,
+//   HP_TRIG_SINGEDGECORNER2,
+//   HP_TRIG_SINGEDGECORNER2,
+//   HP_TRIG_SINGEDGECORNER1,
+  HP_TRIG_SINGEDGECORNER1,
+
+  HP_QUAD_SINGEDGE,
+  HP_QUAD_SINGEDGE,
+  HP_QUAD_SINGEDGE,
+
+  HP_QUAD,
+  HP_NONE,
+};
+int refquad_3e_3vb_newels[][8] =
+{
+//   { 1, 5, 13 },
+//   { 6, 1, 13 },
+//   { 7, 2, 14 },
+//   { 2, 8, 14 },
+  { 1, 5, 13, 6 },
+  { 2, 8, 14, 7 },
+  { 4, 11, 12 },
+  { 5, 7, 14, 13 },
+  { 8, 3, 10, 14 },
+  { 11, 6, 13, 12 },
+  { 13, 14, 10, 12 }
+};
+HPRef_Struct refquad_3e_3vb =
+{
+  HP_QUAD,
+  refquad_3e_3vb_splitedges, 
+  refquad_3e_3vb_splitfaces, 
+  0,
+  refquad_3e_3vb_newelstypes, 
+  refquad_3e_3vb_newels
+};
+
+
+
+
+
+
+
+
+
+// HP_QUAD_3E_4V
+int refquad_3e_4v_splitedges[][3] =
+{
+  { 1, 2, 5 },
+  { 1, 4, 6 },
+  { 2, 1, 7 },
+  { 2, 3, 8 },
+  { 3, 4, 10 },
+  { 3, 2, 11 },
+  { 4, 3, 12 },
+  { 4, 1, 15 },
+  { 0, 0, 0 }
+};
+
+int refquad_3e_4v_splitfaces[][4] =
+{
+  { 1, 2, 4, 13 },
+  { 2, 3, 1, 14 },
+  { 0, 0, 0, 0 },
+};
+
+HPREF_ELEMENT_TYPE refquad_3e_4v_newelstypes[] =
+{
+  HP_QUAD_2E,
+  HP_QUAD_2E,
+
+//   HP_TRIG_SINGEDGECORNER1,
+//   HP_TRIG_SINGEDGECORNER2,
+//   HP_TRIG_SINGEDGECORNER2,
+//   HP_TRIG_SINGEDGECORNER1,
+  HP_TRIG_SINGEDGECORNER2,
+  HP_TRIG_SINGEDGECORNER1,
+
+  HP_QUAD_SINGEDGE,
+  HP_QUAD_SINGEDGE,
+  HP_QUAD_SINGEDGE,
+
+  HP_QUAD,
+  HP_NONE,
+};
+int refquad_3e_4v_newels[][8] =
+{
+//   { 1, 5, 13 },
+//   { 6, 1, 13 },
+//   { 7, 2, 14 },
+//   { 2, 8, 14 },
+  { 1, 5, 13, 6 },
+  { 2, 8, 14, 7 },
+  { 11, 3, 10 },
+  { 4, 15, 12 },
+  { 5, 7, 14, 13 },
+  { 8, 11, 10, 14 },
+  { 15, 6, 13, 12 },
+  { 13, 14, 10, 12 }
+};
+HPRef_Struct refquad_3e_4v =
+{
+  HP_QUAD,
+  refquad_3e_4v_splitedges, 
+  refquad_3e_4v_splitfaces, 
+  0,
+  refquad_3e_4v_newelstypes, 
+  refquad_3e_4v_newels
+};
+
+
+
+
+
+
+
+
+
+// HP_QUAD_4E
+int refquad_4e_splitedges[][3] =
+{
+  { 1, 2, 5 },
+  { 1, 4, 6 },
+  { 2, 1, 7 },
+  { 2, 3, 8 },
+  { 3, 2, 9 },
+  { 3, 4, 10 },
+  { 4, 1, 11 },
+  { 4, 3, 12 },
+  { 0, 0, 0 }
+};
+
+int refquad_4e_splitfaces[][4] =
+{
+  { 1, 2, 4, 13 },
+  { 2, 3, 1, 14 },
+  { 3, 4, 2, 15 },
+  { 4, 1, 3, 16 },
+  { 0, 0, 0, 0 },
+};
+
+HPREF_ELEMENT_TYPE refquad_4e_newelstypes[] =
+{
+  HP_QUAD_2E,
+  HP_QUAD_2E,
+  HP_QUAD_2E,
+  HP_QUAD_2E,
+
+  HP_QUAD_SINGEDGE,
+  HP_QUAD_SINGEDGE,
+  HP_QUAD_SINGEDGE,
+  HP_QUAD_SINGEDGE,
+
+  HP_QUAD,
+  HP_NONE,
+};
+int refquad_4e_newels[][8] =
+{
+  { 1, 5, 13, 6 },
+  { 2, 8, 14, 7 },
+  { 3, 10, 15, 9 },
+  { 4, 11, 16, 12 },
+  { 5, 7, 14, 13 },
+  { 8, 9, 15, 14 },
+  { 10, 12, 16, 15 },
+  { 11, 6, 13, 16 },
+  { 13, 14, 15, 16 }
+};
+HPRef_Struct refquad_4e =
+{
+  HP_QUAD,
+  refquad_4e_splitedges, 
+  refquad_4e_splitfaces, 
+  0,
+  refquad_4e_newelstypes, 
+  refquad_4e_newels
+};
diff --git a/contrib/Netgen/libsrc/meshing/hpref_segm.hpp b/contrib/Netgen/libsrc/meshing/hpref_segm.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..254458232106e82712d96084678bc4b95fc33b31
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/hpref_segm.hpp
@@ -0,0 +1,122 @@
+  // HP_SEGM
+  int refsegm_splitedges[][3] =
+    {
+      { 0, 0, 0 }
+    };
+  
+  HPREF_ELEMENT_TYPE refsegm_newelstypes[] =
+    {
+      HP_SEGM,
+      HP_NONE,
+    };
+  int refsegm_newels[][8] =
+    {
+      { 1, 2 },
+    };
+  HPRef_Struct refsegm =
+    {
+      HP_SEGM, 
+      refsegm_splitedges, 
+      0, 0, 
+      refsegm_newelstypes, 
+      refsegm_newels
+    };
+
+  // HP_SEGM_SINGCORNERL = 2,
+  int refsegm_scl_splitedges[][3] =
+    {
+      { 1, 2, 3 }, 
+      { 0, 0, 0 }
+    };
+  
+  HPREF_ELEMENT_TYPE refsegm_scl_newelstypes[] = 
+    {
+      HP_SEGM_SINGCORNERL,
+      HP_SEGM,
+      HP_NONE,
+    };
+  
+  int refsegm_scl_newels[][8] =
+    {
+      { 1, 3 },
+      { 3, 2 },
+      { 0, 0 },
+    };
+  HPRef_Struct refsegm_scl =
+    {
+      HP_SEGM,
+      refsegm_scl_splitedges,
+      0, 0,
+      refsegm_scl_newelstypes,
+      refsegm_scl_newels
+    };
+
+
+
+  // HP_SEGM_SINGCORNERR
+  int refsegm_scr_splitedges[][3] =
+    {
+      { 2, 1, 3 },
+      { 0, 0, 0 }
+    };
+
+  HPREF_ELEMENT_TYPE refsegm_scr_newelstypes[] =
+    {
+      HP_SEGM,
+      HP_SEGM_SINGCORNERR,
+      HP_NONE,
+    };
+  int refsegm_scr_newels[][8] =
+    {
+      { 1, 3 },
+      { 3, 2 },
+      { 0, 0 },
+    };
+  HPRef_Struct refsegm_scr =
+    {
+      HP_SEGM,
+      refsegm_scr_splitedges,
+      0, 0,
+      refsegm_scr_newelstypes,
+      refsegm_scr_newels
+    };
+
+
+
+
+
+
+  // HP_SEGM_SINGCORNERS = 3,
+  int refsegm_sc2_splitedges[][3] =
+    {
+      { 1, 2, 3 },
+      { 2, 1, 4 },
+      { 0, 0, 0 }
+    };
+
+  HPREF_ELEMENT_TYPE refsegm_sc2_newelstypes[] =
+    {
+      HP_SEGM_SINGCORNERL,
+      HP_SEGM_SINGCORNERR,
+      HP_SEGM,
+      HP_NONE,
+    };
+  int refsegm_sc2_newels[][8] =
+    {
+      { 1, 3 },
+      { 4, 2 },
+      { 3, 4 },
+      { 0, 0 },
+    };
+  HPRef_Struct refsegm_sc2 =
+    {  
+      HP_SEGM,
+      refsegm_sc2_splitedges,
+      0, 0, 
+      refsegm_sc2_newelstypes,
+      refsegm_sc2_newels
+    };
+
+
+
+
diff --git a/contrib/Netgen/libsrc/meshing/hpref_tet.hpp b/contrib/Netgen/libsrc/meshing/hpref_tet.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..df0e2af890aec6de2c30a1821912e8ed79ca0a6b
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/hpref_tet.hpp
@@ -0,0 +1,3128 @@
+
+ 
+
+// HP_TET
+int reftet_splitedges[][3] =
+{
+  { 0, 0, 0 }
+};
+HPREF_ELEMENT_TYPE reftet_newelstypes[] =
+{
+  HP_TET,
+  HP_NONE,
+};
+int reftet_newels[][8] =
+{
+  { 1, 2, 3, 4 },
+};
+HPRef_Struct reftet =
+{
+  HP_TET,
+  reftet_splitedges, 
+  0, 0,
+  reftet_newelstypes, 
+  reftet_newels
+};
+
+
+
+/* *********** Tet - Refinement - 0 edges *************** */
+
+// HP_TET_0E_1V
+int reftet_0e_1v_splitedges[][3] =
+{
+  { 1, 2, 5 },
+  { 1, 3, 6 },
+  { 1, 4, 7 },
+  { 0, 0, 0 }
+};
+HPREF_ELEMENT_TYPE reftet_0e_1v_newelstypes[] =
+{
+  HP_TET_0E_1V,
+  HP_PRISM,
+  HP_NONE,
+};
+int reftet_0e_1v_newels[][8] =
+{
+  { 1, 5, 6, 7 },
+  { 5, 6, 7, 2, 3, 4 }
+};
+HPRef_Struct reftet_0e_1v =
+{
+  HP_TET,
+  reftet_0e_1v_splitedges, 
+  0, 0,
+  reftet_0e_1v_newelstypes, 
+  reftet_0e_1v_newels
+};
+
+
+
+// HP_TET_0E_2V
+int reftet_0e_2v_splitedges[][3] =
+{
+  { 1, 2, 5 },
+  { 1, 3, 6 },
+  { 1, 4, 7 },
+  { 2, 1, 8 },
+  { 2, 3, 9 },
+  { 2, 4, 10 },
+  { 0, 0, 0 }
+};
+HPREF_ELEMENT_TYPE reftet_0e_2v_newelstypes[] =
+{
+  HP_TET_0E_1V,
+  HP_TET_0E_1V,
+  HP_PRISM,
+  HP_PRISM,
+  HP_NONE,
+};
+int reftet_0e_2v_newels[][8] =
+{
+  { 1, 5, 6, 7 },
+  { 2, 10, 9, 8 },
+  { 5, 6, 7, 8, 9, 10 },
+  { 4, 10, 7, 3, 9, 6 },
+};
+HPRef_Struct reftet_0e_2v =
+{
+  HP_TET,
+  reftet_0e_2v_splitedges, 
+  0, 0,
+  reftet_0e_2v_newelstypes, 
+  reftet_0e_2v_newels
+};
+
+
+
+
+
+// HP_TET_0E_3V
+int reftet_0e_3v_splitedges[][3] =
+{
+  { 1, 2, 5 },
+  { 1, 3, 6 },
+  { 1, 4, 7 },
+  { 2, 1, 8 },
+  { 2, 3, 9 },
+  { 2, 4, 10 },
+  { 3, 1, 11 },
+  { 3, 2, 12 },
+  { 3, 4, 13 },
+  { 0, 0, 0 }
+};
+int reftet_0e_3v_splitfaces[][4] =
+  {
+    { 1, 2, 3, 14 },
+    { 2, 3, 1, 15 },
+    { 3, 1, 2, 16 },
+    { 0, 0, 0, 0 },
+  };
+HPREF_ELEMENT_TYPE reftet_0e_3v_newelstypes[] =
+{
+  HP_PYRAMID_0E_1V,
+  HP_PYRAMID_0E_1V,
+  HP_PYRAMID_0E_1V,
+  HP_PRISM,
+  HP_PRISM,
+  HP_PRISM,
+  HP_PRISM,
+  HP_TET,
+  HP_NONE,
+};
+int reftet_0e_3v_newels[][8] =
+{
+  { 1, 5, 14, 6, 7 },
+  { 2, 9, 15, 8, 10 },
+  { 3, 11, 16, 12, 13 },
+  { 5, 14, 7, 8, 15, 10 },
+  { 9, 15, 10, 12, 16, 13 },
+  { 6, 7, 14, 11, 13, 16 },
+  { 14, 15, 16, 7, 10, 13 },
+  { 7, 10, 13, 4 }
+};
+HPRef_Struct reftet_0e_3v =
+{
+  HP_TET,
+  reftet_0e_3v_splitedges, 
+  reftet_0e_3v_splitfaces, 
+  0,
+  reftet_0e_3v_newelstypes, 
+  reftet_0e_3v_newels
+};
+
+
+
+
+
+// HP_TET_0E_4V
+int reftet_0e_4v_splitedges[][3] =
+{
+  { 1, 2, 5 },
+  { 1, 3, 6 },
+  { 1, 4, 7 },
+  { 2, 1, 8 },
+  { 2, 3, 9 },
+  { 2, 4, 10 },
+  { 3, 1, 11 },
+  { 3, 2, 12 },
+  { 3, 4, 13 },
+  { 4, 1, 14 },
+  { 4, 2, 15 },
+  { 4, 3, 16 },
+  { 0, 0, 0 }
+};
+int reftet_0e_4v_splitfaces[][4] =
+  {
+    { 1, 2, 3, 17 },
+    { 1, 2, 4, 18 },
+    { 1, 3, 4, 19 },
+
+    { 2, 1, 3, 20 },
+    { 2, 1, 4, 21 },
+    { 2, 3, 4, 22 },
+
+    { 3, 1, 2, 23 },
+    { 3, 1, 4, 24 },
+    { 3, 2, 4, 25 },
+
+    { 4, 1, 2, 26 },
+    { 4, 1, 3, 27 },
+    { 4, 2, 3, 28 },
+    { 0, 0, 0, 0 },
+  };
+int reftet_0e_4v_splitelements[][5] =
+  {
+    { 1, 2, 3, 4, 29 },
+    { 2, 3, 4, 1, 30 },
+    { 3, 4, 1, 2, 31 },
+    { 4, 1, 2, 3, 32 },
+    { 0 },
+  };
+HPREF_ELEMENT_TYPE reftet_0e_4v_newelstypes[] =
+{
+  HP_HEX_0E_1V,
+  HP_HEX_0E_1V,
+  HP_HEX_0E_1V,
+  HP_HEX_0E_1V,
+  HP_PRISM, HP_PRISM, 
+  HP_PRISM, HP_PRISM, 
+  HP_PRISM, HP_PRISM, 
+  HP_PRISM, HP_PRISM, 
+  HP_PRISM, HP_PRISM, 
+  HP_PRISM, HP_PRISM, 
+  HP_PRISM,
+  HP_PRISM,
+  HP_PRISM,
+  HP_PRISM,
+  HP_TET,
+  HP_NONE,
+};
+int reftet_0e_4v_newels[][8] =
+{
+  { 1, 5, 17, 6, 7, 18, 29, 19 },
+  { 2, 9, 20, 8, 10, 22, 30, 21 },
+  { 3, 11, 23, 12, 13, 24, 31, 25 },
+  { 4, 15, 26, 14, 16, 28, 32, 27 },
+  { 5, 17, 18, 8, 20, 21 },
+  { 18, 17, 29, 21, 20, 30 },
+  { 6, 19, 17,  11, 24, 23 },
+  { 17, 19, 29,  23, 24, 31 },
+  { 7, 18, 19, 14, 26, 27 },
+  { 19, 18, 29, 27, 26, 32 },
+  { 9, 20, 22, 12, 23, 25 },
+  { 22, 20, 30, 25, 23, 31 },
+  { 10, 22, 21, 15, 28, 26 },
+  { 21, 22, 30, 26, 28, 32 },
+  { 13, 24, 25, 16, 27, 28 },
+  { 25, 24, 31, 28, 27, 32 },
+  { 17, 20, 23, 29, 30, 31 },
+  { 18, 26, 21, 29, 32, 30 },
+  { 19, 24, 27, 29, 31, 32 },
+  { 22, 28, 25, 30, 32, 31 },
+  { 29, 30, 31, 32 },
+};
+HPRef_Struct reftet_0e_4v =
+{
+  HP_TET,
+  reftet_0e_4v_splitedges, 
+  reftet_0e_4v_splitfaces, 
+  reftet_0e_4v_splitelements, 
+  reftet_0e_4v_newelstypes, 
+  reftet_0e_4v_newels
+};
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+/* *********** Tet - Refinement - 1 edge *************** */
+
+
+
+// HP_TET_1E_0V
+int reftet_1e_0v_splitedges[][3] =
+{
+  { 1, 3, 5 },
+  { 1, 4, 6 },
+  { 2, 3, 7 },
+  { 2, 4, 8 },
+  { 0, 0, 0 }
+};
+HPREF_ELEMENT_TYPE reftet_1e_0v_newelstypes[] =
+{
+  HP_PRISM_SINGEDGE,
+  HP_PRISM,
+  HP_NONE,
+};
+int reftet_1e_0v_newels[][8] =
+{
+  { 1, 5, 6, 2, 7, 8 },
+  { 7, 3, 5, 8, 4, 6 }
+};
+HPRef_Struct reftet_1e_0v =
+{
+  HP_TET,
+  reftet_1e_0v_splitedges, 
+  0, 0,
+  reftet_1e_0v_newelstypes, 
+  reftet_1e_0v_newels
+};
+
+
+
+
+
+// HP_TET_1E_1VA
+int reftet_1e_1va_splitedges[][3] =
+{
+  { 1, 3, 5 },
+  { 1, 4, 6 },
+  { 2, 3, 7 },
+  { 2, 4, 8 },
+  { 1, 2, 9 },
+  { 0, 0, 0 }
+};
+HPREF_ELEMENT_TYPE reftet_1e_1va_newelstypes[] =
+{
+  HP_TET_1E_1VA,
+  HP_PRISM_SINGEDGE,
+  HP_PRISM,
+  HP_NONE,
+};
+int reftet_1e_1va_newels[][8] =
+{
+  { 1, 9, 5, 6 },
+  { 9, 5, 6, 2, 7, 8 },
+  { 7, 3, 5, 8, 4, 6 }
+};
+HPRef_Struct reftet_1e_1va =
+{
+  HP_TET,
+  reftet_1e_1va_splitedges, 
+  0, 0,
+  reftet_1e_1va_newelstypes, 
+  reftet_1e_1va_newels
+};
+
+
+
+
+
+
+// HP_TET_1E_1VB
+int reftet_1e_1vb_splitedges[][3] =
+{
+  { 1, 3, 5 },
+  { 1, 4, 6 },
+  { 2, 3, 7 },
+  { 2, 4, 8 },
+  { 4, 1, 9 },
+  { 4, 2, 10 },
+  { 4, 3, 11 },
+  { 0, 0, 0 }
+};
+int reftet_1e_1vb_splitelements[][5] =
+{
+  { 4, 1, 2, 3, 12 },
+  { 0 }
+};
+
+HPREF_ELEMENT_TYPE reftet_1e_1vb_newelstypes[] =
+{
+  HP_PRISM_SINGEDGE,
+  HP_TET_0E_1V,
+  HP_PYRAMID,
+  HP_TET,
+  HP_PYRAMID, 
+  HP_TET,
+  HP_PYRAMID,
+  HP_TET,
+  HP_PYRAMID,
+  HP_TET,
+  HP_NONE,
+};
+int reftet_1e_1vb_newels[][8] =
+{
+  { 1, 5, 6, 2, 7, 8 },
+  { 4, 11, 10, 9 },
+  { 7, 8, 10, 11, 12 },
+  { 3, 7, 11, 12 },
+  { 5, 11, 9, 6, 12 },
+  { 5, 3, 11, 12 },
+  { 6, 9, 10, 8, 12 },
+  { 5, 7, 3, 12 },
+  { 5, 6, 8, 7, 12 },
+  { 9, 11, 10, 12 }
+};
+HPRef_Struct reftet_1e_1vb =
+{
+  HP_TET,
+  reftet_1e_1vb_splitedges, 
+  0,
+  reftet_1e_1vb_splitelements, 
+  reftet_1e_1vb_newelstypes, 
+  reftet_1e_1vb_newels
+};
+
+
+
+
+
+
+
+
+// HP_TET_1E_2VA
+int reftet_1e_2va_splitedges[][3] =
+{
+  { 1, 2, 5 },
+  { 1, 3, 6 },
+  { 1, 4, 7 },
+  { 2, 1, 8 },
+  { 2, 3, 9 },
+  { 2, 4, 10 },
+  { 0, 0, 0 }
+};
+HPREF_ELEMENT_TYPE reftet_1e_2va_newelstypes[] =
+{
+  HP_TET_1E_1VA,
+  HP_TET_1E_1VA,
+  HP_PRISM_SINGEDGE,
+  HP_PRISM,
+  HP_NONE,
+};
+int reftet_1e_2va_newels[][8] =
+{
+  { 1, 5, 6, 7 },
+  { 2, 8, 10, 9 },
+  { 5, 6, 7, 8, 9, 10 },
+  { 4, 10, 7, 3, 9, 6 },
+};
+HPRef_Struct reftet_1e_2va =
+{
+  HP_TET,
+  reftet_1e_2va_splitedges, 
+  0, 0,
+  reftet_1e_2va_newelstypes, 
+  reftet_1e_2va_newels
+};
+
+
+
+
+
+
+
+// HP_TET_1E_2VB
+int reftet_1e_2vb_splitedges[][3] =
+{
+  { 1, 2, 5 },
+  { 1, 3, 6 },
+  { 1, 4, 7 },
+  { 2, 3, 8 },
+  { 2, 4, 9 },
+  { 3, 1, 10 },
+  { 3, 2, 11 },
+  { 3, 4, 12 },
+  { 0, 0, 0 }
+};
+int reftet_1e_2vb_splitelements[][5] =
+{
+  { 3, 4, 1, 2, 13 },
+  { 0 }
+};
+
+HPREF_ELEMENT_TYPE reftet_1e_2vb_newelstypes[] =
+{
+  HP_TET_1E_1VA,
+  HP_PRISM_SINGEDGE,
+  HP_TET_0E_1V,
+  HP_PYRAMID,
+  HP_TET,
+  HP_PYRAMID, 
+  HP_TET,
+  HP_PYRAMID,
+  HP_TET,
+  HP_PYRAMID,
+  HP_TET,
+  HP_NONE,
+};
+int reftet_1e_2vb_newels[][8] =
+{
+  { 1, 5, 6, 7 },
+  { 5, 6, 7, 2, 8, 9 },
+  { 3, 10, 11, 12 },
+
+  { 8, 9, 12, 11, 13 },
+  { 4, 12, 9, 13 },
+  { 6, 10, 12, 7, 13 },
+  { 4, 7, 12, 13 },
+  { 6, 8, 11, 10, 13 },
+  { 4, 9, 7, 13 },
+  { 6, 7, 9, 8, 13 },
+  { 10, 11, 12, 13 },
+};
+HPRef_Struct reftet_1e_2vb =
+{
+  HP_TET,
+  reftet_1e_2vb_splitedges, 
+  0,
+  reftet_1e_2vb_splitelements, 
+  reftet_1e_2vb_newelstypes, 
+  reftet_1e_2vb_newels
+};
+
+
+
+
+
+
+// HP_TET_1E_2VC
+int reftet_1e_2vc_splitedges[][3] =
+{
+  { 1, 2, 5 },
+  { 1, 3, 6 },
+  { 1, 4, 7 },
+  { 2, 3, 8 },
+  { 2, 4, 9 },
+  { 4, 1, 10 },
+  { 4, 2, 11 },
+  { 4, 3, 12 },
+  { 0, 0, 0 }
+};
+int reftet_1e_2vc_splitelements[][5] =
+{
+  { 4, 1, 2, 3, 13 },
+  { 0 }
+};
+
+HPREF_ELEMENT_TYPE reftet_1e_2vc_newelstypes[] =
+{
+  HP_TET_1E_1VA,
+  HP_PRISM_SINGEDGE,
+  HP_TET_0E_1V,
+  HP_PYRAMID,
+  HP_TET,
+  HP_PYRAMID, 
+  HP_TET,
+  HP_PYRAMID,
+  HP_TET,
+  HP_PYRAMID,
+  HP_TET,
+  HP_NONE,
+};
+int reftet_1e_2vc_newels[][8] =
+{
+  { 1, 5, 6, 7 },
+  { 5, 6, 7, 2, 8, 9 },
+  { 4, 11, 10, 12 },
+  { 8, 9, 11, 12, 13 },
+  { 3, 8, 12, 13 },
+  { 7, 6, 12, 10, 13 },
+  { 3, 12, 6, 13 },
+  { 9, 7, 10, 11, 13 },
+  { 3, 6, 8, 13 },
+  { 6, 7, 9, 8, 13 },
+  { 10, 12, 11, 13 }
+};
+HPRef_Struct reftet_1e_2vc =
+{
+  HP_TET,
+  reftet_1e_2vc_splitedges, 
+  0,
+  reftet_1e_2vc_splitelements, 
+  reftet_1e_2vc_newelstypes, 
+  reftet_1e_2vc_newels
+};
+
+
+
+
+
+
+
+
+/*
+
+// HP_TET_1E_2VD
+int reftet_1e_2vd_splitedges[][3] =
+{
+  { 1, 3, 5 },
+  { 1, 4, 6 },
+  { 2, 3, 7 },
+  { 2, 4, 8 },
+  { 3, 1, 9 },
+  { 3, 2, 10 },
+  { 3, 4, 11 },
+  { 4, 1, 12 },
+  { 4, 2, 13 },
+  { 4, 3, 14 },
+  { 0, 0, 0 }
+};
+HPREF_ELEMENT_TYPE reftet_1e_2vd_newelstypes[] =
+{
+  HP_PRISM_SINGEDGE,
+  HP_TET_0E_1V,
+  HP_TET_0E_1V,
+  HP_PRISM,
+  HP_HEX,
+  HP_NONE,
+};
+int reftet_1e_2vd_newels[][8] =
+{
+  { 1, 5, 6, 2, 7, 8 },
+  { 4, 13, 12, 14 },
+  { 3, 10, 11, 9 },
+  { 14, 13, 12, 11, 10, 9 },
+  { 6, 12, 13, 8, 5, 9, 10, 7 },
+};
+HPRef_Struct reftet_1e_2vd =
+{
+  HP_TET,
+  reftet_1e_2vd_splitedges, 
+  0, 0,
+  reftet_1e_2vd_newelstypes, 
+  reftet_1e_2vd_newels
+};
+
+*/
+
+
+
+
+//  HP_TET_1E_2VD,  // 1 v on edge
+int reftet_1e_2vd_splitedges[][3] =
+{
+  // { 1, 2, 5 },
+  { 1, 3, 6 },
+  { 1, 4, 7 },
+  // { 2, 1, 8 },
+  { 2, 3, 9 },
+  { 2, 4, 10 },
+  { 3, 1, 11 },
+  { 3, 2, 12 },
+  { 3, 4, 13 },
+  { 4, 1, 14 },
+  { 4, 2, 15 },
+  { 4, 3, 16 },
+  { 0, 0, 0 }
+};
+int reftet_1e_2vd_splitfaces[][4] =
+  {
+    { 1, 3, 4, 19 },
+    { 2, 3, 4, 22 },
+    { 3, 1, 4, 24 },
+    { 3, 2, 4, 25 },
+    { 4, 1, 3, 27 },
+    { 4, 2, 3, 28 },
+    { 0, 0, 0, 0 }
+  };
+HPREF_ELEMENT_TYPE reftet_1e_2vd_newelstypes[] =
+  {
+    HP_PRISM_SINGEDGE,
+    HP_TET_0E_1V,
+    HP_TET_0E_1V,
+    HP_PRISM,
+    HP_HEX,
+    HP_PYRAMID,
+    HP_HEX,
+    HP_PYRAMID,
+    HP_PRISM,
+    HP_PRISM,
+    HP_NONE,
+  };
+int reftet_1e_2vd_newels[][8] =
+{
+  { 1, 6, 7, 2, 9, 10 },
+  { 3, 11, 12, 13 },
+  { 4, 16, 15, 14 },
+  { 7, 6, 19, 10, 9, 22 },
+  { 7, 19, 27, 14, 10, 22, 28, 15 },
+  { 14, 15, 28, 27, 16 },
+  { 9, 6, 19, 22, 12, 11, 24, 25 },
+  { 12, 11, 24, 25, 13 },
+  { 19, 24, 27, 22, 25, 28 },
+  { 16, 28, 27, 13, 25, 24 }
+};
+HPRef_Struct reftet_1e_2vd =
+{
+  HP_TET,
+  reftet_1e_2vd_splitedges, 
+  reftet_1e_2vd_splitfaces, 
+  0,
+  reftet_1e_2vd_newelstypes, 
+  reftet_1e_2vd_newels
+};
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+// HP_TET_1E_3VA
+int reftet_1e_3va_splitedges[][3] =
+{
+  { 1, 2, 5 },
+  { 1, 3, 6 },
+  { 1, 4, 7 },
+  { 2, 1, 8 },
+  { 2, 3, 9 },
+  { 2, 4, 10 },
+  { 3, 1, 11 },
+  { 3, 2, 12 },
+  { 3, 4, 13 },
+  { 0, 0, 0 }
+};
+int reftet_1e_3va_splitelements[][5] =
+{
+  { 1, 2, 3, 4, 14 },
+  { 0 }
+};
+
+HPREF_ELEMENT_TYPE reftet_1e_3va_newelstypes[] =
+{
+  HP_PRISM_SINGEDGE,
+  HP_TET_1E_1VA,
+  HP_TET_1E_1VA,
+  HP_TET_0E_1V,
+
+  HP_PYRAMID,
+  HP_TET,
+  HP_PYRAMID, 
+  HP_TET,
+  HP_PYRAMID,
+  HP_TET,
+  HP_PYRAMID,
+  HP_TET,
+  HP_NONE,
+};
+int reftet_1e_3va_newels[][8] =
+{
+  { 5, 6, 7, 8, 9, 10 },
+  { 1, 5, 6, 7 },
+  { 2, 8, 10, 9 },
+  { 3, 11, 12, 13 },
+
+  { 6, 7, 10, 9, 14 },
+  { 4, 10, 7, 14 },
+  { 9, 10, 13, 12, 14 },
+  { 4, 13, 10, 14 },
+  { 6, 11, 13, 7, 14 },
+  { 4, 7, 13, 14 },
+  { 6, 11, 12, 9, 14 },
+  { 11, 13, 12, 14 },
+};
+
+HPRef_Struct reftet_1e_3va =
+{
+  HP_TET,
+  reftet_1e_3va_splitedges, 
+  0,
+  reftet_1e_3va_splitelements, 
+  reftet_1e_3va_newelstypes, 
+  reftet_1e_3va_newels
+};
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+//  HP_TET_1E_3VB,  // 1 v on edge
+int reftet_1e_3vb_splitedges[][3] =
+{
+  { 1, 2, 5 },
+  { 1, 3, 6 },
+  { 1, 4, 7 },
+  // { 2, 1, 8 },
+  { 2, 3, 9 },
+  { 2, 4, 10 },
+  { 3, 1, 11 },
+  { 3, 2, 12 },
+  { 3, 4, 13 },
+  { 4, 1, 14 },
+  { 4, 2, 15 },
+  { 4, 3, 16 },
+  { 0, 0, 0 }
+};
+int reftet_1e_3vb_splitfaces[][4] =
+  {
+    { 1, 3, 4, 19 },
+    { 2, 3, 4, 22 },
+    { 3, 1, 4, 24 },
+    { 3, 2, 4, 25 },
+    { 4, 1, 3, 27 },
+    { 4, 2, 3, 28 },
+    { 0, 0, 0, 0 }
+  };
+HPREF_ELEMENT_TYPE reftet_1e_3vb_newelstypes[] =
+  {
+    HP_TET_1E_1VA,
+    HP_PRISM_SINGEDGE,
+    HP_TET_0E_1V,
+    HP_TET_0E_1V,
+    HP_PRISM,
+    HP_HEX,
+    HP_PYRAMID,
+    HP_HEX,
+    HP_PYRAMID,
+    HP_PRISM,
+    HP_PRISM,
+    HP_NONE,
+  };
+int reftet_1e_3vb_newels[][8] =
+{
+  { 1, 5, 6, 7 },
+  { 5, 6, 7, 2, 9, 10 },
+  { 3, 11, 12, 13 },
+  { 4, 16, 15, 14 },
+  { 7, 6, 19, 10, 9, 22 },
+  { 7, 19, 27, 14, 10, 22, 28, 15 },
+  { 14, 15, 28, 27, 16 },
+  { 9, 6, 19, 22, 12, 11, 24, 25 },
+  { 12, 11, 24, 25, 13 },
+  { 19, 24, 27, 22, 25, 28 },
+  { 16, 28, 27, 13, 25, 24 }
+};
+HPRef_Struct reftet_1e_3vb =
+{
+  HP_TET,
+  reftet_1e_3vb_splitedges, 
+  reftet_1e_3vb_splitfaces, 
+  0,
+  reftet_1e_3vb_newelstypes, 
+  reftet_1e_3vb_newels
+};
+
+
+
+
+
+
+/*
+// HP_TET_1E_4V
+int reftet_1e_4v_splitedges[][3] =
+{
+  { 1, 2, 5 },
+  { 1, 3, 6 },
+  { 1, 4, 7 },
+  { 2, 1, 8 },
+  { 2, 3, 9 },
+  { 2, 4, 10 },
+  { 3, 1, 11 },
+  { 3, 2, 12 },
+  { 3, 4, 13 },
+  { 4, 1, 14 },
+  { 4, 2, 15 },
+  { 4, 3, 16 },
+  { 0, 0, 0 }
+};
+int reftet_1e_4v_splitfaces[][4] =
+  {
+    { 1, 2, 3, 17 },
+    { 1, 2, 4, 18 },
+    { 1, 3, 4, 19 },
+
+    { 2, 1, 3, 20 },
+    { 2, 1, 4, 21 },
+    { 2, 3, 4, 22 },
+
+    { 3, 1, 2, 23 },
+    { 3, 1, 4, 24 },
+    { 3, 2, 4, 25 },
+
+    { 4, 1, 2, 26 },
+    { 4, 1, 3, 27 },
+    { 4, 2, 3, 28 },
+    { 0, 0, 0, 0 },
+  };
+int reftet_1e_4v_splitelements[][5] =
+  {
+    { 1, 2, 3, 4, 29 },
+    { 2, 3, 4, 1, 30 },
+    { 3, 4, 1, 2, 31 },
+    { 4, 1, 2, 3, 32 },
+    { 0 },
+  };
+HPREF_ELEMENT_TYPE reftet_1e_4v_newelstypes[] =
+{
+  HP_HEX_1E_1V,
+  HP_HEX_1E_1V,
+  HP_HEX_0E_1V,
+  HP_HEX_0E_1V,
+  HP_PRISM_SINGEDGE, HP_PRISM, 
+  HP_PRISM, HP_PRISM, 
+  HP_PRISM, HP_PRISM, 
+  HP_PRISM, HP_PRISM, 
+  HP_PRISM, HP_PRISM, 
+  HP_PRISM, HP_PRISM, 
+  HP_PRISM,
+  HP_PRISM,
+  HP_PRISM,
+  HP_PRISM,
+  HP_TET,
+  HP_NONE,
+};
+int reftet_1e_4v_newels[][8] =
+{
+  { 1, 5, 17, 6, 7, 18, 29, 19 },
+  //  { 2, 9, 20, 8, 10, 22, 30, 21 },
+  { 2, 8, 21, 10, 9, 20, 30, 22 },
+  { 3, 11, 23, 12, 13, 24, 31, 25 },
+  { 4, 15, 26, 14, 16, 28, 32, 27 },
+  { 5, 17, 18, 8, 20, 21 },
+  { 18, 17, 29, 21, 20, 30 },
+  { 6, 19, 17,  11, 24, 23 },
+  { 17, 19, 29,  23, 24, 31 },
+  { 7, 18, 19, 14, 26, 27 },
+  { 19, 18, 29, 27, 26, 32 },
+  { 9, 20, 22, 12, 23, 25 },
+  { 22, 20, 30, 25, 23, 31 },
+  { 10, 22, 21, 15, 28, 26 },
+  { 21, 22, 30, 26, 28, 32 },
+  { 13, 24, 25, 16, 27, 28 },
+  { 25, 24, 31, 28, 27, 32 },
+  { 17, 20, 23, 29, 30, 31 },
+  { 18, 26, 21, 29, 32, 30 },
+  { 19, 24, 27, 29, 31, 32 },
+  { 22, 28, 25, 30, 32, 31 },
+
+  { 29, 30, 31, 32 },
+};
+HPRef_Struct reftet_1e_4v =
+{
+  HP_TET,
+  reftet_1e_4v_splitedges, 
+  reftet_1e_4v_splitfaces, 
+  reftet_1e_4v_splitelements, 
+  reftet_1e_4v_newelstypes, 
+  reftet_1e_4v_newels
+};
+*/
+
+
+
+
+// HP_TET_1E_4V
+int reftet_1e_4v_splitedges[][3] =
+{
+  { 1, 2, 5 },
+  { 1, 3, 6 },
+  { 1, 4, 7 },
+  { 2, 1, 8 },
+  { 2, 3, 9 },
+  { 2, 4, 10 },
+  { 3, 1, 11 },
+  { 3, 2, 12 },
+  { 3, 4, 13 },
+  { 4, 1, 14 },
+  { 4, 2, 15 },
+  { 4, 3, 16 },
+  { 0, 0, 0 }
+};
+int reftet_1e_4v_splitfaces[][4] =
+  {
+    { 1, 3, 4, 17 },
+    { 2, 3, 4, 18 },
+
+    { 3, 1, 4, 19 },
+    { 3, 2, 4, 20 },
+
+    { 4, 1, 3, 21 },
+    { 4, 2, 3, 22 },
+    { 0, 0, 0, 0 },
+  };
+
+HPREF_ELEMENT_TYPE reftet_1e_4v_newelstypes[] =
+{
+  HP_TET_1E_1VA,
+  HP_TET_1E_1VA,
+  //  HP_TET_1E_1VA,
+  //  HP_TET_1E_1VA,
+  HP_PRISM_SINGEDGE,
+  HP_PRISM,
+  HP_HEX, 
+  HP_HEX, 
+  HP_PRISM,
+  HP_PRISM,
+
+  HP_PYRAMID,
+  HP_TET_0E_1V,
+
+  HP_PYRAMID,
+  HP_TET_0E_1V,
+
+  HP_NONE,
+};
+
+int reftet_1e_4v_newels[][8] =
+{
+  { 1, 5, 6, 7 },
+  { 2, 8, 10, 9 },
+
+  { 5, 6, 7, 8, 9, 10 },
+  { 7, 6, 17, 10, 9, 18 },
+
+  { 7, 10, 18, 17, 14, 15, 22, 21 },
+  { 9, 6, 17, 18, 12, 11, 19, 20 },
+
+  { 17, 19, 21, 18, 20, 22 },
+  { 16, 22, 21, 13, 20, 19 },
+
+  { 14, 15, 22, 21, 16 },
+  { 4, 14, 16, 15 },
+  { 12, 11, 19, 20, 13 },
+  { 3, 11, 12, 13 },
+
+
+
+  { 1, 5, 17, 6, 7, 18, 29, 19 },
+  //  { 2, 9, 20, 8, 10, 22, 30, 21 },
+  { 2, 8, 21, 10, 9, 20, 30, 22 },
+  { 3, 11, 23, 12, 13, 24, 31, 25 },
+  { 4, 15, 26, 14, 16, 28, 32, 27 },
+  { 5, 17, 18, 8, 20, 21 },
+  { 18, 17, 29, 21, 20, 30 },
+  { 6, 19, 17,  11, 24, 23 },
+  { 17, 19, 29,  23, 24, 31 },
+  { 7, 18, 19, 14, 26, 27 },
+  { 19, 18, 29, 27, 26, 32 },
+  { 9, 20, 22, 12, 23, 25 },
+  { 22, 20, 30, 25, 23, 31 },
+  { 10, 22, 21, 15, 28, 26 },
+  { 21, 22, 30, 26, 28, 32 },
+  { 13, 24, 25, 16, 27, 28 },
+  { 25, 24, 31, 28, 27, 32 },
+  { 17, 20, 23, 29, 30, 31 },
+  { 18, 26, 21, 29, 32, 30 },
+  { 19, 24, 27, 29, 31, 32 },
+  { 22, 28, 25, 30, 32, 31 },
+
+  { 29, 30, 31, 32 },
+};
+HPRef_Struct reftet_1e_4v =
+{
+  HP_TET,
+  reftet_1e_4v_splitedges, 
+  reftet_1e_4v_splitfaces, 
+  0, 
+  reftet_1e_4v_newelstypes, 
+  reftet_1e_4v_newels
+};
+
+
+
+
+
+
+
+
+
+
+
+
+
+//  HP_TET_2EA_0V,  // 2 edges connected
+int reftet_2ea_0v_splitedges[][3] =
+{
+  { 1, 2, 5 },
+  { 1, 3, 6 },
+  { 1, 4, 7 },
+  { 2, 3, 9 },
+  { 2, 4, 10 },
+  { 3, 2, 12 },
+  { 3, 4, 13 },
+  { 0, 0, 0 }
+};
+int reftet_2ea_0v_splitfaces[][4] =
+  {
+    { 1, 2, 3, 17 },
+    { 0, 0, 0, 0 }
+  };
+HPREF_ELEMENT_TYPE reftet_2ea_0v_newelstypes[] =
+  {
+    HP_PYRAMID_EDGES,
+    HP_PRISM_SINGEDGE,
+    HP_PRISM_SINGEDGE,
+    HP_PRISM,
+    HP_TET,
+    HP_NONE,
+  };
+int reftet_2ea_0v_newels[][8] =
+{
+  { 1, 5, 17, 6, 7 },
+  { 5, 17, 7, 2, 9, 10 },
+  { 6, 7, 17, 3, 13, 12 },
+  { 17, 9, 12, 7, 10, 13 },
+  { 7, 10, 13, 4 },
+};
+HPRef_Struct reftet_2ea_0v =
+{
+  HP_TET,
+  reftet_2ea_0v_splitedges, 
+  reftet_2ea_0v_splitfaces, 
+  0,
+  reftet_2ea_0v_newelstypes, 
+  reftet_2ea_0v_newels
+};
+
+
+
+
+
+
+//  HP_TET_2EA_1VA,  // 2 edges connected
+int reftet_2ea_1va_splitedges[][3] =
+{
+  { 1, 2, 5 },
+  { 1, 3, 6 },
+  { 1, 4, 7 },
+  { 2, 1, 8 },
+  { 2, 3, 9 },
+  { 2, 4, 10 },
+  { 3, 2, 12 },
+  { 3, 4, 13 },
+  { 0, 0, 0 }
+};
+int reftet_2ea_1va_splitfaces[][4] =
+  {
+    { 1, 2, 3, 17 },
+    { 0, 0, 0, 0 }
+  };
+HPREF_ELEMENT_TYPE reftet_2ea_1va_newelstypes[] =
+  {
+    HP_PYRAMID_EDGES,
+    HP_PRISM_SINGEDGE,
+    HP_TET_1E_1VA,
+    HP_PRISM_SINGEDGE,
+    HP_PRISM,
+    HP_TET,
+    HP_NONE,
+  };
+int reftet_2ea_1va_newels[][8] =
+{
+  { 1, 5, 17, 6, 7 },
+  { 5, 17, 7, 8, 9, 10 },
+  { 2, 8, 10, 9 },
+  { 6, 7, 17, 3, 13, 12 },
+  { 17, 9, 12, 7, 10, 13 },
+  { 7, 10, 13, 4 },
+};
+HPRef_Struct reftet_2ea_1va =
+{
+  HP_TET,
+  reftet_2ea_1va_splitedges, 
+  reftet_2ea_1va_splitfaces, 
+  0,
+  reftet_2ea_1va_newelstypes, 
+  reftet_2ea_1va_newels
+};
+
+
+
+
+
+
+
+
+//  HP_TET_2EA_1VB, 
+int reftet_2ea_1vb_splitedges[][3] =
+{
+  { 1, 2, 5 },
+  { 1, 3, 6 },
+  { 1, 4, 7 },
+  { 2, 3, 9 },
+  { 2, 4, 10 },
+  { 3, 1, 11 },
+  { 3, 2, 12 },
+  { 3, 4, 13 },
+  { 0, 0, 0 }
+};
+int reftet_2ea_1vb_splitfaces[][4] =
+  {
+    { 1, 2, 3, 17 },
+    { 0, 0, 0, 0 }
+  };
+HPREF_ELEMENT_TYPE reftet_2ea_1vb_newelstypes[] =
+  {
+    HP_PYRAMID_EDGES,
+    HP_TET_1E_1VA,
+    HP_PRISM_SINGEDGE,
+    HP_PRISM_SINGEDGE,
+    HP_PRISM,
+    HP_TET,
+    HP_NONE,
+  };
+int reftet_2ea_1vb_newels[][8] =
+{
+  { 1, 5, 17, 6, 7 },
+  { 3, 11, 12, 13 },
+  { 5, 17, 7, 2, 9, 10 },
+  { 6, 7, 17, 11, 13, 12 },
+  { 17, 9, 12, 7, 10, 13 },
+  { 7, 10, 13, 4 },
+};
+HPRef_Struct reftet_2ea_1vb =
+{
+  HP_TET,
+  reftet_2ea_1vb_splitedges, 
+  reftet_2ea_1vb_splitfaces, 
+  0,
+  reftet_2ea_1vb_newelstypes, 
+  reftet_2ea_1vb_newels
+};
+
+
+
+
+
+
+//  HP_TET_2EA_1VC,  // 2 edges connected
+int reftet_2ea_1vc_splitedges[][3] =
+{
+  { 1, 2, 5 },
+  { 1, 3, 6 },
+  { 1, 4, 7 },
+  //  { 2, 1, 8 },
+  { 2, 3, 9 },
+  { 2, 4, 10 },
+  { 3, 1, 11 },
+  { 3, 2, 12 },
+  { 3, 4, 13 },
+  { 4, 1, 14 },
+  { 4, 2, 15 },
+  { 4, 3, 16 },
+  { 0, 0, 0 }
+};
+int reftet_2ea_1vc_splitfaces[][4] =
+  {
+    { 1, 2, 3, 17 },
+    { 2, 3, 4, 18 },
+    { 3, 4, 2, 19 },
+    { 4, 2, 3, 20 },
+    { 0, 0, 0, 0 }
+  };
+int reftet_2ea_1vc_splitelements[][5] =
+  {
+    { 1, 2, 3, 4, 21 },
+    { 0, 0, 0, 0 }
+  };
+HPREF_ELEMENT_TYPE reftet_2ea_1vc_newelstypes[] =
+  {
+    HP_PYRAMID_EDGES,
+    //    HP_TET_1E_1VA,
+    HP_TET_0E_1V,
+    HP_PRISM_SINGEDGE,
+    HP_PRISM_SINGEDGE,
+
+    HP_TET, HP_TET, HP_TET, HP_TET, 
+    HP_PYRAMID, HP_PYRAMID, HP_PYRAMID, 
+    HP_PYRAMID, HP_PYRAMID, HP_TET,
+    HP_PYRAMID, HP_PYRAMID, HP_TET,
+    //     HP_PRISM,
+    //    HP_PRISM,
+    HP_NONE,
+  };
+int reftet_2ea_1vc_newels[][8] =
+{
+  { 1, 5, 17, 6, 7 },
+  // { 3, 11, 12, 13 },
+  { 4, 15, 14, 16 }, 
+  { 5, 17, 7, 2, 9, 10 },
+  { 6, 7, 17, 3, 13, 12 },
+ 
+  { 9, 10, 18, 21 },
+  { 13, 12, 19, 21 },
+  { 15, 16, 20, 21 },
+  { 18, 20, 19, 21 },
+  { 10, 15, 20, 18, 21 },
+  { 13, 19, 20, 16, 21 },
+  { 9, 18, 19, 12, 21 },
+  
+  { 7, 13, 16, 14, 21 },
+  { 7, 14, 15, 10, 21 },
+  { 9, 12, 17, 21 },
+  { 7, 10, 9, 17, 21 },
+  { 7, 17, 12, 13, 21 },
+  { 14, 16, 15, 21 },
+  //  { 17, 9, 12, 7, 10, 13 },
+  //  { 7, 10, 13, 14, 15, 16 },
+};
+HPRef_Struct reftet_2ea_1vc =
+{
+  HP_TET,
+  reftet_2ea_1vc_splitedges, 
+  reftet_2ea_1vc_splitfaces, 
+  reftet_2ea_1vc_splitelements, 
+  reftet_2ea_1vc_newelstypes, 
+  reftet_2ea_1vc_newels
+};
+
+
+
+
+
+
+
+
+
+
+
+ 
+//  HP_TET_2EA_2VA, 
+int reftet_2ea_2va_splitedges[][3] =
+{
+  { 1, 2, 5 },
+  { 1, 3, 6 },
+  { 1, 4, 7 },
+  { 2, 1, 8 },
+  { 2, 3, 9 },
+  { 2, 4, 10 },
+  { 3, 1, 11 },
+  { 3, 2, 12 },
+  { 3, 4, 13 },
+  { 0, 0, 0 }
+};
+int reftet_2ea_2va_splitfaces[][4] =
+  {
+    { 1, 2, 3, 17 },
+    { 0, 0, 0, 0 }
+  };
+HPREF_ELEMENT_TYPE reftet_2ea_2va_newelstypes[] =
+  {
+    HP_PYRAMID_EDGES,
+    HP_TET_1E_1VA,
+    HP_TET_1E_1VA,
+    HP_PRISM_SINGEDGE,
+    HP_PRISM_SINGEDGE,
+    HP_PRISM,
+    HP_TET,
+    HP_NONE,
+  };
+int reftet_2ea_2va_newels[][8] =
+{
+  { 1, 5, 17, 6, 7 },
+  { 3, 11, 12, 13 },
+  { 2, 8, 10, 9 },
+  { 5, 17, 7, 8, 9, 10 },
+  { 6, 7, 17, 11, 13, 12 },
+  { 17, 9, 12, 7, 10, 13 },
+  { 7, 10, 13, 4 },
+};
+HPRef_Struct reftet_2ea_2va =
+{
+  HP_TET,
+  reftet_2ea_2va_splitedges, 
+  reftet_2ea_2va_splitfaces, 
+  0,
+  reftet_2ea_2va_newelstypes, 
+  reftet_2ea_2va_newels
+};
+
+
+
+
+
+
+
+
+
+
+
+//  HP_TET_2EA_2VB,  // 2 edges connected
+int reftet_2ea_2vb_splitedges[][3] =
+{
+  { 1, 2, 5 },
+  { 1, 3, 6 },
+  { 1, 4, 7 },
+  { 2, 1, 8 },
+  { 2, 3, 9 },
+  { 2, 4, 10 },
+  //  { 3, 1, 11 },
+  { 3, 2, 12 },
+  { 3, 4, 13 },
+  { 4, 1, 14 },
+  { 4, 2, 15 },
+  { 4, 3, 16 },
+  { 0, 0, 0 }
+};
+int reftet_2ea_2vb_splitfaces[][4] =
+  {
+    { 1, 2, 3, 17 },
+    { 2, 3, 4, 18 },
+    { 3, 4, 2, 19 },
+    { 4, 2, 3, 20 },
+    { 0, 0, 0, 0 }
+  };
+int reftet_2ea_2vb_splitelements[][5] =
+  {
+    { 1, 2, 3, 4, 21 },
+    { 0, 0, 0, 0 }
+  };
+HPREF_ELEMENT_TYPE reftet_2ea_2vb_newelstypes[] =
+  {
+    HP_PYRAMID_EDGES,
+    HP_TET_1E_1VA,
+    //  HP_TET_1E_1VA,
+    HP_TET_0E_1V,
+    HP_PRISM_SINGEDGE,
+    HP_PRISM_SINGEDGE,
+
+    HP_TET, HP_TET, HP_TET, HP_TET, 
+    HP_PYRAMID, HP_PYRAMID, HP_PYRAMID, 
+    HP_PYRAMID, HP_PYRAMID, HP_TET,
+    HP_PYRAMID, HP_PYRAMID, HP_TET,
+    //     HP_PRISM,
+    //    HP_PRISM,
+    HP_NONE,
+  };
+int reftet_2ea_2vb_newels[][8] =
+{
+  { 1, 5, 17, 6, 7 },
+  { 2, 8, 10, 9 },
+  //  { 3, 11, 12, 13 },
+  { 4, 15, 14, 16 }, 
+  { 5, 17, 7, 8, 9, 10 },
+  { 6, 7, 17, 3, 13, 12 },
+ 
+  { 9, 10, 18, 21 },
+  { 13, 12, 19, 21 },
+  { 15, 16, 20, 21 },
+  { 18, 20, 19, 21 },
+  { 10, 15, 20, 18, 21 },
+  { 13, 19, 20, 16, 21 },
+  { 9, 18, 19, 12, 21 },
+  
+  { 7, 13, 16, 14, 21 },
+  { 7, 14, 15, 10, 21 },
+  { 9, 12, 17, 21 },
+  { 7, 10, 9, 17, 21 },
+  { 7, 17, 12, 13, 21 },
+  { 14, 16, 15, 21 },
+  //  { 17, 9, 12, 7, 10, 13 },
+  //  { 7, 10, 13, 14, 15, 16 },
+};
+HPRef_Struct reftet_2ea_2vb =
+{
+  HP_TET,
+  reftet_2ea_2vb_splitedges, 
+  reftet_2ea_2vb_splitfaces, 
+  reftet_2ea_2vb_splitelements, 
+  reftet_2ea_2vb_newelstypes, 
+  reftet_2ea_2vb_newels
+};
+
+
+
+
+
+
+
+ 
+
+
+//  HP_TET_2EA_2VC,  // 2 edges connected
+int reftet_2ea_2vc_splitedges[][3] =
+{
+  { 1, 2, 5 },
+  { 1, 3, 6 },
+  { 1, 4, 7 },
+  //  { 2, 1, 8 },
+  { 2, 3, 9 },
+  { 2, 4, 10 },
+  { 3, 1, 11 },
+  { 3, 2, 12 },
+  { 3, 4, 13 },
+  { 4, 1, 14 },
+  { 4, 2, 15 },
+  { 4, 3, 16 },
+  { 0, 0, 0 }
+};
+int reftet_2ea_2vc_splitfaces[][4] =
+  {
+    { 1, 2, 3, 17 },
+    { 2, 3, 4, 18 },
+    { 3, 4, 2, 19 },
+    { 4, 2, 3, 20 },
+    { 0, 0, 0, 0 }
+  };
+int reftet_2ea_2vc_splitelements[][5] =
+  {
+    { 1, 2, 3, 4, 21 },
+    { 0, 0, 0, 0 }
+  };
+HPREF_ELEMENT_TYPE reftet_2ea_2vc_newelstypes[] =
+  {
+    HP_PYRAMID_EDGES,
+    HP_TET_1E_1VA,
+    //    HP_TET_1E_1VA,
+    HP_TET_0E_1V,
+    HP_PRISM_SINGEDGE,
+    HP_PRISM_SINGEDGE,
+
+    HP_TET, HP_TET, HP_TET, HP_TET, 
+    HP_PYRAMID, HP_PYRAMID, HP_PYRAMID, 
+    HP_PYRAMID, HP_PYRAMID, HP_TET,
+    HP_PYRAMID, HP_PYRAMID, HP_TET,
+    //     HP_PRISM,
+    //    HP_PRISM,
+    HP_NONE,
+  };
+int reftet_2ea_2vc_newels[][8] =
+{
+  { 1, 5, 17, 6, 7 },
+  //  { 2, 8, 10, 9 },
+  { 3, 11, 12, 13 },
+  { 4, 15, 14, 16 }, 
+  { 5, 17, 7, 2, 9, 10 },
+  { 6, 7, 17, 11, 13, 12 },
+ 
+  { 9, 10, 18, 21 },
+  { 13, 12, 19, 21 },
+  { 15, 16, 20, 21 },
+  { 18, 20, 19, 21 },
+  { 10, 15, 20, 18, 21 },
+  { 13, 19, 20, 16, 21 },
+  { 9, 18, 19, 12, 21 },
+  
+  { 7, 13, 16, 14, 21 },
+  { 7, 14, 15, 10, 21 },
+  { 9, 12, 17, 21 },
+  { 7, 10, 9, 17, 21 },
+  { 7, 17, 12, 13, 21 },
+  { 14, 16, 15, 21 },
+  //  { 17, 9, 12, 7, 10, 13 },
+  //  { 7, 10, 13, 14, 15, 16 },
+};
+HPRef_Struct reftet_2ea_2vc =
+{
+  HP_TET,
+  reftet_2ea_2vc_splitedges, 
+  reftet_2ea_2vc_splitfaces, 
+  reftet_2ea_2vc_splitelements, 
+  reftet_2ea_2vc_newelstypes, 
+  reftet_2ea_2vc_newels
+};
+
+
+
+
+
+
+
+
+//  HP_TET_2EA_3V,  // 2 edges connected
+int reftet_2ea_3v_splitedges[][3] =
+{
+  { 1, 2, 5 },
+  { 1, 3, 6 },
+  { 1, 4, 7 },
+  { 2, 1, 8 },
+  { 2, 3, 9 },
+  { 2, 4, 10 },
+  { 3, 1, 11 },
+  { 3, 2, 12 },
+  { 3, 4, 13 },
+  { 4, 1, 14 },
+  { 4, 2, 15 },
+  { 4, 3, 16 },
+  { 0, 0, 0 }
+};
+int reftet_2ea_3v_splitfaces[][4] =
+  {
+    { 1, 2, 3, 17 },
+    { 2, 3, 4, 18 },
+    { 3, 4, 2, 19 },
+    { 4, 2, 3, 20 },
+    { 0, 0, 0, 0 }
+  };
+int reftet_2ea_3v_splitelements[][5] =
+  {
+    { 1, 2, 3, 4, 21 },
+    { 0, 0, 0, 0 }
+  };
+HPREF_ELEMENT_TYPE reftet_2ea_3v_newelstypes[] =
+  {
+    HP_PYRAMID_EDGES,
+    HP_TET_1E_1VA,
+    HP_TET_1E_1VA,
+    HP_TET_0E_1V,
+    HP_PRISM_SINGEDGE,
+    HP_PRISM_SINGEDGE,
+
+    HP_TET, HP_TET, HP_TET, HP_TET, 
+    HP_PYRAMID, HP_PYRAMID, HP_PYRAMID, 
+    HP_PYRAMID, HP_PYRAMID, HP_TET,
+    HP_PYRAMID, HP_PYRAMID, HP_TET,
+    //     HP_PRISM,
+    //    HP_PRISM,
+    HP_NONE,
+  };
+int reftet_2ea_3v_newels[][8] =
+{
+  { 1, 5, 17, 6, 7 },
+  { 2, 8, 10, 9 },
+  { 3, 11, 12, 13 },
+  { 4, 15, 14, 16 }, 
+  { 5, 17, 7, 8, 9, 10 },
+  { 6, 7, 17, 11, 13, 12 },
+ 
+  { 9, 10, 18, 21 },
+  { 13, 12, 19, 21 },
+  { 15, 16, 20, 21 },
+  { 18, 20, 19, 21 },
+  { 10, 15, 20, 18, 21 },
+  { 13, 19, 20, 16, 21 },
+  { 9, 18, 19, 12, 21 },
+  
+  { 7, 13, 16, 14, 21 },
+  { 7, 14, 15, 10, 21 },
+  { 9, 12, 17, 21 },
+  { 7, 10, 9, 17, 21 },
+  { 7, 17, 12, 13, 21 },
+  { 14, 16, 15, 21 },
+  //  { 17, 9, 12, 7, 10, 13 },
+  //  { 7, 10, 13, 14, 15, 16 },
+};
+HPRef_Struct reftet_2ea_3v =
+{
+  HP_TET,
+  reftet_2ea_3v_splitedges, 
+  reftet_2ea_3v_splitfaces, 
+  reftet_2ea_3v_splitelements, 
+  reftet_2ea_3v_newelstypes, 
+  reftet_2ea_3v_newels
+};
+
+
+
+
+
+
+
+//  HP_TET_2EB_0V,  // 2 opposite edges
+int reftet_2eb_0v_splitedges[][3] =
+{
+  { 1, 3, 5 },
+  { 1, 4, 6 },
+  { 2, 3, 7 },
+  { 2, 4, 8 },
+  { 3, 1, 9 },
+  { 3, 2, 10 },
+  { 4, 1, 11 },
+  { 4, 2, 12 },
+  { 0, 0, 0 }
+};
+
+HPREF_ELEMENT_TYPE reftet_2eb_0v_newelstypes[] =
+  {
+    HP_PRISM_SINGEDGE,
+    HP_PRISM_SINGEDGE,
+    HP_HEX,
+    HP_NONE,
+  };
+int reftet_2eb_0v_newels[][8] =
+{
+  { 1, 5, 6, 2, 7, 8 },
+  { 3, 9, 10, 4, 11, 12 },
+  { 6, 11, 12, 8, 5, 9, 10, 7 },
+};
+HPRef_Struct reftet_2eb_0v =
+{
+  HP_TET,
+  reftet_2eb_0v_splitedges, 
+  0, 0,
+  reftet_2eb_0v_newelstypes, 
+  reftet_2eb_0v_newels
+};
+
+
+//  HP_TET_2EB_1V,    // V1
+
+
+//  HP_TET_2EB_1V,  // 2 opposite edges, V1
+int reftet_2eb_1v_splitedges[][3] =
+{
+  { 1, 2, 5 },
+  { 1, 3, 6 },
+  { 1, 4, 7 },
+  { 2, 1, 8 },
+  { 2, 3, 9 },
+  { 2, 4, 10 },
+  { 3, 1, 11 },
+  { 3, 2, 12 },
+  { 3, 4, 13 },
+  { 4, 1, 14 },
+  { 4, 2, 15 },
+  { 4, 3, 16 },
+  { 0, 0, 0 }
+};
+
+HPREF_ELEMENT_TYPE reftet_2eb_1v_newelstypes[] =
+  {
+    HP_PRISM_SINGEDGE,
+    HP_PRISM_SINGEDGE,
+    HP_TET_1E_1VA,
+    //    HP_TET_1E_1VA,
+    //    HP_TET_1E_1VA,
+    //    HP_TET_1E_1VA,
+    HP_HEX,
+    HP_NONE,
+  };
+int reftet_2eb_1v_newels[][8] =
+{
+  { 5, 6, 7, 2, 9, 10 },
+  { 4, 15, 14, 3, 12, 11 },
+  { 1, 5, 6, 7 },
+  //  { 2, 8, 10, 9 },
+  //  { 3, 13, 11, 12 },
+  //  { 4, 16, 15, 14 },
+  { 7, 14, 15, 10, 6, 11, 12, 9 }
+};
+HPRef_Struct reftet_2eb_1v =
+{
+  HP_TET,
+  reftet_2eb_1v_splitedges, 
+  0, 0,
+  reftet_2eb_1v_newelstypes, 
+  reftet_2eb_1v_newels
+};
+
+
+
+//  HP_TET_2EB_2VA,  // 2 opposite edges, V1,2
+int reftet_2eb_2va_splitedges[][3] =
+{
+  { 1, 2, 5 },
+  { 1, 3, 6 },
+  { 1, 4, 7 },
+  { 2, 1, 8 },
+  { 2, 3, 9 },
+  { 2, 4, 10 },
+  { 3, 1, 11 },
+  { 3, 2, 12 },
+  { 3, 4, 13 },
+  { 4, 1, 14 },
+  { 4, 2, 15 },
+  { 4, 3, 16 },
+  { 0, 0, 0 }
+};
+
+HPREF_ELEMENT_TYPE reftet_2eb_2va_newelstypes[] =
+  {
+    HP_PRISM_SINGEDGE,
+    HP_PRISM_SINGEDGE,
+    HP_TET_1E_1VA,
+    HP_TET_1E_1VA,
+    //    HP_TET_1E_1VA,
+    //    HP_TET_1E_1VA,
+    HP_HEX,
+    HP_NONE,
+  };
+int reftet_2eb_2va_newels[][8] =
+{
+  { 5, 6, 7, 8, 9, 10 },
+  { 4, 15, 14, 3, 12, 11 },
+  { 1, 5, 6, 7 },
+  { 2, 8, 10, 9 },
+  //  { 3, 13, 11, 12 },
+  //  { 4, 16, 15, 14 },
+  { 7, 14, 15, 10, 6, 11, 12, 9 }
+};
+HPRef_Struct reftet_2eb_2va =
+{
+  HP_TET,
+  reftet_2eb_2va_splitedges, 
+  0, 0,
+  reftet_2eb_2va_newelstypes, 
+  reftet_2eb_2va_newels
+};
+
+
+//  HP_TET_2EB_2VB,   // V1,3
+int reftet_2eb_2vb_splitedges[][3] =
+{
+  { 1, 2, 5 },
+  { 1, 3, 6 },
+  { 1, 4, 7 },
+  { 2, 1, 8 },
+  { 2, 3, 9 },
+  { 2, 4, 10 },
+  { 3, 1, 11 },
+  { 3, 2, 12 },
+  { 3, 4, 13 },
+  { 4, 1, 14 },
+  { 4, 2, 15 },
+  { 4, 3, 16 },
+  { 0, 0, 0 }
+};
+
+HPREF_ELEMENT_TYPE reftet_2eb_2vb_newelstypes[] =
+  {
+    HP_PRISM_SINGEDGE,
+    HP_PRISM_SINGEDGE,
+    HP_TET_1E_1VA,
+    // HP_TET_1E_1VA,
+    HP_TET_1E_1VA,
+    // HP_TET_1E_1VA,
+    HP_HEX,
+    HP_NONE,
+  };
+int reftet_2eb_2vb_newels[][8] =
+{
+  { 5, 6, 7, 2, 9, 10 },
+  { 4, 15, 14, 13, 12, 11 },
+  { 1, 5, 6, 7 },
+  // { 2, 8, 10, 9 },
+  { 3, 13, 11, 12 },
+  // { 4, 16, 15, 14 },
+  { 7, 14, 15, 10, 6, 11, 12, 9 }
+};
+HPRef_Struct reftet_2eb_2vb =
+{
+  HP_TET,
+  reftet_2eb_2vb_splitedges, 
+  0, 0,
+  reftet_2eb_2vb_newelstypes, 
+  reftet_2eb_2vb_newels
+};
+
+
+
+
+//  HP_TET_2EB_2VC,   // V1,4
+int reftet_2eb_2vc_splitedges[][3] =
+{
+  { 1, 2, 5 },
+  { 1, 3, 6 },
+  { 1, 4, 7 },
+  { 2, 1, 8 },
+  { 2, 3, 9 },
+  { 2, 4, 10 },
+  { 3, 1, 11 },
+  { 3, 2, 12 },
+  { 3, 4, 13 },
+  { 4, 1, 14 },
+  { 4, 2, 15 },
+  { 4, 3, 16 },
+  { 0, 0, 0 }
+};
+
+HPREF_ELEMENT_TYPE reftet_2eb_2vc_newelstypes[] =
+  {
+    HP_PRISM_SINGEDGE,
+    HP_PRISM_SINGEDGE,
+    HP_TET_1E_1VA,
+    // HP_TET_1E_1VA,
+    // HP_TET_1E_1VA,
+    HP_TET_1E_1VA,
+    HP_HEX,
+    HP_NONE,
+  };
+int reftet_2eb_2vc_newels[][8] =
+{
+  { 5, 6, 7, 2, 9, 10 },
+  { 16, 15, 14, 3, 12, 11 },
+  { 1, 5, 6, 7 },
+  // { 2, 8, 10, 9 },
+  // { 3, 13, 11, 12 },
+  { 4, 16, 15, 14 },
+  { 7, 14, 15, 10, 6, 11, 12, 9 }
+};
+HPRef_Struct reftet_2eb_2vc =
+{
+  HP_TET,
+  reftet_2eb_2vc_splitedges, 
+  0, 0,
+  reftet_2eb_2vc_newelstypes, 
+  reftet_2eb_2vc_newels
+};
+
+
+
+
+
+
+//  HP_TET_2EB_3V,    // V1,2,3
+int reftet_2eb_3v_splitedges[][3] =
+{
+  { 1, 2, 5 },
+  { 1, 3, 6 },
+  { 1, 4, 7 },
+  { 2, 1, 8 },
+  { 2, 3, 9 },
+  { 2, 4, 10 },
+  { 3, 1, 11 },
+  { 3, 2, 12 },
+  { 3, 4, 13 },
+  { 4, 1, 14 },
+  { 4, 2, 15 },
+  { 4, 3, 16 },
+  { 0, 0, 0 }
+};
+
+HPREF_ELEMENT_TYPE reftet_2eb_3v_newelstypes[] =
+  {
+    HP_PRISM_SINGEDGE,
+    HP_PRISM_SINGEDGE,
+    HP_TET_1E_1VA,
+    HP_TET_1E_1VA,
+    HP_TET_1E_1VA,
+    // HP_TET_1E_1VA,
+    HP_HEX,
+    HP_NONE,
+  };
+int reftet_2eb_3v_newels[][8] =
+{
+  { 5, 6, 7, 8, 9, 10 },
+  { 4, 15, 14, 13, 12, 11 },
+  { 1, 5, 6, 7 },
+  { 2, 8, 10, 9 },
+  { 3, 13, 11, 12 },
+  // { 4, 16, 15, 14 },
+  { 7, 14, 15, 10, 6, 11, 12, 9 }
+};
+HPRef_Struct reftet_2eb_3v =
+{
+  HP_TET,
+  reftet_2eb_3v_splitedges, 
+  0, 0,
+  reftet_2eb_3v_newelstypes, 
+  reftet_2eb_3v_newels
+};
+
+
+
+
+
+
+//  HP_TET_2EB_4V,  // 2 opposite edges
+int reftet_2eb_4v_splitedges[][3] =
+{
+  { 1, 2, 5 },
+  { 1, 3, 6 },
+  { 1, 4, 7 },
+  { 2, 1, 8 },
+  { 2, 3, 9 },
+  { 2, 4, 10 },
+  { 3, 1, 11 },
+  { 3, 2, 12 },
+  { 3, 4, 13 },
+  { 4, 1, 14 },
+  { 4, 2, 15 },
+  { 4, 3, 16 },
+  { 0, 0, 0 }
+};
+
+HPREF_ELEMENT_TYPE reftet_2eb_4v_newelstypes[] =
+  {
+    HP_PRISM_SINGEDGE,
+    HP_PRISM_SINGEDGE,
+    HP_TET_1E_1VA,
+    HP_TET_1E_1VA,
+    HP_TET_1E_1VA,
+    HP_TET_1E_1VA,
+    HP_HEX,
+    HP_NONE,
+  };
+int reftet_2eb_4v_newels[][8] =
+{
+  { 5, 6, 7, 8, 9, 10 },
+  { 16, 15, 14, 13, 12, 11 },
+  { 1, 5, 6, 7 },
+  { 2, 8, 10, 9 },
+  { 3, 13, 11, 12 },
+  { 4, 16, 15, 14 },
+  { 7, 14, 15, 10, 6, 11, 12, 9 }
+};
+HPRef_Struct reftet_2eb_4v =
+{
+  HP_TET,
+  reftet_2eb_4v_splitedges, 
+  0, 0,
+  reftet_2eb_4v_newelstypes, 
+  reftet_2eb_4v_newels
+};
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+//  HP_TET_3EA_0V,  
+int reftet_3ea_0v_splitedges[][3] =
+{
+  { 1, 2, 5 },
+  { 1, 3, 6 },
+  { 1, 4, 7 },
+  { 2, 3, 8 },
+  { 2, 4, 9 },
+  { 3, 2, 10 },
+  { 3, 4, 11 },
+  { 4, 2, 12 },
+  { 4, 3, 13 },
+  { 0, 0, 0 }
+};
+int reftet_3ea_0v_splitfaces[][4] =
+  {
+    { 1, 2, 3, 14 },
+    { 1, 2, 4, 15 },
+    { 1, 3, 4, 16 },
+    { 2, 3, 4, 17 },
+    { 3, 4, 2, 18 },
+    { 4, 2, 3, 19 },
+    { 0, 0, 0, 0 }
+  };
+int reftet_3ea_0v_splitelements[][5] =
+  {
+    { 1, 2, 3, 4, 20 },
+    { 0 },
+  };
+
+HPREF_ELEMENT_TYPE reftet_3ea_0v_newelstypes[] =
+  {
+    HP_HEX_3E_0V,
+    HP_HEX_1E_0V,
+    HP_HEX_1E_0V,
+    HP_HEX_1E_0V,
+    HP_PRISM,
+    HP_PRISM,
+    HP_PRISM,
+    HP_TET,
+    HP_NONE,
+  };
+int reftet_3ea_0v_newels[][8] =
+{
+  { 1, 5, 14, 6, 7, 15, 20, 16 },
+  { 5, 2, 8, 14, 15, 9, 17, 20 },
+  { 3, 6, 14, 10, 11, 16, 20, 18 },
+  { 7, 4, 12, 15, 16, 13, 19, 20 },
+  { 11, 13, 16, 18, 19, 20 },
+  { 15, 12, 9, 20, 19, 17 },
+  { 8, 10, 14, 17, 18, 20 },
+  { 20, 17, 18, 19 },
+};
+HPRef_Struct reftet_3ea_0v =
+{
+  HP_TET,
+  reftet_3ea_0v_splitedges, 
+  reftet_3ea_0v_splitfaces, 
+  reftet_3ea_0v_splitelements, 
+  reftet_3ea_0v_newelstypes, 
+  reftet_3ea_0v_newels
+};
+
+
+
+
+
+
+
+
+
+
+//  HP_TET_3EA_1V,  
+int reftet_3ea_1v_splitedges[][3] =
+{
+  { 1, 2, 5 },
+  { 1, 3, 6 },
+  { 1, 4, 7 },
+  { 2, 3, 8 },
+  { 2, 4, 9 },
+  { 3, 2, 10 },
+  { 3, 4, 11 },
+  { 4, 2, 12 },
+  { 4, 3, 13 },
+  { 2, 1, 21 },
+  { 3, 1, 22 },
+  { 4, 1, 23 },
+  { 0, 0, 0 }
+};
+int reftet_3ea_1v_splitfaces[][4] =
+  {
+    { 1, 2, 3, 14 },
+    { 1, 2, 4, 15 },
+    { 1, 3, 4, 16 },
+    { 2, 3, 4, 17 },
+    { 3, 4, 2, 18 },
+    { 4, 2, 3, 19 },
+    { 0, 0, 0, 0 }
+  };
+int reftet_3ea_1v_splitelements[][5] =
+  {
+    { 1, 2, 3, 4, 20 },
+    { 0 },
+  };
+
+HPREF_ELEMENT_TYPE reftet_3ea_1v_newelstypes[] =
+  {
+    HP_HEX_3E_0V,
+    HP_TET_1E_1VA,
+    HP_PRISM_SINGEDGE,
+    HP_PRISM,
+    //    HP_TET_1E_1VA,
+    HP_PRISM_SINGEDGE,
+    HP_PRISM,
+    //    HP_TET_1E_1VA,
+    HP_PRISM_SINGEDGE,
+    HP_PRISM,
+
+    HP_PRISM,
+    HP_PRISM,
+    HP_PRISM,
+    HP_TET,
+    HP_NONE,
+  };
+int reftet_3ea_1v_newels[][8] =
+{
+  { 1, 5, 14, 6, 7, 15, 20, 16 },
+
+  { 2, 21, 9, 8 },
+  { 5, 14, 15, 21, 8, 9 },
+  { 15, 14, 20, 9, 8, 17 },
+  //  { 3, 22, 10, 11 },
+  //  { 6, 16, 14, 22, 11, 10 },
+  { 6, 16, 14, 3, 11, 10 },
+  { 14, 16, 20, 10, 11, 18 },
+  //  { 4, 23, 13, 12 },
+  //  { 7, 15, 16, 23, 12, 13 },
+  { 7, 15, 16, 4, 12, 13 },
+  { 16, 15, 20, 13, 12, 19 },
+
+  { 11, 13, 16, 18, 19, 20 },
+  { 15, 12, 9, 20, 19, 17 },
+  { 8, 10, 14, 17, 18, 20 },
+  { 20, 17, 18, 19 },
+};
+HPRef_Struct reftet_3ea_1v =
+{
+  HP_TET,
+  reftet_3ea_1v_splitedges, 
+  reftet_3ea_1v_splitfaces, 
+  reftet_3ea_1v_splitelements, 
+  reftet_3ea_1v_newelstypes, 
+  reftet_3ea_1v_newels
+};
+
+
+
+
+
+
+
+
+
+
+//  HP_TET_3EA_2V,  
+int reftet_3ea_2v_splitedges[][3] =
+{
+  { 1, 2, 5 },
+  { 1, 3, 6 },
+  { 1, 4, 7 },
+  { 2, 3, 8 },
+  { 2, 4, 9 },
+  { 3, 2, 10 },
+  { 3, 4, 11 },
+  { 4, 2, 12 },
+  { 4, 3, 13 },
+  { 2, 1, 21 },
+  { 3, 1, 22 },
+  { 4, 1, 23 },
+  { 0, 0, 0 }
+};
+int reftet_3ea_2v_splitfaces[][4] =
+  {
+    { 1, 2, 3, 14 },
+    { 1, 2, 4, 15 },
+    { 1, 3, 4, 16 },
+    { 2, 3, 4, 17 },
+    { 3, 4, 2, 18 },
+    { 4, 2, 3, 19 },
+    { 0, 0, 0, 0 }
+  };
+int reftet_3ea_2v_splitelements[][5] =
+  {
+    { 1, 2, 3, 4, 20 },
+    { 0 },
+  };
+
+HPREF_ELEMENT_TYPE reftet_3ea_2v_newelstypes[] =
+  {
+    HP_HEX_3E_0V,
+    HP_TET_1E_1VA,
+    HP_PRISM_SINGEDGE,
+    HP_PRISM,
+    HP_TET_1E_1VA,
+    HP_PRISM_SINGEDGE,
+    HP_PRISM,
+    //    HP_TET_1E_1VA,
+    HP_PRISM_SINGEDGE,
+    HP_PRISM,
+
+    HP_PRISM,
+    HP_PRISM,
+    HP_PRISM,
+    HP_TET,
+    HP_NONE,
+  };
+int reftet_3ea_2v_newels[][8] =
+{
+  { 1, 5, 14, 6, 7, 15, 20, 16 },
+
+  { 2, 21, 9, 8 },
+  { 5, 14, 15, 21, 8, 9 },
+  { 15, 14, 20, 9, 8, 17 },
+  { 3, 22, 10, 11 },
+  { 6, 16, 14, 22, 11, 10 },
+  { 14, 16, 20, 10, 11, 18 },
+  //  { 4, 23, 13, 12 },
+  { 7, 15, 16, 4, 12, 13 },
+  { 16, 15, 20, 13, 12, 19 },
+
+  { 11, 13, 16, 18, 19, 20 },
+  { 15, 12, 9, 20, 19, 17 },
+  { 8, 10, 14, 17, 18, 20 },
+  { 20, 17, 18, 19 },
+};
+HPRef_Struct reftet_3ea_2v =
+{
+  HP_TET,
+  reftet_3ea_2v_splitedges, 
+  reftet_3ea_2v_splitfaces, 
+  reftet_3ea_2v_splitelements, 
+  reftet_3ea_2v_newelstypes, 
+  reftet_3ea_2v_newels
+};
+
+
+
+
+
+
+
+
+//  HP_TET_3EA_3V,  
+int reftet_3ea_3v_splitedges[][3] =
+{
+  { 1, 2, 5 },
+  { 1, 3, 6 },
+  { 1, 4, 7 },
+  { 2, 3, 8 },
+  { 2, 4, 9 },
+  { 3, 2, 10 },
+  { 3, 4, 11 },
+  { 4, 2, 12 },
+  { 4, 3, 13 },
+  { 2, 1, 21 },
+  { 3, 1, 22 },
+  { 4, 1, 23 },
+  { 0, 0, 0 }
+};
+int reftet_3ea_3v_splitfaces[][4] =
+  {
+    { 1, 2, 3, 14 },
+    { 1, 2, 4, 15 },
+    { 1, 3, 4, 16 },
+    { 2, 3, 4, 17 },
+    { 3, 4, 2, 18 },
+    { 4, 2, 3, 19 },
+    { 0, 0, 0, 0 }
+  };
+int reftet_3ea_3v_splitelements[][5] =
+  {
+    { 1, 2, 3, 4, 20 },
+    { 0 },
+  };
+
+HPREF_ELEMENT_TYPE reftet_3ea_3v_newelstypes[] =
+  {
+    HP_HEX_3E_0V,
+    HP_TET_1E_1VA,
+    HP_PRISM_SINGEDGE,
+    HP_PRISM,
+    HP_TET_1E_1VA,
+    HP_PRISM_SINGEDGE,
+    HP_PRISM,
+    HP_TET_1E_1VA,
+    HP_PRISM_SINGEDGE,
+    HP_PRISM,
+
+    HP_PRISM,
+    HP_PRISM,
+    HP_PRISM,
+    HP_TET,
+    HP_NONE,
+  };
+int reftet_3ea_3v_newels[][8] =
+{
+  { 1, 5, 14, 6, 7, 15, 20, 16 },
+
+  { 2, 21, 9, 8 },
+  { 5, 14, 15, 21, 8, 9 },
+  { 15, 14, 20, 9, 8, 17 },
+  { 3, 22, 10, 11 },
+  { 6, 16, 14, 22, 11, 10 },
+  { 14, 16, 20, 10, 11, 18 },
+  { 4, 23, 13, 12 },
+  { 7, 15, 16, 23, 12, 13 },
+  { 16, 15, 20, 13, 12, 19 },
+
+  { 11, 13, 16, 18, 19, 20 },
+  { 15, 12, 9, 20, 19, 17 },
+  { 8, 10, 14, 17, 18, 20 },
+  { 20, 17, 18, 19 },
+};
+HPRef_Struct reftet_3ea_3v =
+{
+  HP_TET,
+  reftet_3ea_3v_splitedges, 
+  reftet_3ea_3v_splitfaces, 
+  reftet_3ea_3v_splitelements, 
+  reftet_3ea_3v_newelstypes, 
+  reftet_3ea_3v_newels
+};
+
+
+
+
+
+
+
+//  HP_TET_3EV_0V,  
+int reftet_3eb_0v_splitedges[][3] =
+{
+  { 1, 2, 5 },
+  { 1, 3, 6 },
+  { 1, 4, 7 },
+  { 2, 1, 8 },
+  { 2, 3, 9 },
+  { 2, 4, 10 },
+  { 3, 1, 11 },
+  //  { 3, 2, 12 },
+  { 3, 4, 13 },
+  //  { 4, 1, 14 },
+  { 4, 2, 15 },
+  { 4, 3, 16 },
+  { 0, 0, 0 }
+};
+int reftet_3eb_0v_splitfaces[][4] =
+  {
+    { 1, 2, 4, 17 },
+    { 2, 1, 3, 18 },
+    { 0, 0, 0, 0 }
+  };
+int reftet_3eb_0v_splitelements[][5] =
+  {
+    { 1, 2, 3, 4, 20 },
+    { 0 },
+  };
+
+HPREF_ELEMENT_TYPE reftet_3eb_0v_newelstypes[] =
+  {
+    HP_PYRAMID_EDGES,
+    HP_PYRAMID_EDGES,
+    //    HP_TET_1E_1VA,
+    //    HP_TET_1E_1VA,
+    HP_PRISM_SINGEDGE,
+    HP_PRISM_SINGEDGE,
+    HP_PRISM_SINGEDGE,
+    
+    HP_PYRAMID,
+    HP_PYRAMID,
+    HP_TET,
+    HP_TET,
+    HP_PYRAMID,
+    HP_PYRAMID,
+    HP_PYRAMID,
+    HP_NONE,
+  };
+int reftet_3eb_0v_newels[][8] =
+{
+  { 1, 7, 17, 5, 6 },
+  { 2, 9, 18, 8, 10 },
+  //  { 3, 12, 13, 11 },
+  //  { 4, 14, 16, 15 },
+  { 5, 6, 17, 8, 18, 10 },
+  { 7, 17, 6, 4, 15, 16 },
+  { 9, 18, 10, 3, 11, 13 },
+  
+  { 10, 15, 16, 13, 20 },
+  { 6, 11, 13, 16, 20 },
+  { 10, 17, 15, 20 },
+  { 6, 18, 11, 20 },
+  { 6, 17, 10, 18, 20 },
+  { 6, 16, 15, 17, 20 },
+  { 18, 10, 13, 11, 20 },
+};
+HPRef_Struct reftet_3eb_0v =
+{
+  HP_TET,
+  reftet_3eb_0v_splitedges, 
+  reftet_3eb_0v_splitfaces, 
+  reftet_3eb_0v_splitelements, 
+  reftet_3eb_0v_newelstypes, 
+  reftet_3eb_0v_newels
+};
+
+
+
+
+
+
+
+
+
+//  HP_TET_3EV_1V,  
+int reftet_3eb_1v_splitedges[][3] =
+{
+  { 1, 2, 5 },
+  { 1, 3, 6 },
+  { 1, 4, 7 },
+  { 2, 1, 8 },
+  { 2, 3, 9 },
+  { 2, 4, 10 },
+  { 3, 1, 11 },
+  { 3, 2, 12 },
+  { 3, 4, 13 },
+  //  { 4, 1, 14 },
+  { 4, 2, 15 },
+  { 4, 3, 16 },
+  { 0, 0, 0 }
+};
+int reftet_3eb_1v_splitfaces[][4] =
+  {
+    { 1, 2, 4, 17 },
+    { 2, 1, 3, 18 },
+    { 0, 0, 0, 0 }
+  };
+int reftet_3eb_1v_splitelements[][5] =
+  {
+    { 1, 2, 3, 4, 20 },
+    { 0 },
+  };
+
+HPREF_ELEMENT_TYPE reftet_3eb_1v_newelstypes[] =
+  {
+    HP_PYRAMID_EDGES,
+    HP_PYRAMID_EDGES,
+    HP_TET_1E_1VA,
+    //    HP_TET_1E_1VA,
+    HP_PRISM_SINGEDGE,
+    HP_PRISM_SINGEDGE,
+    HP_PRISM_SINGEDGE,
+    
+    HP_PYRAMID,
+    HP_PYRAMID,
+    HP_TET,
+    HP_TET,
+    HP_PYRAMID,
+    HP_PYRAMID,
+    HP_PYRAMID,
+    HP_NONE,
+  };
+int reftet_3eb_1v_newels[][8] =
+{
+  { 1, 7, 17, 5, 6 },
+  { 2, 9, 18, 8, 10 },
+  { 3, 12, 13, 11 },
+  //  { 4, 14, 16, 15 },
+  { 5, 6, 17, 8, 18, 10 },
+  { 7, 17, 6, 4, 15, 16 },
+  { 9, 18, 10, 12, 11, 13 },
+  
+  { 10, 15, 16, 13, 20 },
+  { 6, 11, 13, 16, 20 },
+  { 10, 17, 15, 20 },
+  { 6, 18, 11, 20 },
+  { 6, 17, 10, 18, 20 },
+  { 6, 16, 15, 17, 20 },
+  { 18, 10, 13, 11, 20 },
+};
+HPRef_Struct reftet_3eb_1v =
+{
+  HP_TET,
+  reftet_3eb_1v_splitedges, 
+  reftet_3eb_1v_splitfaces, 
+  reftet_3eb_1v_splitelements, 
+  reftet_3eb_1v_newelstypes, 
+  reftet_3eb_1v_newels
+};
+
+
+
+
+
+
+
+
+//  HP_TET_3EV_2V,  
+int reftet_3eb_2v_splitedges[][3] =
+{
+  { 1, 2, 5 },
+  { 1, 3, 6 },
+  { 1, 4, 7 },
+  { 2, 1, 8 },
+  { 2, 3, 9 },
+  { 2, 4, 10 },
+  { 3, 1, 11 },
+  { 3, 2, 12 },
+  { 3, 4, 13 },
+  { 4, 1, 14 },
+  { 4, 2, 15 },
+  { 4, 3, 16 },
+  { 0, 0, 0 }
+};
+int reftet_3eb_2v_splitfaces[][4] =
+  {
+    { 1, 2, 4, 17 },
+    { 2, 1, 3, 18 },
+    { 0, 0, 0, 0 }
+  };
+int reftet_3eb_2v_splitelements[][5] =
+  {
+    { 1, 2, 3, 4, 20 },
+    { 0 },
+  };
+
+HPREF_ELEMENT_TYPE reftet_3eb_2v_newelstypes[] =
+  {
+    HP_PYRAMID_EDGES,
+    HP_PYRAMID_EDGES,
+    HP_TET_1E_1VA,
+    HP_TET_1E_1VA,
+    HP_PRISM_SINGEDGE,
+    HP_PRISM_SINGEDGE,
+    HP_PRISM_SINGEDGE,
+    
+    HP_PYRAMID,
+    HP_PYRAMID,
+    HP_TET,
+    HP_TET,
+    HP_PYRAMID,
+    HP_PYRAMID,
+    HP_PYRAMID,
+    HP_NONE,
+  };
+int reftet_3eb_2v_newels[][8] =
+{
+  { 1, 7, 17, 5, 6 },
+  { 2, 9, 18, 8, 10 },
+  { 3, 12, 13, 11 },
+  { 4, 14, 16, 15 },
+  { 5, 6, 17, 8, 18, 10 },
+  { 7, 17, 6, 14, 15, 16 },
+  { 9, 18, 10, 12, 11, 13 },
+  
+  { 10, 15, 16, 13, 20 },
+  { 6, 11, 13, 16, 20 },
+  { 10, 17, 15, 20 },
+  { 6, 18, 11, 20 },
+  { 6, 17, 10, 18, 20 },
+  { 6, 16, 15, 17, 20 },
+  { 18, 10, 13, 11, 20 },
+};
+HPRef_Struct reftet_3eb_2v =
+{
+  HP_TET,
+  reftet_3eb_2v_splitedges, 
+  reftet_3eb_2v_splitfaces, 
+  reftet_3eb_2v_splitelements, 
+  reftet_3eb_2v_newelstypes, 
+  reftet_3eb_2v_newels
+};
+
+
+
+
+
+
+
+
+
+
+
+
+
+//  HP_TET_3EC_0V,  
+int reftet_3ec_0v_splitedges[][3] =
+{
+  { 1, 2, 5 },
+  { 1, 3, 6 },
+  { 1, 4, 7 },
+  { 2, 1, 8 },
+  { 2, 3, 9 },
+  { 2, 4, 10 },
+  //  { 3, 1, 11 },
+  { 3, 2, 12 },
+  { 3, 4, 13 },
+  { 4, 1, 14 },
+  //  { 4, 2, 15 },
+  { 4, 3, 16 },
+  { 0, 0, 0 }
+};
+int reftet_3ec_0v_splitfaces[][4] =
+  {
+    { 1, 2, 3, 17 },
+    { 2, 1, 4, 18 },
+    { 0, 0, 0, 0 }
+  };
+int reftet_3ec_0v_splitelements[][5] =
+  {
+    { 1, 2, 3, 4, 20 },
+    { 0 },
+  };
+
+HPREF_ELEMENT_TYPE reftet_3ec_0v_newelstypes[] =
+  {
+    HP_PYRAMID_EDGES,
+    HP_PYRAMID_EDGES,
+    //    HP_TET_1E_1VA,
+    //    HP_TET_1E_1VA,
+    HP_PRISM_SINGEDGE,
+    HP_PRISM_SINGEDGE,
+    HP_PRISM_SINGEDGE,
+    
+    HP_PYRAMID,
+    HP_PYRAMID,
+    HP_TET,
+    HP_TET,
+    HP_PYRAMID,
+    HP_PYRAMID,
+    HP_PYRAMID,
+    HP_NONE,
+  };
+int reftet_3ec_0v_newels[][8] =
+{
+  { 1, 5, 17, 6, 7 },
+  { 2, 8, 18, 10, 9 },
+  //  { 3, 11, 12, 13 },
+  //  { 4, 15, 14, 16 },
+  { 5, 17, 7, 8, 9, 18 },
+  { 6, 7, 17, 3, 13, 12 },
+  { 10, 9, 18, 4, 16, 14 },
+  
+  { 9, 16, 13, 12, 20 },
+  { 7, 13, 16, 14, 20 },
+  { 7, 14, 18, 20 },
+  { 9, 12, 17, 20 },
+  { 17, 7, 18, 9, 20 },
+  { 7, 17, 12, 13, 20 },
+  { 9, 18, 14, 16, 20 },
+};
+HPRef_Struct reftet_3ec_0v =
+{
+  HP_TET,
+  reftet_3ec_0v_splitedges, 
+  reftet_3ec_0v_splitfaces, 
+  reftet_3ec_0v_splitelements, 
+  reftet_3ec_0v_newelstypes, 
+  reftet_3ec_0v_newels
+};
+
+
+
+
+
+
+ 
+
+
+//  HP_TET_3EC_1V,  
+int reftet_3ec_1v_splitedges[][3] =
+{
+  { 1, 2, 5 },
+  { 1, 3, 6 },
+  { 1, 4, 7 },
+  { 2, 1, 8 },
+  { 2, 3, 9 },
+  { 2, 4, 10 },
+  { 3, 1, 11 },
+  { 3, 2, 12 },
+  { 3, 4, 13 },
+  { 4, 1, 14 },
+  // { 4, 2, 15 },
+  { 4, 3, 16 },
+  { 0, 0, 0 }
+};
+int reftet_3ec_1v_splitfaces[][4] =
+  {
+    { 1, 2, 3, 17 },
+    { 2, 1, 4, 18 },
+    { 0, 0, 0, 0 }
+  };
+int reftet_3ec_1v_splitelements[][5] =
+  {
+    { 1, 2, 3, 4, 20 },
+    { 0 },
+  };
+
+HPREF_ELEMENT_TYPE reftet_3ec_1v_newelstypes[] =
+  {
+    HP_PYRAMID_EDGES,
+    HP_PYRAMID_EDGES,
+    HP_TET_1E_1VA,
+    //    HP_TET_1E_1VA,
+    HP_PRISM_SINGEDGE,
+    HP_PRISM_SINGEDGE,
+    HP_PRISM_SINGEDGE,
+    
+    HP_PYRAMID,
+    HP_PYRAMID,
+    HP_TET,
+    HP_TET,
+    HP_PYRAMID,
+    HP_PYRAMID,
+    HP_PYRAMID,
+    HP_NONE,
+  };
+int reftet_3ec_1v_newels[][8] =
+{
+  { 1, 5, 17, 6, 7 },
+  { 2, 8, 18, 10, 9 },
+  { 3, 11, 12, 13 },
+  //  { 4, 15, 14, 16 },
+  { 5, 17, 7, 8, 9, 18 },
+  { 6, 7, 17, 11, 13, 12 },
+  { 10, 9, 18, 4, 16, 14 },
+  
+  { 9, 16, 13, 12, 20 },
+  { 7, 13, 16, 14, 20 },
+  { 7, 14, 18, 20 },
+  { 9, 12, 17, 20 },
+  { 17, 7, 18, 9, 20 },
+  { 7, 17, 12, 13, 20 },
+  { 9, 18, 14, 16, 20 },
+};
+HPRef_Struct reftet_3ec_1v =
+{
+  HP_TET,
+  reftet_3ec_1v_splitedges, 
+  reftet_3ec_1v_splitfaces, 
+  reftet_3ec_1v_splitelements, 
+  reftet_3ec_1v_newelstypes, 
+  reftet_3ec_1v_newels
+};
+
+
+
+
+
+
+
+
+//  HP_TET_3EC_2V,  
+int reftet_3ec_2v_splitedges[][3] =
+{
+  { 1, 2, 5 },
+  { 1, 3, 6 },
+  { 1, 4, 7 },
+  { 2, 1, 8 },
+  { 2, 3, 9 },
+  { 2, 4, 10 },
+  { 3, 1, 11 },
+  { 3, 2, 12 },
+  { 3, 4, 13 },
+  { 4, 1, 14 },
+  { 4, 2, 15 },
+  { 4, 3, 16 },
+  { 0, 0, 0 }
+};
+int reftet_3ec_2v_splitfaces[][4] =
+  {
+    { 1, 2, 3, 17 },
+    { 2, 1, 4, 18 },
+    { 0, 0, 0, 0 }
+  };
+int reftet_3ec_2v_splitelements[][5] =
+  {
+    { 1, 2, 3, 4, 20 },
+    { 0 },
+  };
+
+HPREF_ELEMENT_TYPE reftet_3ec_2v_newelstypes[] =
+  {
+    HP_PYRAMID_EDGES,
+    HP_PYRAMID_EDGES,
+    HP_TET_1E_1VA,
+    HP_TET_1E_1VA,
+    HP_PRISM_SINGEDGE,
+    HP_PRISM_SINGEDGE,
+    HP_PRISM_SINGEDGE,
+    
+    HP_PYRAMID,
+    HP_PYRAMID,
+    HP_TET,
+    HP_TET,
+    HP_PYRAMID,
+    HP_PYRAMID,
+    HP_PYRAMID,
+    HP_NONE,
+  };
+int reftet_3ec_2v_newels[][8] =
+{
+  { 1, 5, 17, 6, 7 },
+  { 2, 8, 18, 10, 9 },
+  { 3, 11, 12, 13 },
+  { 4, 15, 14, 16 },
+  { 5, 17, 7, 8, 9, 18 },
+  { 6, 7, 17, 11, 13, 12 },
+  { 10, 9, 18, 15, 16, 14 },
+  
+  { 9, 16, 13, 12, 20 },
+  { 7, 13, 16, 14, 20 },
+  { 7, 14, 18, 20 },
+  { 9, 12, 17, 20 },
+  { 17, 7, 18, 9, 20 },
+  { 7, 17, 12, 13, 20 },
+  { 9, 18, 14, 16, 20 },
+};
+HPRef_Struct reftet_3ec_2v =
+{
+  HP_TET,
+  reftet_3ec_2v_splitedges, 
+  reftet_3ec_2v_splitfaces, 
+  reftet_3ec_2v_splitelements, 
+  reftet_3ec_2v_newelstypes, 
+  reftet_3ec_2v_newels
+};
+
+
+
+
+
+
+
+
+
+
+/* ************************ 1 singular face ******************** */
+
+
+// HP_TET_1F_0E_0V
+int reftet_1f_0e_0v_splitedges[][3] =
+{
+  { 2, 1, 5 },
+  { 3, 1, 6 },
+  { 4, 1, 7 },
+  { 0, 0, 0 }
+};
+HPREF_ELEMENT_TYPE reftet_1f_0e_0v_newelstypes[] =
+{
+  HP_PRISM_1FA_0E_0V,
+  HP_TET,
+  HP_NONE,
+};
+int reftet_1f_0e_0v_newels[][8] =
+{
+  { 3, 2, 4, 6, 5, 7 },
+  { 5, 7, 6, 1 }
+};
+HPRef_Struct reftet_1f_0e_0v =
+{
+  HP_TET,
+  reftet_1f_0e_0v_splitedges, 
+  0, 0,
+  reftet_1f_0e_0v_newelstypes, 
+  reftet_1f_0e_0v_newels
+};
+
+
+
+
+
+// HP_TET_1F_0E_1VA    ... singular vertex in face
+int reftet_1f_0e_1va_splitedges[][3] =
+{
+  { 2, 1, 5 },
+  { 2, 3, 6 },
+  { 2, 4, 7 },
+  { 3, 1, 8 },
+  { 4, 1, 9 },
+  { 0, 0, 0 }
+};
+HPREF_ELEMENT_TYPE reftet_1f_0e_1va_newelstypes[] =
+{
+  HP_HEX_1F_0E_0V,
+  HP_TET_1F_0E_1VA,
+  HP_TET,
+  HP_NONE,
+};
+int reftet_1f_0e_1va_newels[][8] =
+{
+  { 3, 6, 7, 4, 8, 5, 5, 9 },
+  { 5, 2, 6, 7 },
+  { 5, 9, 8, 1 },
+};
+HPRef_Struct reftet_1f_0e_1va =
+{
+  HP_TET,
+  reftet_1f_0e_1va_splitedges, 
+  0, 0,
+  reftet_1f_0e_1va_newelstypes, 
+  reftet_1f_0e_1va_newels
+};
+
+
+
+
+
+// HP_TET_1F_0E_1VB    ... singular vertex not in face
+int reftet_1f_0e_1vb_splitedges[][3] =
+{
+  { 1, 2, 5 },
+  { 1, 3, 6 },
+  { 1, 4, 7 },
+  { 2, 1, 8 },
+  { 3, 1, 9 },
+  { 4, 1, 10 },
+  { 0, 0, 0 }
+};
+HPREF_ELEMENT_TYPE reftet_1f_0e_1vb_newelstypes[] =
+{
+  HP_PRISM_1FA_0E_0V,
+  HP_PRISM,
+  HP_TET_0E_1V,
+  HP_NONE,
+};
+int reftet_1f_0e_1vb_newels[][8] =
+{
+  { 2, 4, 3, 8, 10, 9 },
+  { 8, 10, 9, 5, 7, 6 }, 
+  { 1, 5, 6, 7 },
+};
+HPRef_Struct reftet_1f_0e_1vb =
+{
+  HP_TET,
+  reftet_1f_0e_1vb_splitedges, 
+  0, 0,
+  reftet_1f_0e_1vb_newelstypes, 
+  reftet_1f_0e_1vb_newels
+};
+
+
+
+
+
+
+
+
+// HP_TET_1F_1EA_0V  ... sing edge is 1..2
+int reftet_1f_1ea_0v_splitedges[][3] =
+{
+  { 1, 3, 5 },
+  { 1, 4, 6 },
+  { 2, 1, 7 },
+  { 2, 3, 8 },
+  { 2, 4, 9 },
+  { 3, 1, 10 },
+  { 4, 1, 11 },
+  { 0, 0, 0 }
+};
+
+int reftet_1f_1ea_0v_splitfaces[][4] =
+  {
+    { 2, 1, 3, 12 },
+    { 2, 1, 4, 13 },
+    { 0, 0, 0, 0 }
+  };
+
+
+HPREF_ELEMENT_TYPE reftet_1f_1ea_0v_newelstypes[] =
+{
+  HP_HEX_1F_0E_0V,
+  //  HP_PRISM,
+  HP_PYRAMID_1FB_0E_1VA,
+  HP_TET_1E_1VA,
+  HP_PRISM_SINGEDGE,
+  HP_PRISM,
+  HP_NONE,
+};
+int reftet_1f_1ea_0v_newels[][8] =
+{
+  { 3, 8, 9, 4, 10, 12, 13, 11 },
+  // { 2, 9, 8, 7, 13, 12 },
+  { 8, 9, 13, 12, 2 },
+  { 2, 7, 13, 12 },
+  { 7, 13, 12, 1, 6, 5 },
+  { 6, 11, 13, 5, 10, 12 }
+};
+HPRef_Struct reftet_1f_1ea_0v =
+{
+  HP_TET,
+  reftet_1f_1ea_0v_splitedges, 
+  reftet_1f_1ea_0v_splitfaces, 
+  0, 
+  reftet_1f_1ea_0v_newelstypes, 
+  reftet_1f_1ea_0v_newels
+};
+
+
+
+
+
+
+
+
+// HP_TET_1F_1EB_0V     singular edge in face, edge is 2-3
+int reftet_1f_1eb_0v_splitedges[][3] =
+{
+  { 2, 1, 5 },
+  { 2, 4, 6 },
+  { 3, 1, 7 },
+  { 3, 4, 8 },
+  { 4, 1, 9 },
+  { 0, 0, 0 }
+};
+
+
+HPREF_ELEMENT_TYPE reftet_1f_1eb_0v_newelstypes[] =
+{
+  HP_PRISM_1FB_1EA_0V,
+  HP_PRISM_1FA_0E_0V,
+  HP_TET,
+  HP_NONE,
+};
+int reftet_1f_1eb_0v_newels[][8] =
+{
+  // { 2, 5, 6, 3, 7, 8 },
+  { 3, 8, 7, 2, 6, 5 },
+  { 6, 4, 8, 5, 9, 7 },
+  { 5, 9, 7, 1}
+};
+HPRef_Struct reftet_1f_1eb_0v =
+{
+  HP_TET,
+  reftet_1f_1eb_0v_splitedges, 
+  0, 0, 
+  reftet_1f_1eb_0v_newelstypes, 
+  reftet_1f_1eb_0v_newels
+};
+
+
+
+
+
+
+
+
+
+
+/* ************************ 2 singular faces ******************** */
+
+
+// HP_TET_2F_0E_0V
+int reftet_2f_0e_0v_splitedges[][3] =
+{
+  { 1, 2, 5 },
+  { 2, 1, 6 },
+  { 3, 1, 7 },
+  { 3, 2, 8 },
+  { 4, 1, 9 },
+  { 4, 2, 10 },
+  { 0, 0, 0 }
+};
+
+int reftet_2f_0e_0v_splitfaces[][4] =
+  {
+    { 3, 1, 2, 11 },
+    { 4, 1, 2, 12 },
+    { 0, 0, 0, 0 }
+  };
+
+
+HPREF_ELEMENT_TYPE reftet_2f_0e_0v_newelstypes[] =
+{
+  HP_PRISM_1FA_0E_0V,
+  HP_PRISM_1FA_0E_0V,
+  HP_PRISM_1FB_1EA_0V,
+  HP_PRISM_1FB_1EA_0V,
+  HP_TET,
+  HP_NONE,
+};
+int reftet_2f_0e_0v_newels[][8] =
+{
+  { 2, 10, 8, 6, 12, 11 },
+  { 1, 7, 9, 5, 11, 12 },
+  //   { 3, 11, 8, 4, 12, 10 },
+  { 4, 10, 12, 3, 8, 11 }, 
+  { 3, 7, 11, 4, 9, 12 },
+  { 5, 6, 11, 12 }
+};
+HPRef_Struct reftet_2f_0e_0v =
+{
+  HP_TET,
+  reftet_2f_0e_0v_splitedges, 
+  reftet_2f_0e_0v_splitfaces, 
+  0, 
+  reftet_2f_0e_0v_newelstypes, 
+  reftet_2f_0e_0v_newels
+};
+
diff --git a/contrib/Netgen/libsrc/meshing/hpref_trig.hpp b/contrib/Netgen/libsrc/meshing/hpref_trig.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..3676ad0f33f5fdd5c1f0d9d428ec02f723155aba
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/hpref_trig.hpp
@@ -0,0 +1,776 @@
+
+
+// HP_TRIG
+int reftrig_splitedges[][3] =
+{
+  { 0, 0, 0 }
+};
+HPREF_ELEMENT_TYPE reftrig_newelstypes[] =
+{
+  HP_TRIG,
+  HP_NONE,
+};
+int reftrig_newels[][8] =
+{
+  { 1, 2, 3 },
+};
+HPRef_Struct reftrig =
+{
+  HP_TRIG, 
+  reftrig_splitedges, 
+  0, 0, 
+  reftrig_newelstypes, 
+  reftrig_newels
+};
+
+
+
+// HP_TRIG_SINGCORNER
+int reftrig_singcorner_splitedges[][3] =
+{
+  { 1, 2, 4 },
+  { 1, 3, 5 },
+  { 0, 0, 0 }
+};
+HPREF_ELEMENT_TYPE reftrig_singcorner_newelstypes[] =
+{
+  HP_TRIG_SINGCORNER,
+  HP_QUAD,
+  HP_NONE,
+};
+int reftrig_singcorner_newels[][8] =
+{
+  { 1, 4, 5 },
+  { 2, 3, 5, 4 },
+};
+HPRef_Struct reftrig_singcorner =
+{
+  HP_TRIG,
+  reftrig_singcorner_splitedges, 
+  0, 0,
+  reftrig_singcorner_newelstypes, 
+  reftrig_singcorner_newels
+};
+
+
+/*
+// HP_TRIG_SINGCORNER, trigs only
+int reftrig_singcorner_splitedges[][3] =
+{
+  { 1, 2, 4 },
+  { 1, 3, 5 },
+  { 0, 0, 0 }
+};
+HPREF_ELEMENT_TYPE reftrig_singcorner_newelstypes[] =
+{
+  HP_TRIG_SINGCORNER,
+  HP_TRIG,
+  HP_TRIG,
+  HP_NONE,
+};
+int reftrig_singcorner_newels[][8] =
+{
+  { 1, 4, 5 },
+  { 4, 2, 5 },
+  { 5, 2, 3 },
+};
+HPRef_Struct reftrig_singcorner =
+{
+  HP_TRIG,
+  reftrig_singcorner_splitedges, 
+  0, 0,
+  reftrig_singcorner_newelstypes, 
+  reftrig_singcorner_newels
+};
+*/
+
+
+
+
+
+// HP_TRIG_SINGCORNER12
+int reftrig_singcorner12_splitedges[][3] =
+{
+  { 1, 2, 4 },
+  { 1, 3, 5 },
+  { 2, 1, 6 },
+  { 2, 3, 7 },
+  { 0, 0, 0 }
+};
+HPREF_ELEMENT_TYPE reftrig_singcorner12_newelstypes[] =
+{
+  HP_TRIG_SINGCORNER,
+  HP_TRIG_SINGCORNER,
+  HP_QUAD,
+  HP_TRIG,
+  HP_NONE,
+};
+int reftrig_singcorner12_newels[][8] =
+{
+  { 1, 4, 5 },
+  { 2, 7, 6 },
+  { 4, 6, 7, 5 },
+  { 5, 7, 3 },
+};
+HPRef_Struct reftrig_singcorner12 =
+{
+  HP_TRIG,
+  reftrig_singcorner12_splitedges, 
+  0, 0,
+  reftrig_singcorner12_newelstypes, 
+  reftrig_singcorner12_newels
+};
+
+
+
+
+// HP_TRIG_SINGCORNER123_2D
+int reftrig_singcorner123_2D_splitedges[][3] =
+{
+  { 1, 2, 4 },
+  { 1, 3, 5 },
+  { 2, 1, 6 },
+  { 2, 3, 7 },
+  { 3, 1, 8 },
+  { 3, 2, 9 },
+  { 0, 0, 0 }
+};
+HPREF_ELEMENT_TYPE reftrig_singcorner123_2D_newelstypes[] =
+{
+  HP_TRIG_SINGCORNER,
+  HP_TRIG_SINGCORNER,
+  HP_TRIG_SINGCORNER,
+  HP_QUAD,
+  HP_QUAD,
+  HP_NONE,
+};
+int reftrig_singcorner123_2D_newels[][8] =
+{
+  { 1, 4, 5 },
+  { 2, 7, 6 },
+  { 3, 8, 9 },
+  { 4, 6, 8, 5 },
+  { 6, 7, 9, 8 },
+};
+HPRef_Struct reftrig_singcorner123_2D =
+{
+  HP_TRIG,
+  reftrig_singcorner123_2D_splitedges, 
+  0, 0,
+  reftrig_singcorner123_2D_newelstypes, 
+  reftrig_singcorner123_2D_newels
+};
+
+
+
+
+
+
+// HP_TRIG_SINGCORNER123
+int reftrig_singcorner123_splitedges[][3] =
+{
+  { 1, 2, 4 },
+  { 1, 3, 5 },
+  { 2, 1, 6 },
+  { 2, 3, 7 },
+  { 3, 1, 8 },
+  { 3, 2, 9 },
+  { 0, 0, 0 }
+};
+
+int reftrig_singcorner123_splitfaces[][4] =
+{
+  { 1, 2, 3, 10 },
+  { 2, 3, 1, 11 },
+  { 3, 1, 2, 12 },
+  { 0, 0, 0, 0 }
+};
+HPREF_ELEMENT_TYPE reftrig_singcorner123_newelstypes[] =
+{
+  HP_DUMMY_QUAD_SINGCORNER,
+  HP_DUMMY_QUAD_SINGCORNER,
+  HP_DUMMY_QUAD_SINGCORNER,
+  //  HP_TRIG_SINGCORNER,
+  //  HP_TRIG,
+  //  HP_TRIG_SINGCORNER,
+  //  HP_TRIG,
+  //  HP_TRIG_SINGCORNER,
+  //  HP_TRIG,
+  HP_QUAD,
+  HP_QUAD,
+  HP_QUAD,
+  HP_TRIG,
+  HP_NONE,
+};
+int reftrig_singcorner123_newels[][8] =
+{
+  { 1, 4, 10, 5 },
+  { 2, 7, 11, 6 },
+  { 3, 8, 12, 9 },
+  //  { 1, 4, 5 },
+  //  { 5, 4, 10 },
+  //  { 2, 7, 6 },
+  //  { 6, 7, 11 },
+  //  { 3, 8, 9 },
+  //  { 8, 12, 9 },
+  { 4, 6, 11, 10 },
+  { 7, 9, 12, 11 },
+  { 8, 5, 10, 12 },
+  { 10, 11, 12 },
+};
+HPRef_Struct reftrig_singcorner123 =
+{
+  HP_TRIG,
+  reftrig_singcorner123_splitedges, 
+  reftrig_singcorner123_splitfaces, 
+  0, 
+  reftrig_singcorner123_newelstypes, 
+  reftrig_singcorner123_newels
+};
+
+// HP_TRIG_SINGEDGE
+int reftrig_singedge_splitedges[][3] =
+{
+  { 2, 3, 4 },
+  { 1, 3, 5 },
+  { 0, 0, 0 }
+};
+HPREF_ELEMENT_TYPE reftrig_singedge_newelstypes[] =
+{
+  HP_TRIG,
+  HP_QUAD_SINGEDGE,
+  HP_NONE,
+};
+int reftrig_singedge_newels[][8] =
+{
+  { 4, 3, 5 },
+  { 1, 2, 4, 5 },
+};
+HPRef_Struct reftrig_singedge =
+{
+  HP_TRIG,
+  reftrig_singedge_splitedges, 
+  0, 0,
+  reftrig_singedge_newelstypes, 
+  reftrig_singedge_newels
+};
+
+
+
+
+
+
+// HP_TRIG_SINGEDGECORNER1
+int reftrig_singedgecorner1_splitedges[][3] =
+{
+  { 1, 2, 6 },
+  { 1, 3, 5 },
+  { 2, 3, 4 },
+  { 0, 0, 0 }
+};
+HPREF_ELEMENT_TYPE reftrig_singedgecorner1_newelstypes[] =
+{
+  HP_TRIG_SINGEDGECORNER1,
+  HP_QUAD_SINGEDGE,
+  HP_TRIG,
+  HP_NONE,
+};
+int reftrig_singedgecorner1_newels[][8] =
+{
+  { 1, 6, 5 },
+  { 6, 2, 4, 5 },
+  { 5, 4, 3 },
+};
+HPRef_Struct reftrig_singedgecorner1 =
+{
+  HP_TRIG,
+  reftrig_singedgecorner1_splitedges, 
+  0, 0, 
+  reftrig_singedgecorner1_newelstypes, 
+  reftrig_singedgecorner1_newels
+};
+
+
+
+
+
+
+
+
+// HP_TRIG_SINGEDGECORNER2
+int reftrig_singedgecorner2_splitedges[][3] =
+{
+  { 2, 1, 6 },
+  { 1, 3, 5 },
+  { 2, 3, 4 },
+  { 0, 0, 0 }
+};
+HPREF_ELEMENT_TYPE reftrig_singedgecorner2_newelstypes[] =
+{
+  HP_TRIG_SINGEDGECORNER2,
+  HP_QUAD_SINGEDGE,
+  HP_TRIG,
+  HP_NONE,
+};
+int reftrig_singedgecorner2_newels[][8] =
+{
+  { 6, 2, 4},
+  { 1, 6, 4, 5 },
+  { 5, 4, 3 },
+};
+HPRef_Struct reftrig_singedgecorner2 =
+{
+  HP_TRIG,
+  reftrig_singedgecorner2_splitedges, 
+  0, 0,
+  reftrig_singedgecorner2_newelstypes, 
+  reftrig_singedgecorner2_newels
+};
+
+
+
+
+// HP_TRIG_SINGEDGECORNER12
+int reftrig_singedgecorner12_splitedges[][3] =
+{
+  { 1, 2, 4 },
+  { 1, 3, 5 },
+  { 2, 1, 6 },
+  { 2, 3, 7 },
+  { 0, 0, 0 }
+};
+HPREF_ELEMENT_TYPE reftrig_singedgecorner12_newelstypes[] =
+{
+  HP_TRIG_SINGEDGECORNER1,
+  HP_TRIG_SINGEDGECORNER2,
+  HP_QUAD_SINGEDGE,
+  HP_TRIG,
+  HP_NONE,
+};
+int reftrig_singedgecorner12_newels[][8] =
+{
+  { 1, 4, 5 },
+  { 6, 2, 7 },
+  { 4, 6, 7, 5 },
+  { 5, 7, 3 },
+};
+HPRef_Struct reftrig_singedgecorner12 =
+{
+  HP_TRIG,
+  reftrig_singedgecorner12_splitedges, 
+  0, 0,
+  reftrig_singedgecorner12_newelstypes, 
+  reftrig_singedgecorner12_newels
+};
+
+
+
+
+
+
+
+// HP_TRIG_SINGEDGECORNER3
+int reftrig_singedgecorner3_splitedges[][3] =
+{
+  { 1, 3, 4 },
+  { 3, 1, 5 },
+  { 2, 3, 6 },
+  { 3, 2, 7 },
+  { 0, 0, 0 }
+};
+HPREF_ELEMENT_TYPE reftrig_singedgecorner3_newelstypes[] =
+{
+  HP_QUAD_SINGEDGE,
+  HP_QUAD,
+  HP_TRIG_SINGCORNER,
+  HP_NONE,
+};
+int reftrig_singedgecorner3_newels[][8] =
+{
+  { 1, 2, 6, 4 },
+  { 4, 6, 7, 5 },
+  { 3, 5, 7 },
+};
+HPRef_Struct reftrig_singedgecorner3 =
+{
+  HP_TRIG,
+  reftrig_singedgecorner3_splitedges, 
+  0, 0,
+  reftrig_singedgecorner3_newelstypes, 
+  reftrig_singedgecorner3_newels
+};
+
+
+
+
+// HP_TRIG_SINGEDGECORNER13
+int reftrig_singedgecorner13_splitedges[][3] =
+{
+  { 1, 2, 4 },
+  { 1, 3, 5 },
+  { 2, 3, 6 },
+  { 3, 1, 7 },
+  { 3, 2, 8 },
+  { 0, 0, 0 }
+};
+HPREF_ELEMENT_TYPE reftrig_singedgecorner13_newelstypes[] =
+{
+  HP_TRIG_SINGEDGECORNER1,
+  HP_QUAD_SINGEDGE,
+  HP_QUAD,
+  HP_TRIG_SINGCORNER,
+  HP_NONE,
+};
+int reftrig_singedgecorner13_newels[][8] =
+{
+  { 1, 4, 5 },
+  { 4, 2, 6, 5 },
+  { 5, 6, 8, 7 },
+  { 3, 7, 8 },
+};
+HPRef_Struct reftrig_singedgecorner13 =
+{
+  HP_TRIG,
+  reftrig_singedgecorner13_splitedges, 
+  0, 0,
+  reftrig_singedgecorner13_newelstypes, 
+  reftrig_singedgecorner13_newels
+};
+
+
+
+
+
+// HP_TRIG_SINGEDGECORNER23
+int reftrig_singedgecorner23_splitedges[][3] =
+{
+  { 1, 3, 4 },
+  { 2, 1, 5 },
+  { 2, 3, 6 },
+  { 3, 1, 7 },
+  { 3, 2, 8 },
+  { 0, 0, 0 }
+};
+HPREF_ELEMENT_TYPE reftrig_singedgecorner23_newelstypes[] =
+{
+  HP_TRIG_SINGEDGECORNER2,
+  HP_QUAD_SINGEDGE,
+  HP_QUAD,
+  HP_TRIG_SINGCORNER,
+  HP_NONE,
+};
+int reftrig_singedgecorner23_newels[][8] =
+{
+  { 5, 2, 6 },
+  { 1, 5, 6, 4 },
+  { 4, 6, 8, 7 },
+  { 3, 7, 8 },
+};
+HPRef_Struct reftrig_singedgecorner23 =
+{
+  HP_TRIG,
+  reftrig_singedgecorner23_splitedges, 
+  0, 0,
+  reftrig_singedgecorner23_newelstypes, 
+  reftrig_singedgecorner23_newels
+};
+
+
+
+// HP_TRIG_SINGEDGECORNER123
+int reftrig_singedgecorner123_splitedges[][3] =
+{
+  { 1, 2, 4 },
+  { 1, 3, 5 },
+  { 2, 1, 6 },
+  { 2, 3, 7 },
+  { 3, 1, 8 },
+  { 3, 2, 9 },
+  { 0, 0, 0 }
+};
+HPREF_ELEMENT_TYPE reftrig_singedgecorner123_newelstypes[] =
+{
+  HP_TRIG_SINGEDGECORNER1,
+  HP_TRIG_SINGEDGECORNER2,
+  HP_QUAD_SINGEDGE,
+  HP_QUAD,
+  HP_TRIG_SINGCORNER,
+  HP_NONE,
+};
+int reftrig_singedgecorner123_newels[][8] =
+{
+  { 1, 4, 5 },
+  { 6, 2, 7 },
+  { 4, 6, 7, 5 },
+  { 5, 7, 9, 8 },
+  { 3, 8, 9 },
+};
+HPRef_Struct reftrig_singedgecorner123 =
+{
+  HP_TRIG,
+  reftrig_singedgecorner123_splitedges, 
+  0, 0,
+  reftrig_singedgecorner123_newelstypes, 
+  reftrig_singedgecorner123_newels
+};
+
+// HP_TRIG_SINGEDGES
+int reftrig_singedges_splitedges[][3] =
+{
+  { 1, 2, 4 },
+  { 1, 3, 5 },
+  { 2, 3, 6 },
+  { 3, 2, 7 },
+  { 0, 0, 0 }
+};
+int reftrig_singedges_splitfaces[][4] =
+{
+  { 1, 2, 3, 8 },
+  { 0, 0, 0, 0 }
+};
+
+HPREF_ELEMENT_TYPE reftrig_singedges_newelstypes[] =
+{
+  //  HP_QUAD_2E,
+  HP_TRIG_SINGEDGECORNER1,
+  HP_TRIG_SINGEDGECORNER2,
+  HP_QUAD_SINGEDGE,
+  HP_QUAD_SINGEDGE,
+  HP_TRIG,
+  HP_NONE,
+};
+int reftrig_singedges_newels[][8] =
+{
+  // { 1, 4, 8, 5 },
+  { 1, 4, 8 },
+  { 5, 1, 8 },
+  { 4, 2, 6, 8 },
+  { 3, 5, 8, 7 },
+  { 6, 7, 8 },
+};
+HPRef_Struct reftrig_singedges =
+{
+  HP_TRIG,
+  reftrig_singedges_splitedges, 
+  reftrig_singedges_splitfaces, 
+  0,
+  reftrig_singedges_newelstypes, 
+  reftrig_singedges_newels
+};
+
+
+
+
+
+
+
+
+// HP_TRIG_SINGEDGES2
+int reftrig_singedges2_splitedges[][3] =
+{
+  { 1, 2, 4 },
+  { 1, 3, 5 },
+  { 2, 1, 6 },
+  { 2, 3, 7 },
+  { 3, 2, 8 },
+  { 0, 0, 0 }
+};
+int reftrig_singedges2_splitfaces[][4] =
+{
+  { 1, 2, 3, 9 },
+  { 0, 0, 0, 0 }
+};
+
+HPREF_ELEMENT_TYPE reftrig_singedges2_newelstypes[] =
+{
+  //  HP_QUAD_2E,
+  HP_TRIG_SINGEDGECORNER1,
+  HP_TRIG_SINGEDGECORNER2,
+  HP_QUAD_SINGEDGE,
+  HP_QUAD_SINGEDGE,
+  HP_TRIG_SINGEDGECORNER2,
+  HP_TRIG,
+  HP_NONE,
+};
+int reftrig_singedges2_newels[][8] =
+{
+  //  { 1, 4, 9, 5 },
+  { 1, 4, 9 },
+  { 5, 1, 9 },
+  { 4, 6, 7, 9 },
+  { 3, 5, 9, 8 },
+  { 6, 2, 7 },
+  { 7, 8, 9 },
+};
+HPRef_Struct reftrig_singedges2 =
+{
+  HP_TRIG,
+  reftrig_singedges2_splitedges, 
+  reftrig_singedges2_splitfaces, 
+  0,
+  reftrig_singedges2_newelstypes, 
+  reftrig_singedges2_newels
+};
+
+
+
+
+// HP_TRIG_SINGEDGES3
+int reftrig_singedges3_splitedges[][3] =
+{
+  { 1, 2, 4 },
+  { 1, 3, 5 },
+  { 2, 3, 6 },
+  { 3, 1, 7 },
+  { 3, 2, 8 },
+  { 0, 0, 0 }
+};
+int reftrig_singedges3_splitfaces[][4] =
+{
+  { 1, 2, 3, 9 },
+  { 0, 0, 0, 0 }
+};
+
+HPREF_ELEMENT_TYPE reftrig_singedges3_newelstypes[] =
+{
+  //  HP_QUAD_2E,
+  HP_TRIG_SINGEDGECORNER1,
+  HP_TRIG_SINGEDGECORNER2,
+  HP_QUAD_SINGEDGE,
+  HP_QUAD_SINGEDGE,
+  HP_TRIG_SINGEDGECORNER1,
+  HP_TRIG,
+  HP_NONE,
+};
+int reftrig_singedges3_newels[][8] =
+{
+  //  { 1, 4, 9, 5 },
+  { 1, 4, 9 },
+  { 5, 1, 9 },
+  { 4, 2, 6, 9 },
+  { 7, 5, 9, 8 },
+  { 3, 7, 8 },
+  { 6, 8, 9 },
+};
+HPRef_Struct reftrig_singedges3 =
+{
+  HP_TRIG,
+  reftrig_singedges3_splitedges, 
+  reftrig_singedges3_splitfaces, 
+  0,
+  reftrig_singedges3_newelstypes, 
+  reftrig_singedges3_newels
+};
+
+
+
+
+
+
+// HP_TRIG_SINGEDGES23
+int reftrig_singedges23_splitedges[][3] =
+{
+  { 1, 2, 4 },
+  { 1, 3, 5 },
+  { 2, 1, 6 },
+  { 2, 3, 7 },
+  { 3, 1, 8 },
+  { 3, 2, 9 },
+  { 0, 0, 0 }
+};
+int reftrig_singedges23_splitfaces[][4] =
+{
+  { 1, 2, 3, 10 },
+  { 0, 0, 0, 0 }
+};
+
+HPREF_ELEMENT_TYPE reftrig_singedges23_newelstypes[] =
+{
+  //  HP_QUAD_2E,
+  HP_TRIG_SINGEDGECORNER1,
+  HP_TRIG_SINGEDGECORNER2,
+
+  HP_QUAD_SINGEDGE,
+  HP_QUAD_SINGEDGE,
+  HP_TRIG_SINGEDGECORNER2,
+  HP_TRIG_SINGEDGECORNER1,
+  HP_TRIG,
+  HP_NONE,
+};
+int reftrig_singedges23_newels[][8] =
+{
+  //  { 1, 4, 10, 5 },
+  { 1 , 4, 10 },
+  { 5, 1, 10 },
+  { 4, 6, 7, 10 },
+  { 8, 5, 10, 9 },
+  { 6, 2, 7 },
+  { 3, 8, 9 },
+  { 7, 9, 10 },
+};
+HPRef_Struct reftrig_singedges23 =
+{
+  HP_TRIG,
+  reftrig_singedges23_splitedges, 
+  reftrig_singedges23_splitfaces, 
+  0,
+  reftrig_singedges23_newelstypes, 
+  reftrig_singedges23_newels
+};
+
+
+// HP_TRIG_3SINGEDGES
+int reftrig_3singedges_splitedges[][3] =
+{
+  { 1, 2, 4 },
+  { 2, 1, 5 }, 
+  { 2, 3, 6 }, 
+  { 3, 2, 7 }, 
+  { 3, 1, 8 }, 
+  { 1, 3, 9 }, 
+  { 0, 0, 0 }
+};
+int reftrig_3singedges_splitfaces[][4] =
+{
+  { 1, 2, 3, 10 },
+  { 2, 3, 1, 11 },
+  { 3, 1, 2, 12 }, 
+  { 0, 0, 0, 0 }
+};
+
+HPREF_ELEMENT_TYPE reftrig_3singedges_newelstypes[] =
+{
+  HP_TRIG, 
+  HP_QUAD_SINGEDGE, 
+  HP_QUAD_SINGEDGE, 
+  HP_QUAD_SINGEDGE, 
+  HP_TRIG_SINGEDGECORNER1, 
+  HP_TRIG_SINGEDGECORNER2, 
+  HP_TRIG_SINGEDGECORNER1, 
+  HP_TRIG_SINGEDGECORNER2, 
+  HP_TRIG_SINGEDGECORNER1, 
+  HP_TRIG_SINGEDGECORNER2, 
+  HP_NONE, 
+};
+int reftrig_3singedges_newels[][8] =
+{
+  { 10, 11, 12 }, 
+  { 4, 5, 11, 10 }, 
+  { 6, 7, 12, 11 },
+  { 8, 9, 10, 12 }, 
+  { 1, 4, 10 }, 
+  { 9, 1, 10 }, 
+  { 2, 6, 11 }, 
+  { 5, 2, 11 }, 
+  { 3, 8, 12 }, 
+  { 7, 3, 12 }, 
+};
+HPRef_Struct reftrig_3singedges =
+{
+  HP_TRIG,
+  reftrig_3singedges_splitedges, 
+  reftrig_3singedges_splitfaces, 
+  0,
+  reftrig_3singedges_newelstypes, 
+  reftrig_3singedges_newels
+};
diff --git a/contrib/Netgen/libsrc/meshing/hprefinement.cpp b/contrib/Netgen/libsrc/meshing/hprefinement.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..0ba4238baf29e61fc5fe0462d6bed0b37523cf9a
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/hprefinement.cpp
@@ -0,0 +1,1955 @@
+#include <mystdlib.h>
+#include "meshing.hpp"
+#include "hprefinement.hpp" 
+
+namespace netgen
+{
+
+#include "hpref_segm.hpp"
+#include "hpref_trig.hpp"  
+#include "hpref_quad.hpp"
+#include "hpref_tet.hpp"  
+#include "hpref_prism.hpp"
+#include "hpref_hex.hpp" 
+#include "hpref_pyramid.hpp" 
+#include "classifyhpel.hpp"  
+
+
+  void HPRefElement :: Reset(void)
+  {
+    np = 8; 
+    for (int i = 0; i < 8; i++)
+      {
+	pnums[i] = -1;
+	param[i][0] = param[i][1] = param[i][2] = 0;
+        domin=-1; domout=-1; // he:
+      }
+  } 
+
+  HPRefElement :: HPRefElement () 
+  {
+    Reset();
+  }
+
+  HPRefElement :: HPRefElement(Element & el)
+  { 
+    //Reset();
+    np = el.GetNV(); 
+    for (int i=0; i<np ; i++) 
+      pnums[i] = el[i]; 
+    
+    index = el.GetIndex(); 
+    const Point3d * points = 
+      MeshTopology :: GetVertices (el.GetType());
+    for(int i=0;i<np;i++)
+      for(int l=0;l<3;l++) 
+	param[i][l] = points[i].X(l+1); 
+    type = HP_NONE; 
+    domin=-1; domout=-1; // he: needed for segments
+  }
+
+  
+  HPRefElement :: HPRefElement(Element2d & el)
+  { 
+    //Reset();
+    np = el.GetNV(); 
+    
+    for (int i=0; i<np ; i++) 
+      pnums[i] = el[i]; 
+    
+    index = el.GetIndex(); 
+    const Point3d * points = 
+      MeshTopology :: GetVertices (el.GetType());
+    for(int i=0;i<np;i++)
+      for(int l=0;l<3;l++) 
+	param[i][l] = points[i].X(l+1); 
+    type = HP_NONE; 
+    domin=-1; domout=-1; // he: needed for segments
+  }
+
+  HPRefElement :: HPRefElement(Segment & el)
+  { 
+    //Reset();
+    np = 2; 
+    for (int i=0; i<np ; i++) 
+      pnums[i] = el[i];
+    const Point3d * points = 
+      MeshTopology :: GetVertices (SEGMENT); 
+    for(int i=0;i<np;i++)
+      for(int l=0;l<3;l++) 
+        param[i][l] = points[i].X(l+1); 
+
+    /*
+    for (int i=0; i<np; i++)
+    {
+      param[i][0] = i;   
+      param[i][1] = -1; param[i][2] = -1;
+    }
+    */
+
+    singedge_left = el.singedge_left; 
+    singedge_right = el.singedge_right; 
+    type = HP_NONE; 
+    // he: needed for orientation!
+    domin = el.domin;
+    domout = el.domout;
+  }
+  
+  HPRefElement :: HPRefElement(HPRefElement & el)
+  {
+    //Reset();
+    np = el.np; 
+    for (int i=0; i<np ; i++) 
+      {
+	pnums[i] = el[i];
+	for(int l=0; l<3; l++) param[i][l] = el.param[i][l]; 
+      }
+    index = el.index; 
+    levelx = el.levelx; 
+    levely = el.levely; 
+    levelz = el.levelz; 
+    type = el.type; 
+    coarse_elnr = el.coarse_elnr; 
+    singedge_left = el.singedge_left; 
+    singedge_right = el.singedge_right; 
+    domin = el.domin; // he: needed for segments
+    domout=el.domout;
+          
+  }
+
+  void HPRefElement :: SetType( HPREF_ELEMENT_TYPE t) 
+  {
+    type = t; 
+    switch(type)
+      {
+      case HP_SEGM: np=2; break; 
+      case HP_TRIG: np=3; break; 
+      case HP_QUAD: np=4; break; 
+      case HP_TET: np=4; break; 
+      case HP_PRISM: np=6; break; 
+      case HP_PYRAMID: np=5; break; 
+      case HP_HEX: np=8; break;      
+      } 
+    for(int k=0;k<8;k++)
+      {
+	pnums[k]=0;
+	for(int l=0;l<3;l++) param[k][l]=0.;
+      }
+  }
+  
+
+  HPRef_Struct * Get_HPRef_Struct (HPREF_ELEMENT_TYPE type)
+  {
+    HPRef_Struct * hps = NULL;
+
+    switch (type)
+      {
+      case HP_SEGM:
+	hps = &refsegm; break;
+      case HP_SEGM_SINGCORNERL:
+	hps = &refsegm_scl; break;
+      case HP_SEGM_SINGCORNERR:
+	hps = &refsegm_scr; break;
+      case HP_SEGM_SINGCORNERS:
+	hps = &refsegm_sc2; break;
+	
+      case HP_TRIG:
+	hps = &reftrig; break;
+      case HP_TRIG_SINGCORNER:
+	hps = &reftrig_singcorner; break;
+      case HP_TRIG_SINGCORNER12:
+	hps = &reftrig_singcorner12; break; 
+      case HP_TRIG_SINGCORNER123:
+	hps = &reftrig_singcorner123; break;
+      case HP_TRIG_SINGCORNER123_2D:
+	hps = &reftrig_singcorner123_2D; break;
+      case HP_TRIG_SINGEDGE:
+	hps = &reftrig_singedge; break;
+      case HP_TRIG_SINGEDGECORNER1:
+	hps = &reftrig_singedgecorner1; break;
+      case HP_TRIG_SINGEDGECORNER2:
+	hps = &reftrig_singedgecorner2; break;
+      case HP_TRIG_SINGEDGECORNER12:
+	hps = &reftrig_singedgecorner12; break;
+      case HP_TRIG_SINGEDGECORNER3:
+	hps = &reftrig_singedgecorner3; break;
+      case HP_TRIG_SINGEDGECORNER13:
+	hps = &reftrig_singedgecorner13; break;
+      case HP_TRIG_SINGEDGECORNER23:
+	hps = &reftrig_singedgecorner23; break;
+      case HP_TRIG_SINGEDGECORNER123:
+	hps = &reftrig_singedgecorner123; break;
+      case HP_TRIG_SINGEDGES:
+	hps = &reftrig_singedges; break; 
+      case HP_TRIG_SINGEDGES2: 
+	hps = &reftrig_singedges2; break;
+      case HP_TRIG_SINGEDGES3:
+	hps = &reftrig_singedges3; break;
+      case HP_TRIG_SINGEDGES23:  
+	hps = &reftrig_singedges23; break;
+      case HP_TRIG_3SINGEDGES:
+	hps = &reftrig_3singedges; break;
+ 
+ 
+      case HP_QUAD:
+	hps = &refquad; break;
+      case HP_DUMMY_QUAD_SINGCORNER:
+	hps = &refdummyquad_singcorner; break;
+      case HP_QUAD_SINGCORNER:
+	hps = &refquad_singcorner; break;
+      case HP_QUAD_SINGEDGE:
+	hps = &refquad_singedge; break;
+
+      case HP_QUAD_0E_2VA:
+	hps = &refquad_0e_2va; break;
+      case HP_QUAD_0E_2VB:
+	hps = &refquad_0e_2vb; break;
+
+      case HP_QUAD_0E_3V:
+	hps = &refquad_0e_3v; break;
+      case HP_QUAD_0E_4V:
+	hps = &refquad_0e_4v; break;
+
+      case HP_QUAD_1E_1VA:
+	hps = &refquad_1e_1va; break;
+      case HP_QUAD_1E_1VB:
+	hps = &refquad_1e_1vb; break;
+      case HP_QUAD_1E_1VC:
+	hps = &refquad_1e_1vc; break;
+      case HP_QUAD_1E_1VD:
+	hps = &refquad_1e_1vd; break;
+
+      case HP_QUAD_1E_2VA:
+	hps = &refquad_1e_2va; break;
+      case HP_QUAD_1E_2VB:
+	hps = &refquad_1e_2vb; break;
+      case HP_QUAD_1E_2VC:
+	hps = &refquad_1e_2vc; break;
+      case HP_QUAD_1E_2VD:
+	hps = &refquad_1e_2vd; break;
+      case HP_QUAD_1E_2VE:
+	hps = &refquad_1e_2ve; break;
+      case HP_QUAD_1E_2VF:
+	hps = &refquad_1e_2vf; break;
+
+      case HP_QUAD_1E_3VA:
+	hps = &refquad_1e_3va; break;
+      case HP_QUAD_1E_3VB:
+	hps = &refquad_1e_3vb; break;
+      case HP_QUAD_1E_3VC:
+	hps = &refquad_1e_3vc; break;
+      case HP_QUAD_1E_3VD:
+	hps = &refquad_1e_3vd; break;
+      case HP_QUAD_1E_4V:
+	hps = &refquad_1e_4v; break;
+
+
+      case HP_QUAD_2E:
+	hps = &refquad_2e; break;
+      case HP_QUAD_2E_1VA:
+	hps = &refquad_2e_1va; break;
+      case HP_QUAD_2E_1VB:
+	hps = &refquad_2e_1vb; break;
+      case HP_QUAD_2E_1VC:
+	hps = &refquad_2e_1vc; break;
+      case HP_QUAD_2E_2VA:
+	hps = &refquad_2e_2va; break;
+      case HP_QUAD_2E_2VB:
+	hps = &refquad_2e_2vb; break;
+      case HP_QUAD_2E_2VC:
+	hps = &refquad_2e_2vc; break;
+      case HP_QUAD_2E_3V:
+	hps = &refquad_2e_3v; break;
+
+      case HP_QUAD_2EB_0V:
+	hps = &refquad_2eb_0v; break;
+
+      case HP_QUAD_2EB_1VA:
+	hps = &refquad_2eb_1va; break;
+      case HP_QUAD_2EB_1VB:
+	hps = &refquad_2eb_1vb; break;
+
+
+      case HP_QUAD_2EB_2VA:
+	hps = &refquad_2eb_2va; break;
+      case HP_QUAD_2EB_2VB:
+	hps = &refquad_2eb_2vb; break;
+      case HP_QUAD_2EB_2VC:
+	hps = &refquad_2eb_2vc; break;
+      case HP_QUAD_2EB_2VD:
+	hps = &refquad_2eb_2vd; break;
+
+      case HP_QUAD_2EB_3VA:
+	hps = &refquad_2eb_3va; break;
+      case HP_QUAD_2EB_3VB:
+	hps = &refquad_2eb_3vb; break;
+
+      case HP_QUAD_2EB_4V:
+	hps = &refquad_2eb_4v; break;
+
+      case HP_QUAD_3E:
+	hps = &refquad_3e; break;
+      case HP_QUAD_3E_3VA:
+	hps = &refquad_3e_3va; break;
+      case HP_QUAD_3E_3VB:
+	hps = &refquad_3e_3vb; break;
+      case HP_QUAD_3E_4V:
+	hps = &refquad_3e_4v; break;
+
+
+      case HP_QUAD_4E:
+	hps = &refquad_4e; break;
+
+
+      case HP_TET:
+	hps = &reftet; break;
+      case HP_TET_0E_1V:
+	hps = &reftet_0e_1v; break;
+      case HP_TET_0E_2V:
+	hps = &reftet_0e_2v; break;
+      case HP_TET_0E_3V:
+	hps = &reftet_0e_3v; break;
+      case HP_TET_0E_4V:
+	hps = &reftet_0e_4v; break;
+
+      case HP_TET_1E_0V:      
+	hps = &reftet_1e_0v; break;
+      case HP_TET_1E_1VA:
+	hps = &reftet_1e_1va; break;
+      case HP_TET_1E_1VB:
+	hps = &reftet_1e_1vb; break;
+
+      case HP_TET_1E_2VA:
+	hps = &reftet_1e_2va; break;
+      case HP_TET_1E_2VB:
+	hps = &reftet_1e_2vb; break;
+      case HP_TET_1E_2VC:
+	hps = &reftet_1e_2vc; break;
+      case HP_TET_1E_2VD:
+	hps = &reftet_1e_2vd; break;
+
+      case HP_TET_1E_3VA:
+	hps = &reftet_1e_3va; break;
+      case HP_TET_1E_3VB:
+	hps = &reftet_1e_3vb; break;
+      case HP_TET_1E_4V:
+	hps = &reftet_1e_4v; break;
+
+      case HP_TET_2EA_0V:
+	hps = &reftet_2ea_0v; break;
+      case HP_TET_2EA_1VB:
+	hps = &reftet_2ea_1vb; break;
+      case HP_TET_2EA_1VC:
+	hps = &reftet_2ea_1vc; break;
+      case HP_TET_2EA_1VA:
+	hps = &reftet_2ea_1va; break;
+      case HP_TET_2EA_2VA:
+	hps = &reftet_2ea_2va; break;
+      case HP_TET_2EA_2VB:
+	hps = &reftet_2ea_2vb; break;
+      case HP_TET_2EA_2VC:
+	hps = &reftet_2ea_2vc; break;
+      case HP_TET_2EA_3V:
+	hps = &reftet_2ea_3v; break;
+
+      case HP_TET_2EB_0V:
+	hps = &reftet_2eb_0v; break;
+      case HP_TET_2EB_1V:
+	hps = &reftet_2eb_1v; break;
+      case HP_TET_2EB_2VA:
+	hps = &reftet_2eb_2va; break;
+      case HP_TET_2EB_2VB:
+	hps = &reftet_2eb_2vb; break;
+      case HP_TET_2EB_2VC:
+	hps = &reftet_2eb_2vc; break;
+      case HP_TET_2EB_3V:
+	hps = &reftet_2eb_3v; break;
+      case HP_TET_2EB_4V:
+	hps = &reftet_2eb_4v; break;
+
+
+      case HP_TET_3EA_0V:
+	hps = &reftet_3ea_0v; break;
+      case HP_TET_3EA_1V:
+	hps = &reftet_3ea_1v; break;
+      case HP_TET_3EA_2V:
+	hps = &reftet_3ea_2v; break;
+      case HP_TET_3EA_3V:
+	hps = &reftet_3ea_3v; break;
+
+      case HP_TET_3EB_0V:
+	hps = &reftet_3eb_0v; break;
+      case HP_TET_3EB_1V:
+	hps = &reftet_3eb_1v; break;
+      case HP_TET_3EB_2V:
+	hps = &reftet_3eb_2v; break;
+      case HP_TET_3EC_0V:
+	hps = &reftet_3ec_0v; break;
+      case HP_TET_3EC_1V:
+	hps = &reftet_3ec_1v; break;
+      case HP_TET_3EC_2V:
+	hps = &reftet_3ec_2v; break;
+
+
+      case HP_TET_1F_0E_0V:
+	hps = &reftet_1f_0e_0v; break;
+      case HP_TET_1F_0E_1VA:
+	hps = &reftet_1f_0e_1va; break;
+      case HP_TET_1F_0E_1VB:
+	hps = &reftet_1f_0e_1vb; break;
+      case HP_TET_1F_1EA_0V:
+	hps = &reftet_1f_1ea_0v; break;
+      case HP_TET_1F_1EB_0V:
+	hps = &reftet_1f_1eb_0v; break;
+      case HP_TET_2F_0E_0V:
+	hps = &reftet_2f_0e_0v; break;
+
+
+      case HP_PRISM:
+	hps = &refprism; break;
+      case HP_PRISM_SINGEDGE:
+	hps = &refprism_singedge; break;
+	//      case HP_PRISM_SINGEDGE_H1:
+	//	hps = &refprism_singedge_h1; break;
+	// case HP_PRISM_SINGEDGE_H12:
+	//	hps = &refprism_singedge_h12; break;
+      case HP_PRISM_SINGEDGE_V12:
+	hps = &refprism_singedge_v12; break;
+	
+
+      case HP_PRISM_1FA_0E_0V:
+	hps = &refprism_1fa_0e_0v; break;
+      case HP_PRISM_2FA_0E_0V:
+	hps = &refprism_2fa_0e_0v; break;
+      case HP_PRISM_1FB_0E_0V:
+	hps = &refprism_1fb_0e_0v; break;
+      case HP_PRISM_1FB_1EA_0V: 
+	hps = &refprism_1fb_1ea_0v; break;
+ 
+      case HP_PRISM_1FA_1E_0V:
+	hps = &refprism_1fa_1e_0v; break;
+      case HP_PRISM_2FA_1E_0V:
+	hps = &refprism_2fa_1e_0v; break; 
+      case HP_PRISM_1FA_1FB_0E_0V: 
+	hps = &refprism_1fa_1fb_0e_0v; break;
+      case HP_PRISM_2FA_1FB_0E_0V: 
+	hps = &refprism_2fa_1fb_0e_0v; break; 
+      case HP_PRISM_1FA_1FB_1EA_0V: 
+	hps = &refprism_1fa_1fb_1ea_0v; break; 
+      case HP_PRISM_1FA_1FB_1EB_0V: 
+	hps = &refprism_1fa_1fb_1eb_0v; break; 
+      case HP_PRISM_2FA_1FB_1EA_0V:  
+	hps = &refprism_2fa_1fb_1ea_0v; break; 
+      case HP_PRISM_1FB_1EC_0V: 
+	hps = &refprism_1fb_1ec_0v; break; 
+      case HP_PRISM_1FA_1FB_1EC_0V: 
+	hps = &refprism_1fa_1fb_1ec_0v; break; 
+      case HP_PRISM_2FA_1FB_1EC_0V: 
+	hps = &refprism_2fa_1fb_1ec_0v; break;  
+      case HP_PRISM_1FB_2EA_0V: 
+	hps = &refprism_1fb_2ea_0v; break; 
+      case HP_PRISM_1FA_1FB_2EA_0V:   
+	hps = &refprism_1fa_1fb_2ea_0v; break; 
+      case HP_PRISM_2FA_1FB_2EA_0V:  
+	hps = &refprism_2fa_1fb_2ea_0v; break;   
+      case HP_PRISM_1FB_2EB_0V: 
+	hps = &refprism_1fb_2eb_0v; break; 
+      case HP_PRISM_1FA_1FB_2EB_0V:   
+	hps = &refprism_1fa_1fb_2eb_0v; break;  
+      case HP_PRISM_1FA_1FB_2EC_0V: 
+	hps = &refprism_1fa_1fb_2ec_0v; break; 
+      case HP_PRISM_2FA_1FB_2EB_0V: 
+	hps = &refprism_2fa_1fb_2eb_0v; break;  
+      case HP_PRISM_1FB_3E_0V: 
+	hps = &refprism_1fb_3e_0v; break; 
+      case HP_PRISM_1FA_1FB_3E_0V:  
+	hps = &refprism_1fa_1fb_3e_0v; break;  
+      case HP_PRISM_2FA_1FB_3E_0V:  
+        hps = &refprism_2fa_1fb_3e_0v; break; 
+      case HP_PRISM_2FB_0E_0V: 
+	hps = &refprism_2fb_0e_0v; break;  
+      case HP_PRISM_1FA_2FB_0E_0V: 
+	hps = &refprism_1fa_2fb_0e_0v; break; 
+      case HP_PRISM_2FA_2FB_0E_0V:    
+        hps = &refprism_2fa_2fb_0e_0v; break;  
+      case HP_PRISM_2FB_1EC_0V:  
+	hps = &refprism_2fb_1ec_0v; break;  
+      case HP_PRISM_1FA_2FB_1EC_0V: 
+        hps = &refprism_1fa_2fb_1ec_0v; break; 
+      case HP_PRISM_2FA_2FB_1EC_0V: 
+	hps = &refprism_2fa_2fb_1ec_0v; break; 
+      case HP_PRISM_1FA_2FB_1EB_0V: 
+	hps = &refprism_1fa_2fb_1eb_0v; break; 
+      case HP_PRISM_2FB_3E_0V:    
+	hps = &refprism_2fb_3e_0v; break;
+      case HP_PRISM_1FA_2FB_3E_0V: 
+	hps = &refprism_1fa_2fb_3e_0v; break;
+      case HP_PRISM_2FA_2FB_3E_0V:  
+	hps = &refprism_2fa_2fb_3e_0v; break;
+      case HP_PRISM_1FA_2E_0V:   
+	hps = &refprism_1fa_2e_0v; break; 
+      case HP_PRISM_2FA_2E_0V:  
+	hps = &refprism_2fa_2e_0v; break;   
+      case HP_PRISM_3E_0V:  
+	hps = &refprism_3e_0v; break;
+      case HP_PRISM_1FA_3E_0V:   
+	hps = &refprism_1fa_3e_0v; break; 
+      case HP_PRISM_2FA_3E_0V:  
+	hps = &refprism_2fa_3e_0v; break;   
+      case HP_PRISM_3FB_0V:  
+	hps = &refprism_3fb_0v; break;
+      case HP_PRISM_1FA_3FB_0V:   
+	hps = &refprism_1fa_3fb_0v; break; 
+      case HP_PRISM_2FA_3FB_0V:  
+	hps = &refprism_2fa_3fb_0v; break;   
+	//  case HP_PRISM_3E_4EH:
+	//  hps = &refprism_3e_4eh; break;   
+	
+	
+	/*case HP_PRISM_1FB_1EB_0V:
+	hps = &refprism_1fb_1eb_0v; break;
+      case HP_PRISM_2F_0E_0V:
+	hps = &refprism_2f_0e_0v; break;
+	*/
+	
+	
+      case HP_PYRAMID:
+	hps = &refpyramid; break;
+      case HP_PYRAMID_0E_1V:
+	hps = &refpyramid_0e_1v; break;
+      case HP_PYRAMID_EDGES:
+	hps = &refpyramid_edges; break;
+      case HP_PYRAMID_1FB_0E_1VA:
+	hps = &refpyramid_1fb_0e_1va; break;
+
+	
+      case HP_HEX:
+	hps = &refhex; break;
+      case HP_HEX_0E_1V:
+	hps = &refhex_0e_1v; break;
+      case HP_HEX_1E_1V:
+	hps = &refhex_1e_1v; break;
+      case HP_HEX_1E_0V:
+	hps = &refhex_1e_0v; break;
+      case HP_HEX_3E_0V:
+	hps = &refhex_3e_0v; break;
+
+      case HP_HEX_1F_0E_0V:
+	hps = &refhex_1f_0e_0v; break;
+      case HP_HEX_1FA_1FB_0E_0V: 
+	hps = &refhex_1fa_1fb_0e_0v; break; 
+      }
+
+    /*
+    if (type != HP_TET_1E_4V && type != HP_TET_1E_2VD)
+      {
+	if (hps->geom == HP_TET)
+	  hps = &reftet;
+	if (hps->geom == HP_TRIG)
+	  hps = &reftrig;
+      }
+    */
+
+    if (!hps)
+      {
+	cout << "Attention hps : hp-refinement not implemented for case " << type << endl;
+	PrintSysError ("hp-refinement not implemented for case ", type);
+      }
+
+    return hps;
+  }
+
+  bool CheckSingularities(Mesh & mesh, INDEX_2_HASHTABLE<int> & edges, INDEX_2_HASHTABLE<int> & edgepoiclt_dom, 
+		       BitArray & cornerpoint, BitArray & edgepoint, INDEX_3_HASHTABLE<int> & faces, INDEX_2_HASHTABLE<int> & face_edges, 
+			INDEX_2_HASHTABLE<int> & surf_edges, ARRAY<int, PointIndex::BASE> & facepoint, int & levels, int & act_ref); 
+
+  bool ClassifyHPElements (Mesh & mesh, ARRAY<HPRefElement> & elements, int & act_ref, int & levels);
+  
+  
+  void  InitHPElements(Mesh & mesh, ARRAY<HPRefElement> & elements) 
+  { 
+    for(ElementIndex i=0;i<mesh.GetNE();i++) 
+      {
+	HPRefElement hpel(mesh[i]); 
+	hpel.coarse_elnr=i; 
+	
+	switch (mesh[i].GetType()) 
+	  { 
+	  case PRISM:
+	    hpel.type = HP_PRISM; 
+	    break; 
+	  case HEX:
+	    hpel.type = HP_HEX; 
+	    break; 
+	  case TET: 
+	    hpel.type = HP_TET; 
+	    break; 
+	  case PYRAMID: 
+	    hpel.type = HP_PYRAMID; 
+	    break; 
+	  } 
+	elements.Append(hpel); 
+      }
+	    
+    for(SurfaceElementIndex i=0;i<mesh.GetNSE();i++)
+      {
+	HPRefElement hpel(mesh.SurfaceElement(i));
+	hpel.coarse_elnr = i; 
+	switch(mesh.SurfaceElement(i).GetType())
+	  { 
+	  case TRIG: 
+	    hpel.type = HP_TRIG;
+	    break; 
+	  case QUAD: 
+	    hpel.type = HP_QUAD; 
+	    break; 
+	  } 
+	elements.Append(hpel);
+      } 
+        
+    for(int i=1;i<=mesh.GetNSeg();i++) 
+      { 
+	Segment & seg = mesh.LineSegment(i); 
+	HPRefElement hpel(seg); 
+	hpel.coarse_elnr = i-1; 
+	hpel.type = HP_SEGM; 
+	hpel.index = seg.edgenr + 10000*seg.si; 
+	if(seg.edgenr >= 10000)
+	  {
+	    throw NgException("assumption that seg.edgenr < 10000 is wrong");
+	  }
+	elements.Append(hpel); 
+
+      }
+  }
+
+ 
+ 
+  /* *******************************  DoRefinement *************************************** */
+  void DoRefinement (Mesh & mesh, ARRAY<HPRefElement> & elements,
+		     Refinement * ref, double fac1) 
+  {
+    elements.SetAllocSize (5 * elements.Size());
+    INDEX_2_HASHTABLE<int> newpts(elements.Size()+1);
+    INDEX_3_HASHTABLE<int> newfacepts(elements.Size()+1);
+
+    // prepare new points  
+    
+    fac1 = max(0.001,min(0.33,fac1));
+    cout << " in HP-REFINEMENT with fac1 " << fac1 << endl; 
+    *testout << " in HP-REFINEMENT with fac1 " << fac1 <<  endl; 
+   
+
+    int oldelsize = elements.Size();
+       
+    for (int i = 0; i < oldelsize; i++)
+      {
+	HPRefElement & el = elements[i]; 
+	HPRef_Struct * hprs = Get_HPRef_Struct (el.type);
+		
+	if (!hprs) 
+	  {
+	    cout << "Refinementstruct not defined for element " << el.type << endl;
+	    continue;
+	  }
+
+	int j = 0;
+	while (hprs->splitedges[j][0])
+	  {
+	    INDEX_2 i2(el.pnums[hprs->splitedges[j][0]-1],
+		       el.pnums[hprs->splitedges[j][1]-1]);
+	    if (!newpts.Used (i2))
+	      {
+		Point<3> np; 
+		for( int l=0;l<3;l++)
+		  np(l) = (1-fac1)*mesh.Point(i2.I1())(l) 
+		    + fac1 * mesh.Point(i2.I2())(l); 
+	
+		int npi = mesh.AddPoint (np);
+		newpts.Set (i2, npi);
+	      }
+	    j++;
+	  }
+	
+	j = 0;
+	if (hprs->splitfaces)
+	  while (hprs->splitfaces[j][0])
+	    {
+	      INDEX_3 i3(el.pnums[hprs->splitfaces[j][0]-1],
+			 el.pnums[hprs->splitfaces[j][1]-1],
+			 el.pnums[hprs->splitfaces[j][2]-1]);
+
+	      if (i3.I2() > i3.I3()) Swap (i3.I2(), i3.I3());
+	      
+	      if (!newfacepts.Used (i3))
+		{
+		  Point<3> np; 
+		  	for( int l=0;l<3;l++)
+			  np(l) = (1-2*fac1)*mesh.Point(i3.I1())(l) 
+			    + fac1*mesh.Point(i3.I2())(l)  + fac1*mesh.Point(i3.I3())(l);  
+		  int npi = mesh.AddPoint (np);
+		  newfacepts.Set (i3, npi);
+		}
+	      j++;
+	    }
+      }
+     
+    for (int i = 0; i < oldelsize; i++)
+      {
+	HPRefElement el = elements[i];
+	HPRef_Struct * hprs = Get_HPRef_Struct (el.type);
+	int newlevel = el.levelx + 1;
+
+	int oldnp(0);
+	switch (hprs->geom)
+	  {
+	  case HP_SEGM: oldnp = 2; break;
+	  case HP_TRIG: oldnp = 3; break;
+	  case HP_QUAD: oldnp = 4; break;
+	  case HP_TET: oldnp = 4; break;
+	  case HP_PYRAMID: oldnp = 5; break;
+	  case HP_PRISM: oldnp = 6; break;
+	  case HP_HEX: oldnp = 8; break;
+	  }
+
+
+	if (el.type == HP_SEGM ||
+	    el.type == HP_TRIG ||
+	    el.type == HP_QUAD ||
+	    el.type == HP_TET ||
+	    el.type == HP_PRISM ||
+	    el.type == HP_HEX || 
+	    el.type == HP_PYRAMID)
+	  newlevel = el.levelx;
+
+	if (!hprs) continue;
+
+	int newpnums[64];
+	double newparam[64][3];
+
+	int j;
+	for (j = 0; j < oldnp; j++)
+	  {
+	    newpnums[j] = el.pnums[j];
+	    for (int l = 0; l < 3; l++)
+	      newparam[j][l] = el.param[j][l];
+	  }
+
+	// split edges, incl. transferring curvature
+	j = 0;
+	while (hprs->splitedges[j][0])
+	  {
+	    INDEX_2 i2(el.pnums[hprs->splitedges[j][0]-1],
+		       el.pnums[hprs->splitedges[j][1]-1]);
+
+	    int npi = newpts.Get(i2);
+	    newpnums[hprs->splitedges[j][2]-1] = npi;
+
+	    for (int l = 0; l < 3; l++)
+	      newparam[hprs->splitedges[j][2]-1][l] =
+		(1-fac1) * el.param[hprs->splitedges[j][0]-1][l] + 
+		fac1 * el.param[hprs->splitedges[j][1]-1][l];
+	      
+	    j++;
+	  }
+
+	// split faces
+	j = 0;
+	if (hprs->splitfaces)
+	  while (hprs->splitfaces[j][0])
+	    {
+	      INDEX_3 i3(el.pnums[hprs->splitfaces[j][0]-1],
+			 el.pnums[hprs->splitfaces[j][1]-1],
+			 el.pnums[hprs->splitfaces[j][2]-1]);
+	      if (i3.I2() > i3.I3())
+		Swap (i3.I2(), i3.I3());
+	      int npi = newfacepts.Get(i3);
+	      newpnums[hprs->splitfaces[j][3]-1] = npi;
+	    
+
+	      for (int l = 0; l < 3; l++)
+		newparam[hprs->splitfaces[j][3]-1][l] =
+		  (1-2*fac1) * el.param[hprs->splitfaces[j][0]-1][l] + 
+		  fac1 * el.param[hprs->splitfaces[j][1]-1][l] + 
+		  fac1 * el.param[hprs->splitfaces[j][2]-1][l];
+	      j++;
+	    }
+	// split elements
+	j = 0;
+	if (hprs->splitelements)
+	  while (hprs->splitelements[j][0])
+	    {
+	      //int pi1 = el.pnums[hprs->splitelements[j][0]-1];
+	      Point<3> np; 
+	      	for( int l=0;l<3;l++)
+		  np(l) = (1-3*fac1)* mesh.Point(el.pnums[hprs->splitelements[j][0]-1])(l) 
+		    + fac1* mesh.Point(el.pnums[hprs->splitelements[j][1]-1])(l)
+		    + fac1* mesh.Point(el.pnums[hprs->splitelements[j][2]-1])(l)
+		    + fac1* mesh.Point(el.pnums[hprs->splitelements[j][3]-1])(l); 
+	      
+	      int npi = mesh.AddPoint (np);
+	      
+	      newpnums[hprs->splitelements[j][4]-1] = npi;
+	      
+	  	    
+	      for (int l = 0; l  < 3; l++)
+		newparam[hprs->splitelements[j][4]-1][l] =
+		  (1-3*fac1) * el.param[hprs->splitelements[j][0]-1][l] + 
+		  fac1 * el.param[hprs->splitelements[j][1]-1][l] + 
+		  fac1 * el.param[hprs->splitelements[j][2]-1][l] + 
+		  fac1 * el.param[hprs->splitelements[j][3]-1][l];
+
+	      j++;
+	    }
+ 
+	j = 0;
+
+	/*
+	*testout << " newpnums = ";
+	for (int hi = 0; hi < 64; hi++)
+	  *testout << newpnums[hi] << " ";
+	*testout << endl;
+	*/
+
+	while (hprs->neweltypes[j])
+	  {
+	    HPRef_Struct * hprsnew = Get_HPRef_Struct (hprs->neweltypes[j]);
+	    HPRefElement newel(el);
+
+	    newel.type = hprs->neweltypes[j]; 
+            
+	    // newel.index = elements[i].index;
+	    // newel.coarse_elnr = elements[i].coarse_elnr;
+	    newel.levelx = newel.levely = newel.levelz = newlevel;
+            switch(hprsnew->geom) 
+	      {
+	      case HP_SEGM: newel.np=2; break; 
+	      case HP_QUAD: newel.np=4; break; 
+	      case HP_TRIG: newel.np=3; break; 
+	      case HP_HEX: newel.np=8; break; 
+	      case HP_PRISM: newel.np=6; break;
+	      case HP_TET: newel.np=4; break; 
+	      case HP_PYRAMID: newel.np=5; break; 
+	      }
+
+	    for (int k = 0; k < newel.np; k++)
+	      newel.pnums[k] = newpnums[hprs->newels[j][k]-1];
+	    
+	    /*
+	    *testout  << " newel pnums " ; 
+	    for (int k = 0; k < newel.np; k++)  
+	      *testout  << newel.pnums[k] << "\t"; 
+	    *testout << endl; 
+	    */
+
+	    for (int k = 0; k < newel.np; k++)  
+	      { 
+		for (int l = 0; l < 3; l++)
+		  { 
+		    newel.param[k][l] = newparam[hprs->newels[j][k]-1][l];
+		    //    *testout << newel.param[k][l] << " \t ";
+		  } 
+		// *testout << endl; 
+	      } 
+	    
+	    if (j == 0) 
+	      elements[i] = newel; // overwrite old element
+	    else        
+	      elements.Append (newel);
+	    j++;
+	  }
+      } 
+  }
+
+
+
+
+
+
+  /* ************************** DoRefineDummies ******************************** */
+
+  void DoRefineDummies (Mesh & mesh, ARRAY<HPRefElement> & elements,
+			Refinement * ref)
+  {
+    int oldelsize = elements.Size();
+
+    for (int i = 0; i < oldelsize; i++)
+      {
+	HPRefElement el = elements[i];
+
+	HPRef_Struct * hprs = Get_HPRef_Struct (el.type);
+	if (!hprs) continue;
+
+	if (el.type != HP_DUMMY_QUAD_SINGCORNER &&
+	    el.type != HP_PYRAMID_EDGES &&
+	    el.type != HP_PYRAMID_0E_1V &&
+	    el.type != HP_HEX_0E_1V &&
+	    el.type != HP_HEX_1E_1V &&
+	    el.type != HP_HEX_1E_0V &&
+	    el.type != HP_HEX_3E_0V
+	    ) continue;
+
+	int newlevel = el.levelx;
+
+	int newpnums[8];
+	int j;
+	for (j = 0; j < 8; j++)
+	  newpnums[j] = el.pnums[j];
+
+	double newparam[8][3];
+	for (j = 0; j < 8; j++)
+	  for (int k = 0; k < 3; k++)
+	    newparam[j][k] = el.param[j][k];
+
+	j = 0;
+	while (hprs->neweltypes[j])
+	  {
+	    HPRef_Struct * hprsnew = Get_HPRef_Struct (hprs->neweltypes[j]);
+	    HPRefElement newel(el);
+	    switch(hprsnew->geom)
+	      {
+	      case HP_SEGM: newel.np=2; break; 
+	      case HP_QUAD: newel.np=4; break; 
+	      case HP_TRIG: newel.np=3; break; 
+	      case HP_HEX: newel.np=8; break; 
+	      case HP_PRISM: newel.np=6; break;
+	      case HP_TET: newel.np=4; break; 
+	      case HP_PYRAMID: newel.np=5; break; 
+	      }
+	    newel.type = hprs->neweltypes[j];
+	    for (int k = 0; k < 8; k++)
+	      newel.pnums[k] = newpnums[hprs->newels[j][k]-1];
+	    newel.index = el.index;
+	    newel.coarse_elnr = el.coarse_elnr;
+	    newel.levelx = newel.levely = newel.levelz = newlevel;
+
+	    for (int k = 0; k < 8; k++)
+	      for (int l = 0; l < 3; l++)
+		newel.param[k][l] = newparam[hprs->newels[j][k]-1][l];
+		
+	    if (j == 0)
+	      elements[i] = newel;
+	    else
+	      elements.Append (newel);
+	    j++;
+	  }
+      }
+  }
+
+
+
+
+
+
+
+  void SubdivideDegeneratedHexes (Mesh & mesh, ARRAY<HPRefElement> & elements, double fac1)
+  {
+    int oldne = elements.Size();
+    for (int i = 0; i < oldne; i++)
+      if (Get_HPRef_Struct (elements[i].type)->geom == HP_HEX)
+	{
+	  bool common = 0;
+	  for (int j = 0; j < 8; j++)
+	    for (int k = 0; k < j; k++)
+	      if (elements[i].pnums[j] == elements[i].pnums[k])
+		common = 1;
+	  if (common)
+	    {
+
+               
+	      cout << " Degenerate Hex found " << endl; 
+              *testout << " Degenerate Hex found " << endl; 
+	      HPRefElement el = elements[i];
+	      HPRefElement newel = el;
+
+	      Point<3> center(0,0,0);
+	      double newparam[3] = { 0, 0, 0 };
+
+	      for (int j = 0; j < 8; j++)
+		{
+		  
+		  
+		  center += 0.125 * Vec<3>(mesh[el.pnums[j]]); 
+		  // 0.125 originates form 8 points not from fac1;
+                  
+		  for (int l = 0; l < 3; l++)
+		    newparam[l] += 0.125 * el.param[j][l];
+                  
+		}
+
+	      int npi = mesh.AddPoint (center);
+
+	      const ELEMENT_FACE * faces = MeshTopology::GetFaces (HEX);
+
+	      for (int j = 0; j < 6; j++)  
+		{
+		  ARRAY<int> pts;
+		  for (int k = 0; k < 4; k++)
+		    {
+		      bool same = 0;
+		      for (int l = 0; l < pts.Size(); l++)
+			if (el.pnums[pts[l]] == el.pnums[faces[j][k]-1])
+			  same = 1;
+		      if (!same)
+			pts.Append (faces[j][k]-1);
+
+		    }
+		  
+		  
+		  if (pts.Size() == 3) // TrigFace -> TET 
+		    {
+		      
+		      for (int k = 0; k < 3; k++)
+			{
+			  newel.pnums[k] = el.pnums[pts[2-k]];
+			  for (int l = 0; l < 3; l++)
+			    newel.param[k][l] = el.param[pts[2-k]][l];
+			}
+		      newel.pnums[3] = npi;
+		      for (int l = 0; l < 3; l++)
+			newel.param[3][l] = newparam[l];
+
+		      newel.type = HP_TET;
+		      newel.np = 4; 
+		    }
+		  else
+		    {
+		      for (int k = 0; k < 4; k++)
+			{
+			  newel.pnums[k] = el.pnums[pts[3-k]];
+			  for (int l = 0; l < 3; l++)
+			    newel.param[k][l] = el.param[pts[3-k]][l];
+			}
+
+		      newel.pnums[4] = npi;
+		      for (int l = 0; l < 3; l++)
+			newel.param[4][l] = newparam[l];
+
+		      newel.type = HP_PYRAMID;
+		      newel.np = 5;
+		    }
+		  
+		  if (j == 0)
+		    elements[i] = newel;
+		  else
+		    elements.Append (newel); 
+
+		  
+		}
+
+	      /*     const ELEMENT_EDGE * edges = MeshTopology::GetEdges (HEX);
+	       
+		for(int k=0;k<12;k++) 
+		  { 
+		    int e[2];  
+		    for(int l=0;l<2;l++) e[l] = edges[k][l]-1; 
+		    if(el.PNum(e[0]+1)!=el.PNum(e[1]+1)) 
+		      { 
+			newel.SetType(HP_SEGM);
+			for(int l=0;l<2;l++) 
+			  { 
+			    newel.pnums[0] = el.PNum(e[l]+1); 
+			    newel.pnums[1] = npi; 
+			    for(int j=0;j<3;j++) 
+			      {
+				//	newel.param[0][j] = el.param[e[l]][j]; 
+				//	newel.param[1][j] = newparam[j]; 
+			      } 
+			    
+			    elements.Append(newel);
+			  }
+			newel.SetType(HP_TRIG);
+			newel.pnums[0] = el.PNum(e[0]+1); 			
+			newel.pnums[1] = el.PNum(e[1]+1); 			
+			newel.pnums[2] = npi; 
+			
+			*testout << "DEGHEX TRIG :: newpnums " << newel.pnums[0] << "\t"  << newel.pnums[1] << "\t"  << newel.pnums[2] << endl;  
+	cout << "DEGHEX TRIG :: newpnums " << newel.pnums[0] << "\t"  << newel.pnums[1] << "\t"  << newel.pnums[2] << endl;  
+			for(int j=0;j<3;j++) 
+			  {
+			    // newel.param[0][j] = el.param[e[0]][j]; 
+			    //   newel.param[1][j] = el.param[e[1]][j]; 
+			    //   newel.param[2][j] = newparam[j]; 
+			  } 
+			
+			elements.Append(newel);
+		      }
+			
+		      }*/
+	    }
+	}
+  }
+
+
+  void CalcStatistics (ARRAY<HPRefElement> & elements)
+  {
+    return;
+#ifdef ABC    
+    int i, p;
+    int nsegm = 0, ntrig = 0, nquad = 0;
+    int nhex = 0, nprism = 0, npyramid = 0, ntet = 0;
+    int maxlevel = 0;
+
+    for (i = 1; i <= elements.Size(); i++)
+      {
+	const HPRefElement & el = elements.Get(i);
+	maxlevel = max2 (el.level, maxlevel);
+	switch (Get_HPRef_Struct (el.type)->geom)
+	  {
+	  case HP_SEGM:
+
+	    {
+	      nsegm++;
+	      break;
+	    }
+	  case HP_TRIG:
+	    {
+	      ntrig ++;
+	      break;
+	    }
+	  case HP_QUAD:
+	    {
+	      nquad++;
+	      break;
+	    }
+	  case HP_TET:
+	    {
+	      ntet++;
+	      break;
+	    }
+
+	  case HP_PRISM:
+	    {
+	      nprism++;
+	      break;
+	    }
+
+	  case HP_PYRAMID:
+	    {
+	      npyramid++;
+	      break;
+	    }
+
+	  case HP_HEX:
+	    {	
+	      nhex++;
+	      break;
+	    }
+
+	  default:
+	    {
+	      cerr << "statistics error, unknown element type" << endl;
+	    }
+	  }
+      }
+
+    cout << "level = " << maxlevel << endl;
+    cout << "nsegm = " << nsegm << endl;
+    cout << "ntrig = " << ntrig << ", nquad = " << nquad << endl;
+    cout << "ntet = " << ntet << ", npyr = " << npyramid
+	 << ", nprism = " << nprism << ", nhex = " << nhex << endl;
+
+    return;
+
+    double memcost = 0, cpucost = 0;
+    for (p = 1; p <= 20; p++)
+      {
+	memcost = (ntet + nprism + nhex) * pow (static_cast<double>(p), 6.0);
+	cpucost = (ntet + nprism + nhex) * pow (static_cast<double>(p), 9.0);
+	cout << "costs for p = " << p << ": mem = " << memcost << ", cpu = " << cpucost << endl;
+      }
+
+    double memcosttet = 0;
+    double memcostprism = 0;
+    double memcosthex = 0;
+    double memcostsctet = 0; 
+    double memcostscprism = 0;
+    double memcostschex = 0;
+    double cpucosttet = 0;
+    double cpucostprism = 0;
+    double cpucosthex = 0;
+
+    for (i = 1; i <= elements.Size(); i++)
+      {
+	const HPRefElement & el = elements.Get(i);
+	switch (el.type)
+	  {
+	  case HP_TET:
+	  case HP_TET_0E_1V:
+	  case HP_TET_1E_0V:
+	  case HP_TET_1E_1VA:
+	    {
+	      int p1 = maxlevel - el.level + 1;
+	      (*testout) << "p1 = " << p1 << ", P1^6 = " << pow (static_cast<double>(p1), 6.0)
+			 << " (p1-3)^6 = " << pow ( static_cast<double>(max2(p1-3, 0)), 6.0) 
+			 << " p1^3 = " << pow ( static_cast<double>(p1), 3.0) 
+			 << " (p1-3)^3 = " << pow ( static_cast<double>(p1-3), 3.0) 
+			 << " [p1^3-(p1-3)^3]^2 = " << sqr (pow (static_cast<double>(p1),3.0) - pow ( static_cast<double>(p1-3), 3.0))
+			 << endl;
+
+	      p1 /= 2 +1;
+	      memcosttet += pow (static_cast<double>(p1), 6.0);
+	      memcostsctet += pow (static_cast<double>(p1), 6.0) - pow ( static_cast<double>(max2(p1-3, 1)), 6.0);
+	      cpucosttet += pow (static_cast<double>(p1), 9.0);
+	      break;
+	    }
+	  case HP_PRISM:
+	  case HP_PRISM_SINGEDGE:
+	    {
+	      int p1 = maxlevel - el.level + 1;
+	      p1 /= 2 +1;
+	      memcostprism += pow (static_cast<double>(p1), 6.0);
+	      memcostscprism += pow (static_cast<double>(p1), 6.0) - pow ( static_cast<double>(max2(p1-3, 1)), 6.0);
+	      cpucostprism += pow (static_cast<double>(p1), 9.0);
+	      break;
+	    }
+	  case HP_HEX:
+	    {	
+	      int p1 = maxlevel - el.level + 1;
+	      int p2 = maxlevel;
+	      p1 /= 2 +1;
+	      p2 /= 2 +1;
+	      memcosthex += pow (static_cast<double>(p1), 4.0) * pow (static_cast<double>(p2), 2.0);
+	      memcostschex += pow (static_cast<double>(p1), 6.0) - pow ( static_cast<double>(max2(p1-2, 0)), 6.0);
+	      cpucosthex += pow (static_cast<double>(p1), 6.0) * pow (static_cast<double>(p2), 3.0);
+	      break;
+	    }
+	  default:
+	    ;
+	  }
+      }
+    cout << "TET: hp-memcost = " << memcosttet 
+	 << ", scmemcost = " << memcostsctet
+	 << ", cpucost = " << cpucosttet
+	 << endl;
+    cout << "PRI: hp-memcost = " << memcostprism
+	 << ", scmemcost = " << memcostscprism
+	 << ", cpucost = " << cpucostprism << endl;
+    cout << "HEX: hp-memcost = " << memcosthex
+	 << ", scmemcost = " << memcostschex
+	 << ", cpucost = " << cpucosthex << endl;
+#endif
+  }
+
+
+
+  void ReorderPoints (Mesh & mesh, ARRAY<HPRefElement> & hpelements)
+  {
+    ARRAY<int, 1> map (mesh.GetNP());
+    
+    for (int i = 1; i <= mesh.GetNP(); i++)
+      map[i] = i;
+
+    int nwrong(0), nright(0);
+    for (int k = 0; k < 5; k++)
+      {
+        nwrong = nright = 0;
+        for (int i = 0; i < hpelements.Size(); i++)
+          {
+            const HPRefElement & hpel = hpelements[i];
+            
+            if (Get_HPRef_Struct (hpel.type) -> geom == HP_PRISM)
+              {
+                int minbot = 0, mintop = 0;
+                for (int j = 0; j < 3; j++)
+                  {
+                    if (map[hpel.pnums[j]] < map[hpel.pnums[minbot]]) minbot = j;
+                    if (map[hpel.pnums[j+3]] < map[hpel.pnums[mintop+3]]) mintop = j;
+                  }
+                if (minbot != mintop) 
+                  nwrong++;
+                else
+                  nright++;
+                
+                if (minbot != mintop)
+                  {
+                    if (map[hpel.pnums[minbot]] < map[hpel.pnums[mintop+3]])
+                      swap (map[hpel.pnums[3+minbot]], map[hpel.pnums[3+mintop]]);
+                    else
+                      swap (map[hpel.pnums[minbot]], map[hpel.pnums[mintop]]);
+                  }
+              }
+          }
+        // cout << nwrong << " wrong prisms, " << nright << " right prisms" << endl;
+      }
+
+    cout << nwrong << " wrong prisms, " << nright << " right prisms" << endl;
+
+
+    ARRAY<MeshPoint, 1> hpts(mesh.GetNP());
+
+    for (int i = 1; i <= mesh.GetNP(); i++)
+      hpts[map[i]] = mesh.Point(i);
+
+    for (int i = 1; i <= mesh.GetNP(); i++)
+      mesh.Point(i) = hpts[i];
+
+    for (int i = 0; i < hpelements.Size(); i++)
+      {
+        HPRefElement & hpel = hpelements[i];
+        for (int j = 0; j < hpel.np; j++)
+          hpel.pnums[j] = map[hpel.pnums[j]];
+      }
+  }
+
+
+
+  /* ***************************** HPRefinement ********************************** */
+
+  void HPRefinement (Mesh & mesh, Refinement * ref, int levels, double fac1, bool setorders, bool reflevels)
+  {
+    PrintMessage (1, "HP Refinement called, levels = ", levels);
+
+ 
+    NgLock mem_lock (mem_mutex,1);
+
+    mesh.coarsemesh = new Mesh; 
+    *mesh.coarsemesh = mesh;
+    
+#ifdef CURVEDELEMS_NEW
+    const_cast<CurvedElements&> (mesh.coarsemesh->GetCurvedElements() ).
+      BuildCurvedElements (ref, mesh.GetCurvedElements().GetOrder());
+#endif
+
+
+    delete mesh.hpelements;
+    mesh.hpelements = new ARRAY<HPRefElement>;
+        
+    ARRAY<HPRefElement> & hpelements = *mesh.hpelements; 
+        
+    InitHPElements(mesh,hpelements); 
+    
+    ARRAY<int> nplevel;
+    nplevel.Append (mesh.GetNP());
+    
+    int act_ref=1;
+    bool sing = ClassifyHPElements(mesh,hpelements, act_ref, levels); 
+
+    sing = true; // iterate at least once
+    while(sing) 
+      {
+	cout << " Start new hp-refinement: step " <<  act_ref  << endl; 
+		
+	DoRefinement (mesh, hpelements, ref, fac1); 
+	DoRefineDummies (mesh, hpelements, ref);
+	
+	nplevel.Append (mesh.GetNP());
+	CalcStatistics (hpelements);
+	
+	SubdivideDegeneratedHexes (mesh, hpelements,fac1);
+
+        ReorderPoints (mesh, hpelements);
+
+	mesh.ClearSegments();
+	mesh.ClearSurfaceElements();
+  	mesh.ClearVolumeElements();
+
+	for (int i = 0; i < hpelements.Size(); i++)
+	  {
+	    HPRefElement & hpel = hpelements[i];
+	    if (Get_HPRef_Struct (hpel.type))
+	      switch (Get_HPRef_Struct (hpel.type) -> geom)
+		{
+		case HP_SEGM:
+		  {
+		    Segment seg;
+		    seg.p1 = hpel.pnums[0];
+		    seg.p2 = hpel.pnums[1];
+		    // NOTE: only for less than 10000 elements (HACK) !!!
+		    seg.edgenr = hpel.index % 10000;
+		    seg.si     = hpel.index / 10000;
+
+                    /*
+                    seg.epgeominfo[0].dist = hpel.param[0][0]; // he: war hpel.param[0][0]
+                    seg.epgeominfo[1].dist = hpel.param[1][0]; // he: war hpel.param[1][0]
+                    */
+                    
+                    const Segment & coarseseg = mesh.coarsemesh->LineSegment(hpel.coarse_elnr+1);
+                    double d1 = coarseseg.epgeominfo[0].dist;
+                    double d2 = coarseseg.epgeominfo[1].dist;
+
+                    // seg.epgeominfo[0].dist = hpel.param[0][0]; // he: war hpel.param[0][0]
+                    // seg.epgeominfo[1].dist = hpel.param[1][0]; // he: war hpel.param[1][0]
+
+                    seg.epgeominfo[0].dist = d1 + hpel.param[0][0] * (d2-d1); // JS, June 08
+                    seg.epgeominfo[1].dist = d1 + hpel.param[1][0] * (d2-d1); 
+
+
+		    seg.epgeominfo[0].edgenr = seg.edgenr;
+		    seg.epgeominfo[1].edgenr = seg.edgenr;
+                    seg.domin = hpel.domin; seg.domout=hpel.domout; // he: needed for segments!
+		    seg.hp_elnr = i;
+		    seg.singedge_left = hpel.singedge_left; 
+		    seg.singedge_right = hpel.singedge_right; 
+		    mesh.AddSegment (seg); 
+		    break;
+		  }
+		  
+		case HP_TRIG: 
+		case HP_QUAD: 
+		  { 
+		    Element2d el(hpel.np); 
+		    for(int j=0;j<hpel.np;j++) 
+		      el.PNum(j+1) = hpel.pnums[j]; 
+		    el.hp_elnr = i; 
+		    el.SetIndex(hpel.index);
+		    if(setorders)
+		      el.SetOrder(act_ref+1,act_ref+1,0); 
+		    mesh.AddSurfaceElement(el);
+		    break; 
+		  } 
+		case HP_HEX:
+		case HP_TET:
+		case HP_PRISM:
+		case HP_PYRAMID:
+		  { 
+		    Element el(hpel.np); 
+		    for(int j=0;j<hpel.np;j++) 
+		      el.PNum(j+1) = hpel.pnums[j]; 
+		    el.SetIndex(hpel.index); 
+		    el.hp_elnr = i; 
+		    if(setorders)
+		      el.SetOrder(act_ref+1,act_ref+1,act_ref+1);
+		    mesh.AddVolumeElement(el); 
+		    break;
+		  } 
+		      
+		default:
+		  PrintSysError ("hpref, backconversion failed for element ", 
+				 int(Get_HPRef_Struct (hpel.type) -> geom));
+		}
+	  }
+	cout << " Start with Update Topology " << endl; 
+	mesh.UpdateTopology();
+	cout << " Mesh Update Topology done " << endl; 
+
+	act_ref++; 
+	
+	sing = ClassifyHPElements(mesh,hpelements, act_ref, levels); 
+      }
+
+    cout << " HP-Refinement done with " << --act_ref << " refinement steps." << endl; 
+
+    if(act_ref>=1)
+      { 
+	for(ElementIndex i=0;i<mesh.GetNE(); i++) 
+	  { 
+	    Element el = mesh[i] ;
+	    HPRefElement & hpel = hpelements[mesh[i].hp_elnr];
+	    const ELEMENT_EDGE * edges = MeshTopology::GetEdges (mesh[i].GetType());
+	    double dist[3] = {0,0,0}; 
+	    int ord_dir[3] = {0,0,0}; 
+	    int edge_dir[12] = {0,0,0,0,0,0,0,0,0,0,0,0}; 
+	    int ned = 4; 
+	    
+	    switch (mesh[i].GetType())
+	      {
+	      case TET: 
+		/* cout << " TET " ; 
+		for(int k=0;k<4;k++) cout << el[k] << "\t" ; 
+		cout << endl; */ 
+		break; 
+	      case PRISM:
+		/* cout << " PRISM " ; 
+		for(int k=0;k<6;k++) cout << el[k] << "\t" ; 
+		cout << endl;  */ 
+		for(int l=6;l<9;l++) edge_dir[l] = 2; 
+		ord_dir[2] = 2; 
+		ned = 9; 
+		break; 
+	      case HEX: 
+		/* cout << " HEX " ; 
+		for(int k=0;k<8;k++) cout << el[k] << "\t" ; 
+		cout << endl; */
+		for(int l=8;l<12; l++) edge_dir[l] = 2; 
+		edge_dir[2] = edge_dir[3] = edge_dir[6] = edge_dir[7] = 1;
+		ord_dir[1] = 1; 
+		ord_dir[2] = 2; 
+		ned = 12; 
+		break;  
+	      case PYRAMID: 
+		/*	cout << " PYRAMID " ; 
+		for(int k=0;k<5;k++) cout << el[k] << "\t" ; 
+		cout << endl; */ 
+		for(int l=4;l<8;l++) edge_dir[l] = 2; 
+		edge_dir[2] = edge_dir[3] = 1; 
+		ord_dir[1] = 1; 
+		ord_dir[2] = 2; 
+		ned = 8;  
+		break; 
+	      }
+	
+	    for (int j=0;j<ned;j++) 
+	      { 
+			
+		Vec<3> v(hpel.param[edges[j][0]-1][0]-hpel.param[edges[j][1]-1][0],
+			    hpel.param[edges[j][0]-1][1]-hpel.param[edges[j][1]-1][1],
+			    hpel.param[edges[j][0]-1][2]-hpel.param[edges[j][1]-1][2]);
+		dist[edge_dir[j]] = max(v.Length(),dist[edge_dir[j]]);
+	      }
+	    
+	    int refi[3];  
+	    for(int j=0;j<3;j++) 
+	      refi[j] = int(max(double(floor(log(dist[ord_dir[j]]/sqrt(2.))/log(fac1))),0.)); 	
+	    
+	    // cout << " ref " << refi[0] << "\t" << refi[1] << "\t" << refi[2] << endl; 
+	    // cout << " order " << act_ref +1 - refi[0] << "\t" << act_ref +1 - refi[1] << "\t" << act_ref +1 - refi[2] << endl; 
+	   	      
+	    if(setorders)
+	      mesh[i].SetOrder(act_ref+1-refi[0],act_ref+1-refi[1],act_ref+1-refi[2]); 
+	  }
+	for(SurfaceElementIndex i=0;i<mesh.GetNSE(); i++) 
+	  { 
+	    Element2d el = mesh[i] ;
+	    HPRefElement & hpel = hpelements[mesh[i].hp_elnr];
+	    const ELEMENT_EDGE * edges = MeshTopology::GetEdges (mesh[i].GetType());
+	    double dist[3] = {0,0,0}; 
+	    int ord_dir[3] = {0,0,0}; 
+	    int  edge_dir[4] = {0,0,0,0} ; 
+	    int ned = 3; 
+	   
+	    if(mesh[i].GetType() == QUAD)
+	      {
+		/*	cout << " QUAD " ; 
+		for(int k=0;k<4;k++) cout << el[k] << "\t" ; 
+		cout << endl; 	*/ 
+ 
+		edge_dir[2] = edge_dir[3] = 1; 
+		ord_dir[1] = 1; 
+		ned = 4; 
+	      }
+	    /*  else 
+	      { 
+		cout << " TRIG " ; 
+		for(int k=0;k<3;k++) cout << el[k] << "\t" ; 
+		cout << endl; 
+		} */ 
+	    
+	    for (int j=0;j<ned;j++) 
+	      { 
+		Vec<3> v(hpel.param[edges[j][0]-1][0]-hpel.param[edges[j][1]-1][0],
+			    hpel.param[edges[j][0]-1][1]-hpel.param[edges[j][1]-1][1],
+			    hpel.param[edges[j][0]-1][2]-hpel.param[edges[j][1]-1][2]);
+		dist[edge_dir[j]] = max(v.Length(),dist[edge_dir[j]]);
+	      }
+	    
+	    int refi[3]; 
+	    for(int j=0;j<3;j++) 
+	      refi[j] = int(max(double(floor(log(dist[ord_dir[j]]/sqrt(2.))/log(fac1))),0.)); 	
+	    
+	    if(setorders)
+	      mesh[i].SetOrder(act_ref+1-refi[0],act_ref+1-refi[1],act_ref+1-refi[2]); 
+
+	      // cout << " ref " << refi[0] << "\t" << refi[1] << endl; 
+	      // cout << " order " << act_ref +1 - refi[0] << "\t" << act_ref +1 - refi[1] << endl; 
+	  }
+      }
+  }
+
+bool CheckSingularities(Mesh & mesh, INDEX_2_HASHTABLE<int> & edges, INDEX_2_HASHTABLE<int> & edgepoint_dom, 
+		       BitArray & cornerpoint, BitArray & edgepoint, INDEX_3_HASHTABLE<int> & faces, INDEX_2_HASHTABLE<int> & face_edges, 
+			INDEX_2_HASHTABLE<int> & surf_edges, ARRAY<int, PointIndex::BASE> & facepoint, int & levels, int & act_ref)
+{ 
+  bool sing=0; 
+  if (mesh.GetDimension() == 3)
+      {
+	/*
+	// check, if point has as least 3 different surfs:
+
+	ARRAY<INDEX_3, PointIndex::BASE> surfonpoint(mesh.GetNP());
+  	surfonpoint = INDEX_3(0,0,0);
+
+	for (SurfaceElementIndex sei = 0; sei < mesh.GetNSE(); sei++)
+	  {
+	    const Element2d & el = mesh[sei];
+	    int ind = el.GetIndex();
+	    for (int j = 0; j < el.GetNP(); j++)
+	      {
+		INDEX_3 & i3 = surfonpoint[el[j]];
+		if (ind != i3.I1() && ind != i3.I2() && ind != i3.I3())
+		  {
+		    i3.I1() = i3.I2();
+		    i3.I2() = i3.I3();
+		    i3.I3() = ind;
+		  }
+	      }
+	  }
+	for (int i = 1; i <= mesh.GetNP(); i++)
+	  if (surfonpoint.Get(i).I1())
+	    cornerpoint.Set(i);
+	*/
+	cornerpoint.Clear();
+	
+	for (int i = 1; i <= mesh.GetNP(); i++)
+	  {
+	    if (mesh.Point(i).Singularity() * levels >= act_ref)
+	      {
+		cornerpoint.Set(i);
+		sing = 1; 
+	      } 
+	  }
+	cout << endl; 
+
+	for (int i = 1; i <= mesh.GetNSeg(); i++)
+	  if (mesh.LineSegment(i).singedge_left * levels >= act_ref)
+	    {
+	      INDEX_2 i2 (mesh.LineSegment(i).p1, 
+			  mesh.LineSegment(i).p2);
+
+	      /*
+		// before
+	      edges.Set (i2, 1);
+	      i2.Sort();   
+	      INDEX_2 i2s(i2.I2(), i2.I1());
+	      edges.Set (i2s, 1);
+	      */
+
+	      edges.Set (i2, 1);
+	      INDEX_2 i2s(i2.I2(), i2.I1());
+	      edges.Set (i2s, 1);
+
+
+	      edgepoint.Set (i2.I1());
+	      edgepoint.Set (i2.I2());
+	      sing = 1; 
+	    }
+
+	// if 2 adjacent edges of an element are singular, the 
+	// commen point must be a singular point
+	for (int i = 1; i <= mesh.GetNE(); i++)
+	  {
+	    const Element & el = mesh.VolumeElement(i);
+	    const ELEMENT_EDGE * eledges = MeshTopology::GetEdges (el.GetType());
+	    int nedges = MeshTopology::GetNEdges (el.GetType());
+	    for (int j = 0; j < nedges; j++)
+	      for (int k = 0; k < nedges; k++)
+		if (j != k)
+		  {
+		    INDEX_2 ej(el.PNum(eledges[j][0]), el.PNum(eledges[j][1]));
+		    ej.Sort();
+		    INDEX_2 ek(el.PNum(eledges[k][0]), el.PNum(eledges[k][1]));
+		    ek.Sort();
+		    if (edges.Used(ej) && edges.Used(ek))
+		      {
+			if (ej.I1() == ek.I1()) cornerpoint.Set (ek.I1());
+			if (ej.I1() == ek.I2()) cornerpoint.Set (ek.I2());
+			if (ej.I2() == ek.I1()) cornerpoint.Set (ek.I1());
+			if (ej.I2() == ek.I2()) cornerpoint.Set (ek.I2());
+		      }
+		  }
+	  }
+
+	edgepoint.Or (cornerpoint);
+	(*testout) << "cornerpoint = " << endl << cornerpoint << endl;
+	(*testout) << "edgepoint = " << endl << edgepoint << endl;
+
+	facepoint = 0;
+	for (SurfaceElementIndex sei = 0; sei < mesh.GetNSE(); sei++)
+	  {
+	    const Element2d & el = mesh[sei];
+	    const FaceDescriptor & fd = mesh.GetFaceDescriptor (el.GetIndex());
+	  
+	    int domnr = 0;
+	    if (fd.domin_singular * levels < act_ref && fd.domout_singular * levels < act_ref) 
+	      { domnr=0;  continue;}
+	    
+	    if (fd.domin_singular * levels >= act_ref) 
+	      {
+		domnr = fd.DomainIn();
+		sing = 1;
+	      }
+	    if (fd.domout_singular * levels >= act_ref)
+	      {
+		domnr = fd.DomainOut();
+		sing = 1; 
+	      } 
+	    if (fd.domin_singular * levels >= act_ref 
+		&& fd.domout_singular * levels >= act_ref) 
+	      {
+		domnr = -1;
+		sing = 1;
+	      } 
+  
+	    INDEX_3 i3;
+	    if (el.GetNP() == 3) 
+	      i3 = INDEX_3::Sort (el[0], el[1], el[2]);
+	    else
+	      {
+		INDEX_4 i4 (el[0], el[1], el[2], el[3]);
+		i4.Sort();
+		i3 = INDEX_3(i4.I1(), i4.I2(), i4.I3());
+	      }
+	    faces.Set (i3, domnr);
+	
+	    for (int j = 0; j < el.GetNP(); j++)
+	      {
+		face_edges.Set (INDEX_2::Sort (el[j], el[(j+1)%el.GetNP()]), domnr);
+	
+		surf_edges.Set (INDEX_2::Sort (el[j], el[(j+1)%el.GetNP()]), fd.SurfNr()+1);
+		
+		facepoint[el[j]] = domnr;
+	      }
+	   
+	  }
+	(*testout) << "singular faces = " << faces << endl;
+	(*testout) << "singular faces_edges = " << face_edges << endl;
+      }
+    else
+      {
+	// 2D case
+
+	// check, if point has as least 3 different surfs:
+	ARRAY<INDEX_3, PointIndex::BASE> surfonpoint(mesh.GetNP());
+
+	for (int i = 1; i <= mesh.GetNP(); i++)
+	  surfonpoint.Elem(i) = INDEX_3(0,0,0);
+      
+	for (int i = 1; i <= mesh.GetNSeg(); i++)
+	  {
+	    const Segment & seg = mesh.LineSegment(i);
+	    int ind = seg.edgenr;
+
+	   
+		if (seg.singedge_left * levels >= act_ref)
+		  {
+		    INDEX_2 i2 (mesh.LineSegment(i).p1, 
+				mesh.LineSegment(i).p2);
+		    edges.Set(i2,1); 
+		    edgepoint.Set(i2.I1());
+		    edgepoint.Set(i2.I2());
+		    *testout << " singleft " << endl;  
+		    *testout << " mesh.LineSegment(i).domout " << mesh.LineSegment(i).domout << endl;      
+		    *testout << " mesh.LineSegment(i).domin " << mesh.LineSegment(i).domin << endl;      
+		    edgepoint_dom.Set (INDEX_2(mesh.LineSegment(i).domin, i2.I1()), 1);
+		    edgepoint_dom.Set (INDEX_2(mesh.LineSegment(i).domin, i2.I2()), 1);
+		    sing = 1; 
+		    
+		  }
+		
+		  if (seg.singedge_right * levels >= act_ref)
+		    {
+		      INDEX_2 i2 (mesh.LineSegment(i).p2, 
+				  mesh.LineSegment(i).p1);  
+		      edges.Set (i2, 1);
+		      edgepoint.Set(i2.I1());
+		      edgepoint.Set(i2.I2());
+
+		      *testout << " singright " << endl;  
+		      *testout << " mesh.LineSegment(i).domout " << mesh.LineSegment(i).domout << endl;      
+		      *testout << " mesh.LineSegment(i).domin " << mesh.LineSegment(i).domin << endl;      
+		      
+		      edgepoint_dom.Set (INDEX_2(mesh.LineSegment(i).domout, i2.I1()), 1);
+		      edgepoint_dom.Set (INDEX_2(mesh.LineSegment(i).domout, i2.I2()), 1);
+		      sing = 1;
+		    }
+	
+	    // (*testout) << "seg = " << ind << ", " << seg.p1 << "-" << seg.p2 << endl;
+
+
+	    if (seg.singedge_left * levels >= act_ref
+		|| seg.singedge_right* levels >= act_ref)
+	      {
+		for (int j = 0; j < 2; j++)
+		  {
+		    int pi = (j == 0) ? seg.p1 : seg.p2;
+		    INDEX_3 & i3 = surfonpoint.Elem(pi);
+		    if (ind != i3.I1() &&
+			ind != i3.I2())
+		      {
+			i3.I1() = i3.I2();
+			i3.I2() = ind;
+		      }
+		  }
+	      }
+	  }
+
+
+	for (int i = 1; i <= mesh.GetNP(); i++)
+	  {
+	    // mark points for refinement that are in corners between two anisotropic edges 
+	    if (surfonpoint.Get(i).I1())
+	      {
+		cornerpoint.Set(i);
+		edgepoint.Set(i);
+	      }
+	
+	    // mark points for refinement that are explicity specified in input file
+	    if (mesh.Point(i).Singularity()*levels >= act_ref)
+	      {
+		cornerpoint.Set(i);
+		edgepoint.Set(i);
+		sing =  1; 
+	      }
+	  }
+
+	edgepoint.Or (cornerpoint);
+
+	(*testout) << "2d sing edges: " << endl << edges << endl;
+	(*testout) << "2d cornerpoints: " << endl << cornerpoint << endl
+		   << "2d edgepoints: " << endl << edgepoint << endl;
+	
+	facepoint = 0;
+      }
+
+    if (!sing)
+      {
+	cout << "PrepareElements no more to do for actual refinement " << act_ref << endl; 
+	return(sing);
+      } 
+    return(sing); 
+}
+
+
+
+  bool ClassifyHPElements (Mesh & mesh, ARRAY<HPRefElement> & elements, int & act_ref, int & levels)
+  {
+    
+    INDEX_2_HASHTABLE<int> edges(mesh.GetNSeg()+1);
+    BitArray edgepoint(mesh.GetNP());
+    INDEX_2_HASHTABLE<int> edgepoint_dom(mesh.GetNSeg()+1);
+
+    edgepoint.Clear();
+    BitArray cornerpoint(mesh.GetNP());
+    cornerpoint.Clear();
+
+    // value = nr > 0 ... refine elements in domain nr
+    // value = -1   ..... refine elements in any domain
+    INDEX_3_HASHTABLE<int> faces(mesh.GetNSE()+1);
+    INDEX_2_HASHTABLE<int> face_edges(mesh.GetNSE()+1);
+    INDEX_2_HASHTABLE<int> surf_edges(mesh.GetNSE()+1);
+    ARRAY<int, PointIndex::BASE> facepoint(mesh.GetNP());
+
+    bool sing = CheckSingularities(mesh, edges, edgepoint_dom, 
+			      cornerpoint, edgepoint, faces, face_edges, 
+			      surf_edges, facepoint, levels, act_ref); 
+  
+    if(sing==0) return(sing); 
+
+    int cnt_undef = 0, cnt_nonimplement = 0;
+    ARRAY<int> misses(10000);
+    misses = 0;
+
+    (*testout) << "edgepoint_dom = " << endl << edgepoint_dom << endl;
+
+    for( int i = 0; i<elements.Size(); i++) 
+      {
+	// *testout << "classify element " << i << endl;
+
+	HPRefElement & hpel = elements[i]; 
+	HPRef_Struct * hprs = Get_HPRef_Struct (hpel.type);
+	HPRefElement old_el = elements[i]; 
+	int dd=3; 
+
+
+	if(act_ref !=1 && (hpel.type == HP_HEX || hpel.type == HP_PRISM || hpel.type == HP_TET 
+			   || hpel.type == HP_PYRAMID || hpel.type == HP_QUAD || hpel.type == HP_TRIG || hpel.type == HP_SEGM)) 
+	  continue; 
+	
+	sing = 1; 
+	switch (hprs->geom)
+	  {
+	  case HP_TET:
+	    {
+	      hpel.type = ClassifyTet(hpel, edges, edgepoint_dom, cornerpoint, edgepoint, faces,face_edges, surf_edges, facepoint); 
+	      break;
+	    }
+	  case HP_PRISM:
+	    {
+	      hpel.type = ClassifyPrism(hpel, edges, edgepoint_dom, cornerpoint, edgepoint, faces,
+					face_edges, surf_edges, facepoint); 	    	    
+	 
+	    
+	      break;
+	    }
+	  case HP_HEX:
+	    { 
+	      hpel.type = hpel.type = ClassifyHex(hpel, edges, edgepoint_dom, cornerpoint, edgepoint, faces,
+						  face_edges, surf_edges, facepoint); 	    	    
+	      break; 
+	    } 
+	  case HP_TRIG: 
+	    { 
+	      int dim = mesh.GetDimension(); 
+	      const FaceDescriptor & fd = mesh.GetFaceDescriptor (hpel.GetIndex());	
+	      
+	      hpel.type = ClassifyTrig(hpel, edges, edgepoint_dom, cornerpoint, edgepoint, 
+				       faces, face_edges, surf_edges, facepoint, dim, fd);    
+	     
+	      dd = 2; 
+	      break; 
+	    } 
+	  case HP_QUAD: 
+	    { 
+	      int dim = mesh.GetDimension(); 
+	      const FaceDescriptor & fd = mesh.GetFaceDescriptor (hpel.GetIndex());	
+	      hpel.type = ClassifyQuad(hpel, edges, edgepoint_dom, cornerpoint, edgepoint, 
+				  faces, face_edges, surf_edges, facepoint, dim, fd);    
+
+	      dd = 2; 
+	      break; 
+	    }
+	  case HP_SEGM: 
+	    {
+	      hpel.type = ClassifySegm(hpel, edges, edgepoint_dom, cornerpoint, edgepoint, 
+				       faces, face_edges, surf_edges, facepoint);    
+	      dd = 1; 
+	      break; 
+	    }
+	  case HP_PYRAMID: 
+	    {
+	      hpel.type = ClassifyPyramid(hpel, edges, edgepoint_dom, cornerpoint, edgepoint, faces,
+						  face_edges, surf_edges, facepoint); 	    	    
+	      
+	      cout << " ** Pyramid classified  " << hpel.type << endl; 
+	      break; 
+	    }
+	  default:
+	    {
+	      cout << "illegal element type for hp-prepare elements " << hpel.type << endl;
+	      throw NgException ("hprefinement.cpp: don't know how to set parameters");
+	    }
+	  }
+	    
+	if(hpel.type == HP_NONE) 
+	  cnt_undef++; 
+
+	//else 
+	//cout << "elem " << i << " classified type " << hpel.type << endl; 
+
+	
+	
+	if (!Get_HPRef_Struct (hpel.type)) 
+	  {
+	    (*testout) << "hp-element-type " << hpel.type << " not implemented   " << endl;
+	    (*testout) << " elType " << hprs->geom << endl; 
+ (cout) << " elType " << hprs->geom << endl;        
+	    cnt_nonimplement++;
+	    misses[hpel.type]++;
+	  }
+	
+  
+	for(int j=0; j<hpel.np; j++)
+	  {
+	    for( int k=0; k<hpel.np; k++) 
+	      if(hpel[j] == old_el.pnums[k]) 
+		{ 
+		  for(int l=0;l<dd;l++) 
+		    hpel.param[j][l] = old_el.param[k][l];
+		  break;
+		}
+	  } 
+
+      }
+    
+    
+    cout << "undefined elements update classification: " << cnt_undef << endl;
+    cout << "non-implemented in update classification: " << cnt_nonimplement << endl;
+
+    for (int i = 0; i < misses.Size(); i++)
+      if (misses[i])
+	cout << " in update classification missing case " << i << " occured " << misses[i] << " times" << endl;
+
+    return(sing); 
+  }
+}
+  
diff --git a/contrib/Netgen/libsrc/meshing/hprefinement.hpp b/contrib/Netgen/libsrc/meshing/hprefinement.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..05e4d7278085f4d9ac6dfddb21360823885b9a25
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/hprefinement.hpp
@@ -0,0 +1,319 @@
+#ifndef FILE_HPREFINEMENT
+#define FILE_HPREFINEMENT
+
+/**************************************************************************/
+/* File:   hprefinement.hh                                                */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   27. Oct. 2000                                                  */
+/**************************************************************************/
+
+/*
+  HP Refinement
+*/
+
+
+
+
+enum HPREF_ELEMENT_TYPE {
+  HP_NONE=0,
+
+  HP_SEGM = 1,
+  HP_SEGM_SINGCORNERL,
+  HP_SEGM_SINGCORNERR,
+  HP_SEGM_SINGCORNERS,
+
+  HP_TRIG = 10,
+  HP_TRIG_SINGCORNER,
+  HP_TRIG_SINGCORNER12,
+  HP_TRIG_SINGCORNER123,
+  HP_TRIG_SINGCORNER123_2D,   // not rotational symmetric
+  HP_TRIG_SINGEDGE = 20,
+  HP_TRIG_SINGEDGECORNER1,   // E = 100, V = 100
+  HP_TRIG_SINGEDGECORNER2,   // E = 100, V = 010
+  HP_TRIG_SINGEDGECORNER12,  // E = 100, V = 110
+  HP_TRIG_SINGEDGECORNER3,
+  HP_TRIG_SINGEDGECORNER13,
+  HP_TRIG_SINGEDGECORNER23,
+  HP_TRIG_SINGEDGECORNER123,
+  HP_TRIG_SINGEDGES = 30,
+  HP_TRIG_SINGEDGES2,
+  HP_TRIG_SINGEDGES3,
+  HP_TRIG_SINGEDGES23,
+  HP_TRIG_3SINGEDGES = 40,
+
+  HP_QUAD = 50,
+  HP_QUAD_SINGCORNER,
+  HP_DUMMY_QUAD_SINGCORNER,
+  HP_QUAD_SINGEDGE,
+  HP_QUAD_0E_2VA,  // V = 1100
+  HP_QUAD_0E_2VB,  // V = 1010
+  HP_QUAD_0E_3V,
+  HP_QUAD_0E_4V,
+
+  // one edge: marked edge is always edge from vertex 1 to vertex 2 (E = 1000)
+  HP_QUAD_1E_1VA,  // vertex on beginning of edge: V = 1000
+  HP_QUAD_1E_1VB,  // vertex on end of edge: V = 0100
+  HP_QUAD_1E_1VC,  // V = 0010
+  HP_QUAD_1E_1VD,  // V = 0001
+
+  HP_QUAD_1E_2VA,  // V = 1100
+  HP_QUAD_1E_2VB,  // V = 1010
+  HP_QUAD_1E_2VC,  // V = 1001
+  HP_QUAD_1E_2VD,  // V = 0110
+  HP_QUAD_1E_2VE,  // V = 0101
+  HP_QUAD_1E_2VF,  // V = 0011
+
+  HP_QUAD_1E_3VA,  // V = 1110
+  HP_QUAD_1E_3VB,  // V = 1101
+  HP_QUAD_1E_3VC,  // V = 1011
+  HP_QUAD_1E_3VD,  // V = 0111
+
+  HP_QUAD_1E_4V,   // V = 1111
+
+
+  HP_QUAD_2E,      // E = 1001, V = 1000
+  HP_QUAD_2E_1VA,  // E = 1001, V = 1100
+  HP_QUAD_2E_1VB,  // E = 1001, V = 1010
+  HP_QUAD_2E_1VC,  // E = 1001, V = 1001
+  HP_QUAD_2E_2VA,  // E = 1001, V = 1110
+  HP_QUAD_2E_2VB,  // E = 1001, V = 1101
+  HP_QUAD_2E_2VC,  // E = 1001, V = 1011
+  HP_QUAD_2E_3V,   // E = 1001, V = 1111
+
+  HP_QUAD_2EB_0V,   // E = 1010, V = 0000
+  HP_QUAD_2EB_1VA,  // E = 1010, V = 1000
+  HP_QUAD_2EB_1VB,  // E = 1010, V = 0100
+  HP_QUAD_2EB_2VA,  // E = 1010, V = 1100
+  HP_QUAD_2EB_2VB,  // E = 1010, V = 1010
+  HP_QUAD_2EB_2VC,  // E = 1010, V = 1001
+  HP_QUAD_2EB_2VD,  // E = 1010, V = 0101
+  HP_QUAD_2EB_3VA,  // E = 1010, V = 1110
+  HP_QUAD_2EB_3VB,  // E = 1010, V = 1101
+
+  HP_QUAD_2EB_4V,
+
+
+  HP_QUAD_3E,      // E = 1101, V = 1100
+  HP_QUAD_3E_3VA,  // E = 1101, V = 1110
+  HP_QUAD_3E_3VB,  // E = 1101, V = 1101
+  HP_QUAD_3E_4V,   // E = 1101, V = 1111
+
+  HP_QUAD_4E,
+
+
+  HP_TET = 100,     // no singular vertex/edge
+  HP_TET_0E_1V,     // V1
+  HP_TET_0E_2V,     // V1,2
+  HP_TET_0E_3V,     // V1,2,3  
+  HP_TET_0E_4V,     // V1,2,3,4
+  HP_TET_1E_0V = 200,   // E1-2
+  HP_TET_1E_1VA,    // V1
+  HP_TET_1E_1VB,    // V3
+  HP_TET_1E_2VA,    // V1,2
+  HP_TET_1E_2VB,    // V1,3
+  HP_TET_1E_2VC,    // V1,4
+  HP_TET_1E_2VD,    // V3,4
+  HP_TET_1E_3VA,    // V1,2,3
+  HP_TET_1E_3VB,    // V1,3,4
+  HP_TET_1E_4V,     // V1,2,3,4
+
+
+  // 2 connected edges, additonally marked Vs
+  HP_TET_2EA_0V = 220,    // E1-2, E1-3
+  HP_TET_2EA_1VA,   // V2
+  HP_TET_2EA_1VB,   // V3
+  HP_TET_2EA_1VC,   // V4
+  HP_TET_2EA_2VA,   // V2,3
+  HP_TET_2EA_2VB,   // V2,4
+  HP_TET_2EA_2VC,   // V3,4
+  HP_TET_2EA_3V,    // V2,3,4
+
+  // 2 opposite edges
+  HP_TET_2EB_0V = 230,    // E1-2, E3-4
+  HP_TET_2EB_1V,    // V1
+  HP_TET_2EB_2VA,   // V1,2
+  HP_TET_2EB_2VB,   // V1,3
+  HP_TET_2EB_2VC,   // V1,4
+  HP_TET_2EB_3V,    // V1,2,3
+  HP_TET_2EB_4V,    // V1,2,3,4
+
+  HP_TET_3EA_0V = 400,  // E1-2, E1-3, E1-4, 3 edges connected
+  HP_TET_3EA_1V,        // V2
+  HP_TET_3EA_2V,        // V2,3
+  HP_TET_3EA_3V,        // V2,3,4
+
+  HP_TET_3EB_0V = 420,  // E1-2, E1-4, E2-3  3 edges chain
+  HP_TET_3EB_1V,        // 
+  HP_TET_3EB_2V,        // 
+  HP_TET_3EC_0V = 430,  // 3 edges chain, alter
+  HP_TET_3EC_1V,        // 3 edges chain, alter
+  HP_TET_3EC_2V,        // 3 edges chain, alter
+
+
+  HP_TET_1F_0E_0V = 500,  // 1 singular face
+  HP_TET_1F_0E_1VA,       // 1 sing vertex in face (V2)
+  HP_TET_1F_0E_1VB,       // 1 sing vertex not in face (V1)
+  HP_TET_1F_1EA_0V,       // 1 sing edge not in face
+  HP_TET_1F_1EB_0V,       // 1 sing edge in face
+  HP_TET_2F_0E_0V = 600,  // 2 singular faces
+
+  HP_PRISM = 1000,
+  HP_PRISM_SINGEDGE,
+  HP_PRISM_SINGEDGE_V12,
+  HP_PRISM_SINGEDGE_H1,
+  HP_PRISM_SINGEDGE_H12,
+
+  HP_PRISM_1FA_0E_0V,     // 1 singular trig face
+  HP_PRISM_2FA_0E_0V,     // 2 singular trig faces
+  HP_PRISM_1FB_0E_0V,     // 1 singular quad face  1-2-4-5
+
+  HP_PRISM_1FB_1EA_0V,     // 1 singular quad face, edge is 1-2
+  HP_PRISM_1FA_1E_0V, 
+  HP_PRISM_2FA_1E_0V, 
+  HP_PRISM_1FA_1FB_0E_0V, 
+  HP_PRISM_2FA_1FB_0E_0V,
+  HP_PRISM_1FA_1FB_1EA_0V, 
+  HP_PRISM_1FA_1FB_1EB_0V, 
+  HP_PRISM_2FA_1FB_1EA_0V,
+  HP_PRISM_1FB_1EC_0V, 
+  HP_PRISM_1FA_1FB_1EC_0V, 
+  HP_PRISM_2FA_1FB_1EC_0V,
+  HP_PRISM_1FB_2EA_0V, 
+  HP_PRISM_1FA_1FB_2EA_0V, 
+  HP_PRISM_2FA_1FB_2EA_0V,
+  HP_PRISM_1FB_2EB_0V,
+  HP_PRISM_1FA_1FB_2EB_0V,  
+  HP_PRISM_1FA_1FB_2EC_0V, 
+  HP_PRISM_2FA_1FB_2EB_0V, 
+  HP_PRISM_1FB_3E_0V, 
+  HP_PRISM_1FA_1FB_3E_0V, 
+  HP_PRISM_2FA_1FB_3E_0V, 
+  HP_PRISM_2FB_0E_0V, 
+  HP_PRISM_1FA_2FB_0E_0V, 
+  HP_PRISM_2FA_2FB_0E_0V,
+  HP_PRISM_2FB_1EC_0V, 
+  HP_PRISM_1FA_2FB_1EC_0V,
+  HP_PRISM_1FA_2FB_1EB_0V,
+  HP_PRISM_2FA_2FB_1EC_0V,
+  HP_PRISM_2FB_3E_0V, 
+  HP_PRISM_1FA_2FB_3E_0V, 
+  HP_PRISM_2FA_2FB_3E_0V, 
+  HP_PRISM_1FA_2E_0V, 
+  HP_PRISM_2FA_2E_0V,
+  HP_PRISM_3E_0V, 
+  HP_PRISM_1FA_3E_0V, 
+  HP_PRISM_2FA_3E_0V,  
+  HP_PRISM_3FB_0V, 
+  HP_PRISM_1FA_3FB_0V, 
+  HP_PRISM_2FA_3FB_0V,  
+  HP_PRISM_3E_4EH,
+  
+ 
+
+  /*  HP_PRISM_1FB_1EA_0V,     // 1 singular quad face, edge is 1-4
+  HP_PRISM_1FB_1EB_0V,     // 1 singular quad face, edge is 2-5
+  HP_PRISM_2F_0E_0V,      // 2 singular quad faces
+  */
+
+  HP_PYRAMID = 2000,
+  HP_PYRAMID_0E_1V,
+  HP_PYRAMID_EDGES,
+  HP_PYRAMID_1FB_0E_1VA,  // 1 trig face, top vertex
+
+  HP_HEX = 3000,
+  HP_HEX_0E_1V,
+  HP_HEX_1E_1V,
+  HP_HEX_1E_0V,
+  HP_HEX_3E_0V,
+  HP_HEX_1F_0E_0V,
+  HP_HEX_1FA_1FB_0E_0V, 
+};
+
+
+
+struct HPRef_Struct {
+  HPREF_ELEMENT_TYPE geom;
+  int (*splitedges)[3];
+  int (*splitfaces)[4];
+  int (*splitelements)[5];
+  HPREF_ELEMENT_TYPE * neweltypes;
+  int (*newels)[8];
+};
+
+
+
+
+class HPRefElement
+{
+private:
+  void Reset(void);
+
+public:
+  HPRefElement (); 
+  HPRefElement(Element & el);
+  HPRefElement(Element2d & el);
+  HPRefElement(Segment & el);	
+  HPRefElement(HPRefElement & el);
+
+  void SetType( HPREF_ELEMENT_TYPE t);
+  // HPRefElement(HPRefElement & el, HPREF_ELEMENT_TYPE t); 
+	       
+  /* HPRefElement(HPRefElement & el, HPREF_ELEMENT_TYPE t)
+  { 
+    type = t; 
+    HPRef_Struct * hprs = Get_HPRef_Struct(t);
+    for (int i=0; i<np ; i++) 
+      {
+	pnums[i] = el[i];
+	for(int l=0; l<np; l++) param[i][l] = el.param[i][l]; 
+      }
+    switch(hprs->geom)
+      {
+      case HP_SEGM: np=2; sing_edge_left=0; sing_edge_right=0; break; 
+      case HP_QUAD: np=4; break; 
+      case HP_TRIG: np=3; break; 
+      case HP_HEX: np=8; break; 
+      case HP_PRISM: np=6; break;
+      case HP_TET: np=4; break; 
+      case HP_PYRAMID: np=5; break; 
+      }
+    index = el.index; 
+    levelx = el.levelx; 
+    levely = el.levely; 
+    levelz = el.levelz; 
+    type = el.type; 
+    coarse_elnr = el.coarse_elnr;
+    singedge_left = el.singedge_left; 
+    singedge_right = el.singedge_left; 
+    } */ 
+  
+  HPREF_ELEMENT_TYPE type;
+  PointIndex pnums[8];
+  double param[8][3];
+  int index;
+  int levelx;
+  int levely;
+  int levelz;
+  int np; 
+  int coarse_elnr;
+  int domin, domout; // he: needed for segment!! in 3d there should be surf1, surf2!!
+  // int coarse_hpelnr; 
+  PointIndex & operator[](int i) { return(pnums[i]);}
+  PointIndex & PNumMod(int i) { return pnums[(i-1) % np]; };
+  PointIndex & PNum(int i) {return pnums[(i-1)]; };
+  int GetIndex () const { return index; }; 
+  double singedge_left, singedge_right; 
+  
+
+  //  EdgePointGeomInfo epgeominfo[2];
+  
+};
+
+
+
+extern void HPRefinement (Mesh & mesh, Refinement * ref, int levels, 
+			  double fac1=0.125, bool setorders=true, bool ref_level = false);
+
+
+#endif
+
diff --git a/contrib/Netgen/libsrc/meshing/improve2.cpp b/contrib/Netgen/libsrc/meshing/improve2.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..4824d4eb31335a0161223dc5d78ae00c170b38f5
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/improve2.cpp
@@ -0,0 +1,831 @@
+#include <mystdlib.h>
+
+#include "meshing.hpp"
+#include <opti.hpp>
+
+#ifndef SMALLLIB
+//#ifndef NOTCL
+//#include <visual.hpp>
+//#endif
+#endif
+
+namespace netgen
+{
+
+class Neighbour
+{
+  int nr[3];
+  int orient[3];
+
+public:
+  Neighbour () { nr[0] = nr[1] = nr[2] = -1; orient[0] = orient[1] = orient[2] = 0; }
+
+  void SetNr (int side, int anr) { nr[side-1] = anr; }
+  int GetNr (int side) { return nr[side-1]; }
+
+  void SetOrientation (int side, int aorient) { orient[side-1] = aorient; }
+  int GetOrientation (int side) { return orient[side-1]; }
+};
+
+
+
+
+class trionedge
+{
+public:
+  int tnr;
+  int sidenr;
+
+  trionedge () { tnr = 0; sidenr = 0; }
+  trionedge (int atnr, int asidenr)
+    { tnr = atnr; sidenr = asidenr; }
+};
+
+
+
+ 
+void MeshOptimize2d :: EdgeSwapping (Mesh & mesh, int usemetric)
+{
+  //  return; 
+
+  if (!faceindex)
+    {
+      if (usemetric)
+	PrintMessage (3, "Edgeswapping, metric");
+      else
+	PrintMessage (3, "Edgeswapping, topological");
+
+      for (faceindex = 1; faceindex <= mesh.GetNFD(); faceindex++)
+	{
+	  EdgeSwapping (mesh, usemetric);
+
+	  if (multithread.terminate)
+	    throw NgException ("Meshing stopped");
+	}
+
+      faceindex = 0;
+      mesh.CalcSurfacesOfNode();
+      return;
+    }
+
+
+  static int timer = NgProfiler::CreateTimer ("EdgeSwapping 2D");
+  NgProfiler::RegionTimer reg1 (timer);
+
+
+  int i, i2, j, j2;
+  bool should;
+  PointIndex pi;
+
+  ARRAY<SurfaceElementIndex> seia;
+  mesh.GetSurfaceElementsOfFace (faceindex, seia);
+
+  for (i = 0; i < seia.Size(); i++)
+    if (mesh[seia[i]].GetNP() != 3)
+      {
+	GenericImprove (mesh);
+	return;
+      }
+
+  int surfnr = mesh.GetFaceDescriptor (faceindex).SurfNr();
+
+  ARRAY<Neighbour> neighbors(mesh.GetNSE());
+  INDEX_2_HASHTABLE<trionedge> other(seia.Size() + 2);
+
+
+  ARRAY<char> swapped(mesh.GetNSE());
+  ARRAY<int,PointIndex::BASE> pdef(mesh.GetNP());
+  ARRAY<double,PointIndex::BASE> pangle(mesh.GetNP());
+
+  SurfaceElementIndex t1, t2;
+  int o1, o2;
+
+  PointIndex pi1, pi2, pi3, pi4;
+  PointGeomInfo gi1, gi2, gi3, gi4;
+
+
+  int nswaps = 0;
+  int e, done;
+  double d;
+  Vec3d nv1, nv2;
+  double horder;
+  double loch(-1);
+  static const double minangle[] = { 0, 1.481, 2.565, 3.627, 4.683, 5.736, 7, 9 };
+
+  pangle = 0;
+
+  for (i = 0; i < seia.Size(); i++)
+    {
+      const Element2d & sel = mesh[seia[i]];
+      for (j = 0; j < 3; j++)
+	{
+	  POINTTYPE typ = mesh[sel[j]].Type();
+	  if (typ == FIXEDPOINT || typ == EDGEPOINT)
+	    {
+	      pangle[sel[j]] +=
+		Angle (mesh[sel[(j+1)%3]] - mesh[sel[j]],
+		       mesh[sel[(j+2)%3]] - mesh[sel[j]]);
+	    }
+	}
+    }
+
+  for (pi = PointIndex::BASE; 
+       pi < mesh.GetNP()+PointIndex::BASE; pi++)
+    {
+      if (mesh[pi].Type() == INNERPOINT || mesh[pi].Type() == SURFACEPOINT)
+	pdef[pi] = -6;
+      else
+	for (j = 0; j < 8; j++)
+	  if (pangle[pi] >= minangle[j])
+	    pdef[pi] = -1-j;
+    }
+
+  for (i = 0; i < seia.Size(); i++)
+    {
+      const Element2d & sel = mesh[seia[i]];
+      for (j = 0; j < 3; j++)
+	pdef[sel[j]]++;
+    }
+
+  for (i = 0; i < seia.Size(); i++)
+    {
+      //const Element2d & sel = mesh[seia[i]];
+      for (j = 0; j < 3; j++)
+	{
+	  neighbors[seia[i]].SetNr (j+1, -1);
+	  neighbors[seia[i]].SetOrientation (j+1, 0);
+	}
+    }
+
+  /*
+  ARRAY<Vec3d> normals(mesh.GetNP());
+  for (i = 1; i <= mesh.GetNSE(); i++)
+    {
+      Element2d & hel = mesh.SurfaceElement(i);
+      if (hel.GetIndex() == faceindex)
+	for (k = 1; k <= 3; k++)
+	  {
+	    int pi = hel.PNum(k);
+	    SelectSurfaceOfPoint (mesh.Point(pi), hel.GeomInfoPi(k));
+	    int surfi = mesh.GetFaceDescriptor(faceindex).SurfNr();
+	    GetNormalVector (surfi, mesh.Point(pi), normals.Elem(pi));
+	    normals.Elem(pi) /= normals.Elem(pi).Length();
+	  }
+    }
+  */	    
+
+  
+  for (i = 0; i < seia.Size(); i++)
+    {
+      const Element2d & sel = mesh[seia[i]];
+
+      for (j = 1; j <= 3; j++)
+	{
+	  pi1 = sel.PNumMod(j+1);
+	  pi2 = sel.PNumMod(j+2);
+	  
+	  loch = mesh.GetH(mesh[pi1]);
+	    
+	  INDEX_2 edge(pi1, pi2);
+	  edge.Sort();
+	  
+	  if (mesh.IsSegment (pi1, pi2))
+	    continue;
+	  
+	  /*
+	    if (segments.Used (edge))
+	    continue;
+	  */
+	  INDEX_2 ii2 (pi1, pi2);
+	  if (other.Used (ii2))
+	    {
+	      // INDEX_2 i2s(ii2);
+	      // i2s.Sort();
+	      
+	      i2 = other.Get(ii2).tnr;
+	      j2 = other.Get(ii2).sidenr;
+		
+	      neighbors[seia[i]].SetNr (j, i2);
+	      neighbors[seia[i]].SetOrientation (j, j2);
+	      neighbors[i2].SetNr (j2, seia[i]);
+	      neighbors[i2].SetOrientation (j2, j);
+	    }
+	  else
+	    {
+	      other.Set (INDEX_2 (pi2, pi1), trionedge (seia[i], j));
+	    }
+	}
+    }
+
+  for (i = 0; i < seia.Size(); i++)
+    swapped[seia[i]] = 0;
+
+
+  int t = 4;
+  done = 0;
+  while (!done && t >= 2)
+    {
+      for (i = 0; i < seia.Size(); i++)
+	{
+	  t1 = seia[i];
+
+	  if (mesh[t1].IsDeleted())
+	    continue;
+
+	  if (mesh[t1].GetIndex() != faceindex)
+	    continue;
+
+	  if (multithread.terminate)
+	    throw NgException ("Meshing stopped");
+
+	  for (o1 = 1; o1 <= 3; o1++)
+	    {
+	      t2 = neighbors[t1].GetNr (o1);
+	      o2 = neighbors[t1].GetOrientation (o1);
+
+	      if (t2 == -1) continue;
+	      if (swapped[t1] || swapped[t2]) continue;
+	      
+
+	      pi1 = mesh[t1].PNumMod(o1+1);
+	      pi2 = mesh[t1].PNumMod(o1+2);
+	      pi3 = mesh[t1].PNumMod(o1);
+	      pi4 = mesh[t2].PNumMod(o2);
+	      
+	      gi1 = mesh[t1].GeomInfoPiMod(o1+1);
+	      gi2 = mesh[t1].GeomInfoPiMod(o1+2);
+	      gi3 = mesh[t1].GeomInfoPiMod(o1);
+	      gi4 = mesh[t2].GeomInfoPiMod(o2);
+	    
+	      bool allowswap = true;
+
+	      Vec3d auxvec1,auxvec2;
+
+	      auxvec1 = mesh.Point(pi3)-mesh.Point(pi4);
+	      auxvec2 = mesh.Point(pi1)-mesh.Point(pi4);
+	      allowswap = allowswap && fabs(1.-(auxvec1*auxvec2)/(auxvec1.Length()*auxvec2.Length())) > 1e-4;
+
+	      if(!allowswap)
+		continue;
+
+	      // normal of new
+	      nv1 = Cross (auxvec1, 
+			   auxvec2);
+
+	      auxvec1 = mesh.Point(pi4)-mesh.Point(pi3);
+	      auxvec2 = mesh.Point(pi2)-mesh.Point(pi3);
+	      allowswap = allowswap && fabs(1.-(auxvec1*auxvec2)/(auxvec1.Length()*auxvec2.Length())) > 1e-4;
+
+
+	      if(!allowswap)
+		continue;
+
+	      nv2 = Cross (auxvec1, 
+			   auxvec2);
+
+	      
+	      // normals of original
+	      Vec3d nv3, nv4;
+	      nv3 = Cross (mesh.Point(pi1)-mesh.Point(pi4), 
+			   mesh.Point(pi2)-mesh.Point(pi4));
+	      nv4 = Cross (mesh.Point(pi2)-mesh.Point(pi3), 
+			   mesh.Point(pi1)-mesh.Point(pi3));
+	      
+	      nv3 *= -1;
+	      nv4 *= -1;
+	      nv3.Normalize();
+	      nv4.Normalize();
+
+	      nv1.Normalize();
+	      nv2.Normalize();
+	    
+	      Vec<3> nvp3, nvp4;
+	      SelectSurfaceOfPoint (mesh.Point(pi3), gi3);
+	      GetNormalVector (surfnr, mesh.Point(pi3), gi3, nvp3);
+
+	      nvp3.Normalize();
+
+	      SelectSurfaceOfPoint (mesh.Point(pi4), gi4);
+	      GetNormalVector (surfnr, mesh.Point(pi4), gi4, nvp4);
+	    
+	      nvp4.Normalize();
+	      
+	      
+	      
+	      double critval = cos (M_PI / 6);  // 30 degree
+	      allowswap = allowswap &&
+		(nv1 * nvp3 > critval) && 
+		(nv1 * nvp4 > critval) && 
+		(nv2 * nvp3 > critval) && 
+		(nv2 * nvp4 > critval) &&
+		(nvp3 * nv3 > critval) && 
+		(nvp4 * nv4 > critval);
+	      
+
+	      horder = Dist (mesh.Point(pi1), mesh.Point(pi2));
+
+	      if ( // nv1 * nv2 >= 0 &&
+		  nv1.Length() > 1e-3 * horder * horder &&
+		  nv2.Length() > 1e-3 * horder * horder &&
+		  allowswap )
+		{
+		  if (!usemetric)
+		    {
+		      e = pdef[pi1] + pdef[pi2] - pdef[pi3] - pdef[pi4];
+		      d = 
+			Dist2 (mesh.Point(pi1), mesh.Point(pi2)) - 
+			Dist2 (mesh.Point(pi3), mesh.Point(pi4));
+		      
+		      should = e >= t && (e > 2 || d > 0);
+		    }
+		  else
+		    {
+		      should = 
+			CalcTriangleBadness (mesh.Point(pi4), mesh.Point(pi3), mesh.Point(pi1), 
+					     metricweight, loch) +
+			CalcTriangleBadness (mesh.Point(pi3), mesh.Point(pi4), mesh.Point(pi2), 
+					     metricweight, loch) <
+			CalcTriangleBadness (mesh.Point(pi1), mesh.Point(pi2), mesh.Point(pi3), 
+					     metricweight, loch) +
+			CalcTriangleBadness (mesh.Point(pi2), mesh.Point(pi1), mesh.Point(pi4), 
+					     metricweight, loch);
+
+		    }
+		  
+		  if (allowswap)
+		    {
+		      Element2d sw1 (pi4, pi3, pi1);
+		      Element2d sw2 (pi3, pi4, pi2);
+
+		      int legal1 = 
+			mesh.LegalTrig (mesh.SurfaceElement (t1)) + 
+			mesh.LegalTrig (mesh.SurfaceElement (t2));
+		      int legal2 = 
+			mesh.LegalTrig (sw1) + mesh.LegalTrig (sw2);
+
+		      if (legal1 < legal2) should = 1;
+		      if (legal2 < legal1) should = 0;
+		    }
+		  
+		  if (should)
+		    {
+		      // do swapping !
+		      
+		      // cout << "swap " << endl;
+
+		      nswaps ++;
+		      
+		      // testout << "nv1 = " << nv1 << "   nv2 = " << nv2 << endl;
+		     
+
+		      done = 1;
+		      
+		      mesh[t1].PNum(1) = pi1;
+		      mesh[t1].PNum(2) = pi4;
+		      mesh[t1].PNum(3) = pi3;
+		      
+		      mesh[t2].PNum(1) = pi2;
+		      mesh[t2].PNum(2) = pi3;
+		      mesh[t2].PNum(3) = pi4;
+		      
+		      mesh[t1].GeomInfoPi(1) = gi1;
+		      mesh[t1].GeomInfoPi(2) = gi4;
+		      mesh[t1].GeomInfoPi(3) = gi3;
+		      
+		      mesh[t2].GeomInfoPi(1) = gi2;
+		      mesh[t2].GeomInfoPi(2) = gi3;
+		      mesh[t2].GeomInfoPi(3) = gi4;
+		      
+		      pdef[pi1]--;
+		      pdef[pi2]--;
+		      pdef[pi3]++;
+		      pdef[pi4]++;
+		      
+		      swapped[t1] = 1;
+		      swapped[t2] = 1;
+		    }
+		}
+	    }
+	}
+      t--;
+    }
+
+  mesh.SetNextTimeStamp();
+}
+
+
+
+
+
+
+
+ 
+void MeshOptimize2d :: CombineImprove (Mesh & mesh)
+{
+  if (!faceindex)
+    {
+      PrintMessage (3, "Combine improve");
+
+      for (faceindex = 1; faceindex <= mesh.GetNFD(); faceindex++)
+	{
+	  CombineImprove (mesh);
+
+	  if (multithread.terminate)
+	    throw NgException ("Meshing stopped");
+	}
+      faceindex = 0;
+      return;
+    }
+
+
+  static int timer = NgProfiler::CreateTimer ("Combineimprove 2D");
+  NgProfiler::RegionTimer reg (timer);
+
+
+
+  int i, j, k, l;
+  PointIndex pi;
+  SurfaceElementIndex sei;
+
+
+  ARRAY<SurfaceElementIndex> seia;
+  mesh.GetSurfaceElementsOfFace (faceindex, seia);
+
+
+  for (i = 0; i < seia.Size(); i++)
+    if (mesh[seia[i]].GetNP() != 3)
+      return;
+
+
+
+  int surfnr = 0;
+  if (faceindex)
+    surfnr = mesh.GetFaceDescriptor (faceindex).SurfNr();
+
+
+  PointIndex pi1, pi2;
+  MeshPoint p1, p2, pnew;
+  double bad1, bad2;
+  Vec<3> nv;
+
+  int np = mesh.GetNP();
+  //int nse = mesh.GetNSE();
+
+  TABLE<SurfaceElementIndex,PointIndex::BASE> elementsonnode(np); 
+  ARRAY<SurfaceElementIndex> hasonepi, hasbothpi;
+
+  for (i = 0; i < seia.Size(); i++)
+    {
+      Element2d & el = mesh[seia[i]];
+      for (j = 0; j < el.GetNP(); j++)
+	{
+	  elementsonnode.Add (el[j], seia[i]);
+	}      
+    }
+
+
+  ARRAY<bool,PointIndex::BASE> fixed(np);
+  fixed = false;
+
+  SegmentIndex si;
+  for (si = 0; si < mesh.GetNSeg(); si++)
+    {
+      INDEX_2 i2(mesh[si].p1, mesh[si].p2);
+      fixed[i2.I1()] = true;
+      fixed[i2.I2()] = true;
+    }
+
+  for(i = 0; i<mesh.LockedPoints().Size(); i++)
+    fixed[mesh.LockedPoints()[i]] = true;
+
+
+  ARRAY<Vec<3>,PointIndex::BASE> normals(np);
+
+  for (pi = PointIndex::BASE; 
+       pi < np + PointIndex::BASE; pi++)
+    {
+      if (elementsonnode[pi].Size())
+	{
+	  Element2d & hel = mesh[elementsonnode[pi][0]];
+	  for (k = 0; k < 3; k++)
+	    if (hel[k] == pi)
+	      {
+		SelectSurfaceOfPoint (mesh[pi], hel.GeomInfoPi(k+1));
+		GetNormalVector (surfnr, mesh[pi], hel.GeomInfoPi(k+1), normals[pi]);
+		break;
+	      }
+	  if (k == 3)
+	    {
+	      cerr << "Neuer Fehler von Joachim, code 17121" << endl;
+	    }
+	}
+    }
+
+
+  for (i = 0; i < seia.Size(); i++)
+    {
+
+      sei = seia[i];
+      Element2d & elem = mesh[sei];
+      if (elem.IsDeleted()) continue;
+
+      for (j = 0; j < 3; j++)
+	{
+	  pi1 = elem[j];
+	  pi2 = elem[(j+1) % 3];
+
+	  if (pi1 < PointIndex::BASE || 
+	      pi2 < PointIndex::BASE)
+	    continue;
+
+	  /*
+	  INDEX_2 i2(pi1, pi2);
+	  i2.Sort();
+	  if (segmentht.Used(i2))
+	    continue;
+	  */
+
+	  bool debugflag = 0;
+
+	  if (debugflag)
+	    {
+	      (*testout) << "Combineimprove, face = " << faceindex 
+			 << "pi1 = " << pi1 << " pi2 = " << pi2 << endl;
+	    }
+
+	  /*
+	  // save version:
+	  if (fixed.Get(pi1) || fixed.Get(pi2)) 
+	    continue;
+	  if (pi2 < pi1) swap (pi1, pi2);
+	  */
+
+	  // more general 
+	  if (fixed[pi2]) 
+	    Swap (pi1, pi2);
+
+	  if (fixed[pi2])  
+	    continue;
+
+	  double loch = mesh.GetH (mesh[pi1]);
+
+	  INDEX_2 si2 (pi1, pi2);
+	  si2.Sort();
+
+	  /*	  
+	  if (edgetested.Used (si2))
+	    continue;
+	  edgetested.Set (si2, 1);
+	  */
+
+	  hasonepi.SetSize(0);
+	  hasbothpi.SetSize(0);
+
+	  for (k = 0; k < elementsonnode[pi1].Size(); k++)
+	    {
+	      const Element2d & el2 = mesh[elementsonnode[pi1][k]];
+
+	      if (el2.IsDeleted()) continue;
+
+	      if (el2[0] == pi2 || el2[1] == pi2 || el2[2] == pi2)
+		{
+		  hasbothpi.Append (elementsonnode[pi1][k]);
+		  nv = Cross (Vec3d (mesh[el2[0]], mesh[el2[1]]),
+			      Vec3d (mesh[el2[0]], mesh[el2[2]]));
+		}
+	      else
+		{
+		  hasonepi.Append (elementsonnode[pi1][k]);
+		}
+	    } 
+
+
+	  Element2d & hel = mesh[hasbothpi[0]];
+	  for (k = 0; k < 3; k++)
+	    if (hel[k] == pi1)
+	      {
+		SelectSurfaceOfPoint (mesh[pi1],
+				      hel.GeomInfoPi(k+1));
+		GetNormalVector (surfnr, mesh[pi1], hel.GeomInfoPi(k+1), nv);
+		break;
+	      }
+	  if (k == 3)
+	    {
+	      cerr << "Neuer Fehler von Joachim, code 32434" << endl;
+	    }
+
+
+	  //	  nv = normals.Get(pi1);
+
+
+
+	  for (k = 0; k < elementsonnode[pi2].Size(); k++)
+	    {
+	      const Element2d & el2 = mesh[elementsonnode[pi2][k]];
+	      if (el2.IsDeleted()) continue;
+
+	      if (el2[0] == pi1 || el2[1] == pi1 || el2[2] == pi1)
+		;
+	      else
+		hasonepi.Append (elementsonnode[pi2][k]);
+	    } 
+
+	  bad1 = 0;
+	  int illegal1 = 0, illegal2 = 0;
+	  for (k = 0; k < hasonepi.Size(); k++)
+	    {
+	      const Element2d & el = mesh[hasonepi[k]];
+	      bad1 += CalcTriangleBadness (mesh[el[0]], mesh[el[1]], mesh[el[2]],
+					   nv, -1, loch);
+	      illegal1 += 1-mesh.LegalTrig(el);
+	    }
+	  
+	  for (k = 0; k < hasbothpi.Size(); k++)
+	    {
+	      const Element2d & el = mesh[hasbothpi[k]];
+	      bad1 += CalcTriangleBadness (mesh[el[0]], mesh[el[1]], mesh[el[2]],
+					   nv, -1, loch);
+	      illegal1 += 1-mesh.LegalTrig(el);
+	    }
+	  bad1 /= (hasonepi.Size()+hasbothpi.Size());
+
+	  p1 = mesh[pi1];
+	  p2 = mesh[pi2];
+
+	  pnew = p1;
+	  mesh[pi1] = pnew;
+	  mesh[pi2] = pnew;
+
+	  bad2 = 0;
+	  for (k = 0; k < hasonepi.Size(); k++)
+	    {
+	      Element2d & el = mesh[hasonepi[k]];
+	      double err = 
+		CalcTriangleBadness (mesh[el[0]], mesh[el[1]], mesh[el[2]],
+				     nv, -1, loch);
+	      bad2 += err;
+
+	      Vec<3> hnv = Cross (Vec3d (mesh[el[0]],
+                                         mesh[el[1]]),
+                                  Vec3d (mesh[el[0]],
+                                         mesh[el[2]]));
+	      if (hnv * nv < 0)
+		bad2 += 1e10;
+              
+	      for (l = 0; l < 3; l++)
+		if ( (normals[el[l]] * nv) < 0.5)
+		  bad2 += 1e10;
+
+	      illegal2 += 1-mesh.LegalTrig(el);
+	    }
+	  bad2 /= hasonepi.Size();
+
+	  mesh[pi1] = p1;
+	  mesh[pi2] = p2;
+	  
+       
+	  if (debugflag)
+	    {
+	      (*testout) << "bad1 = " << bad1 << ", bad2 = " << bad2 << endl;
+	    }
+
+
+	  bool should = (bad2 < bad1 && bad2 < 1e4);
+	  if (bad2 < 1e4)
+	    {
+	      if (illegal1 > illegal2) should = 1;
+	      if (illegal2 > illegal1) should = 0;
+	    }
+	  
+
+	  if (should)
+	    {
+	      // (*testout) << "combine !" << endl;
+	      // (*testout) << "bad1 = " << bad1 << ", bad2 = " << bad2 << endl;
+
+
+	      mesh[pi1] = pnew;
+	      PointGeomInfo gi;
+	      bool gi_set(false);
+	      
+	      
+	      Element2d *el1p(NULL);
+	      l=0;
+	      while(mesh[elementsonnode[pi1][l]].IsDeleted() && l<elementsonnode.EntrySize(pi1)) l++;
+	      if(l<elementsonnode.EntrySize(pi1))
+		el1p = &mesh[elementsonnode[pi1][l]];
+	      else
+		cerr << "OOPS!" << endl;
+
+	      for (l = 0; l < el1p->GetNP(); l++)
+		if ((*el1p)[l] == pi1)
+		  {
+		    gi = el1p->GeomInfoPi (l+1);
+		    gi_set = true;
+		  }
+
+	      // (*testout) << "Connect point " << pi2 << " to " << pi1 << "\n";
+	      for (k = 0; k < elementsonnode[pi2].Size(); k++)
+		{
+		  Element2d & el = mesh[elementsonnode[pi2][k]];
+		  if(el.IsDeleted()) continue;
+		  elementsonnode.Add (pi1, elementsonnode[pi2][k]);
+
+		  bool haspi1 = 0;
+		  for (l = 0; l < el.GetNP(); l++)
+		    if (el[l] == pi1)
+		      haspi1 = 1;
+		  if (haspi1) continue;
+
+		  for (l = 0; l < el.GetNP(); l++)
+		    {
+		      if (el[l] == pi2)
+			{
+			  el[l] = pi1;
+			  el.GeomInfoPi (l+1) = gi;
+			}
+
+		      fixed[el[l]] = true;
+		    }
+		}
+
+	      /*
+	      for (k = 0; k < hasbothpi.Size(); k++)
+		{
+		  cout << mesh[hasbothpi[k]] << endl;
+		  for (l = 0; l < 3; l++)
+		    cout << mesh[mesh[hasbothpi[k]][l]] << " ";
+		  cout << endl;
+		}
+	      */
+
+	      for (k = 0; k < hasbothpi.Size(); k++)
+		{
+		  mesh[hasbothpi[k]].Delete();
+		  /*
+		  for (l = 0; l < 4; l++)
+		    mesh[hasbothpi[k]][l] = PointIndex::BASE-1;
+		  */
+		}
+
+	    }
+	}
+    }
+
+  //  mesh.Compress();
+  mesh.SetNextTimeStamp();
+}
+
+
+void MeshOptimize2d :: CheckMeshApproximation (Mesh & mesh)
+{
+  // Check angles between elements and normals at corners
+  /*
+  
+  int i, j;
+  int ne = mesh.GetNSE();
+  int surfnr;
+  
+  Vec3d n, ng;
+  ARRAY<Vec3d> ngs(3);
+
+  (*mycout) << "Check Surface Approxiamtion" << endl;
+  (*testout) << "Check Surface Approxiamtion" << endl;
+
+  for (i = 1; i <= ne; i++)
+    {
+      const Element2d & el = mesh.SurfaceElement(i);
+      surfnr = mesh.GetFaceDescriptor (el.GetIndex()).SurfNr();
+      Vec3d n = Cross (mesh.Point (el.PNum(1)) - mesh.Point (el.PNum(2)),
+		       mesh.Point (el.PNum(1)) - mesh.Point (el.PNum(3)));
+      n /= n.Length();
+
+      for (j = 1; j <= el.GetNP(); j++)
+	{
+	  SelectSurfaceOfPoint (mesh.Point(el.PNum(j)), el.GeomInfoPi(j));
+	  GetNormalVector (surfnr, mesh.Point(el.PNum(j)), ng);
+	  ng /= ng.Length();
+	  ngs.Elem(j) = ng;
+
+	  double angle =  (180.0 / M_PI) * Angle (n, ng);
+	  if (angle > 60)
+	    {
+	      (*testout) << "el " << i << " node " << el.PNum(j)
+			 << "has angle = " << angle << endl;
+	    }
+	}	
+
+      for (j = 1; j <= 3; j++)
+	{
+	  double angle =  (180.0 / M_PI) * Angle (ngs.Get(j), ngs.Get(j%3+1));
+	  if (angle > 60)
+	    {
+	      (*testout) << "el " << i << " node-node " 
+			 << ngs.Get(j) << " - " << ngs.Get(j%3+1)
+			 << " has angle = " << angle << endl;
+	    }
+	}
+    }
+  */
+}
+}
diff --git a/contrib/Netgen/libsrc/meshing/improve2.hpp b/contrib/Netgen/libsrc/meshing/improve2.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..4f25863d40857b5600af1bd2cb24bac3273785c5
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/improve2.hpp
@@ -0,0 +1,102 @@
+#ifndef FILE_IMPROVE2
+#define FILE_IMPROVE2
+
+
+
+///
+class MeshOptimize2d
+{
+  int faceindex;
+  int improveedges;
+  double metricweight;
+  int writestatus;
+
+public:
+  ///
+  MeshOptimize2d ();
+  ///
+  void ImproveMesh (Mesh & mesh2d);
+  void ImproveMeshJacobian (Mesh & mesh2d);
+  void ImproveVolumeMesh (Mesh & mesh);
+  void ProjectBoundaryPoints(ARRAY<int> & surfaceindex, 
+			     const ARRAY<Point<3>* > & from, ARRAY<Point<3>* > & dest);
+
+  void EdgeSwapping (Mesh & mesh, int usemetric);
+  void CombineImprove (Mesh & mesh);
+
+  void GenericImprove (Mesh & mesh);
+
+
+  void SetFaceIndex (int fi) { faceindex = fi; }
+  void SetImproveEdges (int ie) { improveedges = ie; }
+  void SetMetricWeight (double mw) { metricweight = mw; }
+  void SetWriteStatus (int ws) { writestatus = ws; }
+
+
+
+  ///
+  virtual void SelectSurfaceOfPoint (const Point<3> & p,
+				     const PointGeomInfo & gi);
+  ///
+  virtual void ProjectPoint (INDEX /* surfind */, Point<3> & /* p */) const { };
+
+  /// project point, use gi as initial value, and compute new gi
+  virtual int ProjectPointGI (INDEX surfind, Point<3> & p, PointGeomInfo & gi) const 
+  { ProjectPoint (surfind, p); return CalcPointGeomInfo (surfind, gi, p); }
+
+  ///
+  virtual void ProjectPoint2 (INDEX /* surfind */, INDEX /* surfind2 */, Point<3> & /* p */) const { };
+
+  /// liefert zu einem 3d-Punkt die geominfo (Dreieck) und liefert 1, wenn erfolgreich, 
+  /// 0, wenn nicht (Punkt ausserhalb von chart)
+  virtual int CalcPointGeomInfo(PointGeomInfo& gi, const Point<3> & /*p3*/) const
+    { gi.trignum = 1; return 1;};
+
+  virtual int CalcPointGeomInfo(int /* surfind */, PointGeomInfo& gi, const Point<3> & p3) const
+    { return CalcPointGeomInfo (gi, p3); }
+
+  ///
+  virtual void GetNormalVector(INDEX surfind, const Point<3>  & p, PointGeomInfo & gi, Vec<3> & n) const;
+  virtual void GetNormalVector(INDEX surfind, const Point<3> & p, Vec<3> & n) const;
+
+  void CheckMeshApproximation (Mesh & mesh);
+
+
+  ///
+  friend class Opti2SurfaceMinFunction;
+  ///
+  friend class Opti2EdgeMinFunction;
+  ///
+  friend double Opti2FunctionValueGrad (const Vector & x, Vector & grad);
+  ///
+  friend double Opti2EdgeFunctionValueGrad (const Vector & x, Vector & grad);
+
+
+
+};
+
+
+extern void CalcTriangleBadness (double x2, double x3, double y3, 
+				 double metricweight,
+				 double h, double & badness, 
+				 double & g1x, double & g1y);
+
+
+
+
+extern double CalcTriangleBadness (const Point3d & p1, 
+				   const Point3d & p2, 
+				   const Point3d & p3,
+				   double metricweight,
+				   double h);
+
+extern double CalcTriangleBadness (const Point3d & p1, 
+				   const Point3d & p2, 
+				   const Point3d & p3,
+				   const Vec3d & n,
+				   double metricweight,
+				   double h);
+
+#endif
+
+
diff --git a/contrib/Netgen/libsrc/meshing/improve2gen.cpp b/contrib/Netgen/libsrc/meshing/improve2gen.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..75ffc80183a18b9981f95c662ac7d5563391ff88
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/improve2gen.cpp
@@ -0,0 +1,455 @@
+#include <mystdlib.h>
+
+#include "meshing.hpp"
+#include <opti.hpp>
+
+namespace netgen
+{
+
+  class ImprovementRule
+  {
+  public:
+    ARRAY<Element2d> oldels;
+    ARRAY<Element2d> newels;
+    ARRAY<INDEX_2> deledges;
+    ARRAY<int> incelsonnode;
+    ARRAY<int> reused;
+    int bonus;
+    int onp;
+  };
+
+
+  void MeshOptimize2d :: GenericImprove (Mesh & mesh)
+  {
+    if (!faceindex)
+      {
+	if (writestatus)
+	  PrintMessage (3, "Generic Improve");
+
+	for (faceindex = 1; faceindex <= mesh.GetNFD(); faceindex++)
+	  GenericImprove (mesh);
+      
+	faceindex = 0;
+      }
+
+    // int j, k, l, ri;
+    int np = mesh.GetNP();
+    int ne = mesh.GetNSE();
+    //    SurfaceElementIndex sei;
+
+    
+//     for (SurfaceElementIndex sei = 0; sei < ne; sei++)
+//       {
+// 	const Element2d & el = mesh[sei];
+// 	(*testout) << "element " << sei << ": " <<flush;
+// 	for(int j=0; j<el.GetNP(); j++)
+// 	  (*testout) << el[j] << " " << flush;
+// 	(*testout) << "IsDeleted() " << el.IsDeleted()<< endl;
+//       }
+
+    bool ok;
+    int olddef, newdef;
+
+    ARRAY<ImprovementRule*> rules;
+    ARRAY<SurfaceElementIndex> elmap;
+    ARRAY<int> elrot;
+    ARRAY<PointIndex> pmap;
+    ARRAY<PointGeomInfo> pgi;
+
+    int surfnr = mesh.GetFaceDescriptor (faceindex).SurfNr();
+  
+    ImprovementRule * r1;
+
+    // 2 triangles to quad
+    r1 = new ImprovementRule;
+    r1->oldels.Append (Element2d (1, 2, 3));
+    r1->oldels.Append (Element2d (3, 2, 4));
+    r1->newels.Append (Element2d (1, 2, 4, 3));
+    r1->deledges.Append (INDEX_2 (2,3));
+    r1->onp = 4;
+    r1->bonus = 2;
+    rules.Append (r1);
+
+    // 2 quad to 1 quad
+    r1 = new ImprovementRule;
+    r1->oldels.Append (Element2d (1, 2, 3, 4));
+    r1->oldels.Append (Element2d (4, 3, 2, 5));
+    r1->newels.Append (Element2d (1, 2, 5, 4));
+    r1->deledges.Append (INDEX_2 (2, 3));
+    r1->deledges.Append (INDEX_2 (3, 4));
+    r1->onp = 5;
+    r1->bonus = 0;
+    rules.Append (r1);
+
+    // swap quads
+    r1 = new ImprovementRule;
+    r1->oldels.Append (Element2d (1, 2, 3, 4));
+    r1->oldels.Append (Element2d (3, 2, 5, 6));
+    r1->newels.Append (Element2d (1, 6, 3, 4));
+    r1->newels.Append (Element2d (1, 2, 5, 6));
+    r1->deledges.Append (INDEX_2 (2, 3));
+    r1->onp = 6;
+    r1->bonus = 0;
+    rules.Append (r1);
+
+    // three quads to 2
+    r1 = new ImprovementRule;
+    r1->oldels.Append (Element2d (1, 2, 3, 4));
+    r1->oldels.Append (Element2d (2, 5, 6, 3));
+    r1->oldels.Append (Element2d (3, 6, 7, 4));
+    r1->newels.Append (Element2d (1, 2, 5, 4));
+    r1->newels.Append (Element2d (4, 5, 6, 7));
+    r1->deledges.Append (INDEX_2 (2, 3));
+    r1->deledges.Append (INDEX_2 (3, 4));
+    r1->deledges.Append (INDEX_2 (3, 6));
+    r1->onp = 7;
+    r1->bonus = -1;
+    rules.Append (r1);
+
+    // quad + 2 connected trigs to quad
+    r1 = new ImprovementRule;
+    r1->oldels.Append (Element2d (1, 2, 3, 4));
+    r1->oldels.Append (Element2d (2, 5, 3));
+    r1->oldels.Append (Element2d (3, 5, 4));
+    r1->newels.Append (Element2d (1, 2, 5, 4));
+    r1->deledges.Append (INDEX_2 (2, 3));
+    r1->deledges.Append (INDEX_2 (3, 4));
+    r1->deledges.Append (INDEX_2 (3, 5));
+    r1->onp = 5;
+    r1->bonus = 0;
+    rules.Append (r1);
+
+    // quad + 2 non-connected trigs to quad (a and b)
+    r1 = new ImprovementRule;
+    r1->oldels.Append (Element2d (1, 2, 3, 4));
+    r1->oldels.Append (Element2d (2, 6, 3));
+    r1->oldels.Append (Element2d (1, 4, 5));
+    r1->newels.Append (Element2d (1, 3, 4, 5));
+    r1->newels.Append (Element2d (1, 2, 6, 3));
+    r1->deledges.Append (INDEX_2 (1, 4));
+    r1->deledges.Append (INDEX_2 (2, 3));
+    r1->onp = 6;
+    r1->bonus = 0;
+    rules.Append (r1);
+
+    r1 = new ImprovementRule;
+    r1->oldels.Append (Element2d (1, 2, 3, 4));
+    r1->oldels.Append (Element2d (2, 6, 3));
+    r1->oldels.Append (Element2d (1, 4, 5));
+    r1->newels.Append (Element2d (1, 2, 4, 5));
+    r1->newels.Append (Element2d (4, 2, 6, 3));
+    r1->deledges.Append (INDEX_2 (1, 4));
+    r1->deledges.Append (INDEX_2 (2, 3));
+    r1->onp = 6;
+    r1->bonus = 0;
+    rules.Append (r1);
+
+    // two quad + trig -> one quad + trig
+    r1 = new ImprovementRule;
+    r1->oldels.Append (Element2d (1, 2, 3, 4));
+    r1->oldels.Append (Element2d (2, 5, 6, 3));
+    r1->oldels.Append (Element2d (4, 3, 6));
+    r1->newels.Append (Element2d (1, 2, 6, 4));
+    r1->newels.Append (Element2d (2, 5, 6));
+    r1->deledges.Append (INDEX_2 (2, 3));
+    r1->deledges.Append (INDEX_2 (3, 4));
+    r1->deledges.Append (INDEX_2 (3, 6));
+    r1->onp = 6;
+    r1->bonus = -1;
+    rules.Append (r1);
+
+    // swap quad + trig (a and b)
+    r1 = new ImprovementRule;
+    r1->oldels.Append (Element2d (1, 2, 3, 4));
+    r1->oldels.Append (Element2d (2, 5, 3));
+    r1->newels.Append (Element2d (2, 5, 3, 4));
+    r1->newels.Append (Element2d (1, 2, 4));
+    r1->deledges.Append (INDEX_2 (2, 3));
+    r1->onp = 5;
+    r1->bonus = 0;
+    rules.Append (r1);
+
+    r1 = new ImprovementRule;
+    r1->oldels.Append (Element2d (1, 2, 3, 4));
+    r1->oldels.Append (Element2d (2, 5, 3));
+    r1->newels.Append (Element2d (1, 2, 5, 3));
+    r1->newels.Append (Element2d (1, 3, 4));
+    r1->deledges.Append (INDEX_2 (2, 3));
+    r1->onp = 5;
+    r1->bonus = 0;
+    rules.Append (r1);
+
+
+    // 2 quads to quad + 2 trigs
+    r1 = new ImprovementRule;
+    r1->oldels.Append (Element2d (1, 2, 3, 4));
+    r1->oldels.Append (Element2d (3, 2, 5, 6));
+    r1->newels.Append (Element2d (1, 5, 6, 4));
+    r1->newels.Append (Element2d (1, 2, 5));
+    r1->newels.Append (Element2d (4, 6, 3));
+    r1->deledges.Append (INDEX_2 (2, 3));
+    r1->onp = 6;
+    r1->bonus = 0;
+    //    rules.Append (r1);
+
+
+
+
+    ARRAY<int> mapped(rules.Size());
+    ARRAY<int> used(rules.Size());
+    used = 0;
+    mapped = 0;
+
+  
+
+    for (int ri = 0; ri < rules.Size(); ri++)
+      {
+	ImprovementRule & rule = *rules[ri];
+	rule.incelsonnode.SetSize (rule.onp);
+	rule.reused.SetSize (rule.onp);
+
+	for (int j = 1; j <= rule.onp; j++)
+	  {
+	    rule.incelsonnode.Elem(j) = 0;
+	    rule.reused.Elem(j) = 0;
+	  }
+
+	for (int j = 1; j <= rule.oldels.Size(); j++)
+	  {
+	    const Element2d & el = rule.oldels.Elem(j);
+	    for (int k = 1; k <= el.GetNP(); k++)
+	      rule.incelsonnode.Elem(el.PNum(k))--;
+	  }
+
+	for (int j = 1; j <= rule.newels.Size(); j++)
+	  {
+	    const Element2d & el = rule.newels.Elem(j);
+	    for (int k = 1; k <= el.GetNP(); k++)
+	      {
+		rule.incelsonnode.Elem(el.PNum(k))++;
+		rule.reused.Elem(el.PNum(k)) = 1;
+	      }
+	  }
+      }
+
+
+
+  
+    TABLE<int,PointIndex::BASE> elonnode(np);
+    ARRAY<int,PointIndex::BASE> nelonnode(np);
+    TABLE<SurfaceElementIndex> nbels(ne);
+
+    nelonnode = -4;
+
+    for (SurfaceElementIndex sei = 0; sei < ne; sei++)
+      {
+	const Element2d & el = mesh[sei];
+
+	if (el.GetIndex() == faceindex && !el.IsDeleted())
+	  {
+	    for (int j = 0; j < el.GetNP(); j++)
+	      elonnode.Add (el[j], sei);
+	  }
+	if(!el.IsDeleted())
+	  {
+	    for (int j = 0; j < el.GetNP(); j++)
+	      nelonnode[el[j]]++;
+	  }
+      }
+
+    for (SurfaceElementIndex sei = 0; sei < ne; sei++)
+      {
+	const Element2d & el = mesh[sei];
+	if (el.GetIndex() == faceindex && !el.IsDeleted())
+	  {
+	    for (int j = 0; j < el.GetNP(); j++)
+	      {
+		for (int k = 0; k < elonnode[el[j]].Size(); k++)
+		  {
+		    int nbel = elonnode[el[j]] [k];
+		    bool inuse = false;
+		    for (int l = 0; l < nbels[sei].Size(); l++)
+		      if (nbels[sei][l] == nbel)
+			inuse = true;
+		    if (!inuse)
+		      nbels.Add (sei, nbel);
+		  }
+	      }
+	  }
+      }
+
+
+    for (int ri = 0; ri < rules.Size(); ri++)
+      {
+	const ImprovementRule & rule = *rules[ri];
+      
+	elmap.SetSize (rule.oldels.Size());
+	elrot.SetSize (rule.oldels.Size());
+	pmap.SetSize (rule.onp);
+	pgi.SetSize (rule.onp);
+
+
+	for (SurfaceElementIndex sei = 0; sei < ne; sei++)
+	  {
+	    if (multithread.terminate)
+	      break;
+	    if (mesh[sei].IsDeleted()) continue;
+
+	    elmap[0] = sei;
+	    FlatArray<SurfaceElementIndex> neighbours = nbels[sei];
+	    
+	    for (elrot[0] = 0; elrot[0] < mesh[sei].GetNP(); elrot[0]++)
+	      {
+		const Element2d & el0 = mesh[sei];
+		const Element2d & rel0 = rule.oldels[0];
+
+		if (el0.GetIndex() != faceindex) continue;
+		if (el0.IsDeleted()) continue;
+		if (el0.GetNP() != rel0.GetNP()) continue;
+
+
+		pmap = -1;
+ 
+		for (int k = 0; k < el0.GetNP(); k++)
+		  {
+		    pmap.Elem(rel0[k]) = el0.PNumMod(k+elrot[0]+1);
+		    pgi.Elem(rel0[k]) = el0.GeomInfoPiMod(k+elrot[0]+1);
+		  }
+		
+		ok = 1;
+		for (int i = 1; i < elmap.Size(); i++)
+		  {
+		    // try to find a mapping for reference-element i
+
+		    const Element2d & rel = rule.oldels[i];
+		    bool possible = 0;
+
+		    for (elmap[i] = 0; elmap[i] < neighbours.Size(); elmap[i]++)
+		      {
+			const Element2d & el = mesh[neighbours[elmap[i]]];
+			if (el.IsDeleted()) continue;
+			if (el.GetNP() != rel.GetNP()) continue;
+
+			for (elrot[i] = 0; elrot[i] < rel.GetNP(); elrot[i]++)
+			  {
+			    possible = 1;
+
+			    for (int k = 0; k < rel.GetNP(); k++)
+			      if (pmap.Elem(rel[k]) != -1 &&
+				  pmap.Elem(rel[k]) != el.PNumMod (k+elrot[i]+1))
+				possible = 0;
+
+			    if (possible) 
+			      {
+				for (int k = 0; k < el.GetNP(); k++)
+				  {
+				    pmap.Elem(rel[k]) = el.PNumMod(k+elrot[i]+1);
+				    pgi.Elem(rel[k]) = el.GeomInfoPiMod(k+elrot[i]+1);
+				  }
+				break;
+			      }
+			  }
+			if (possible) break;
+		      }
+
+		    if (!possible) 
+		      {
+			ok = 0;
+			break;
+		      }
+
+		    elmap[i] = neighbours[elmap[i]];
+		  }
+
+		for(int i=0; ok && i<rule.deledges.Size(); i++)
+		  {
+		    ok = !mesh.IsSegment(pmap.Elem(rule.deledges[i].I1()),
+					 pmap.Elem(rule.deledges[i].I2()));
+		  }
+								    
+								    
+		
+		
+		if (!ok) continue;
+
+		mapped[ri]++;
+
+		olddef = 0;
+		for (int j = 1; j <= pmap.Size(); j++)
+		  olddef += sqr (nelonnode[pmap.Get(j)]);
+		olddef += rule.bonus;
+
+		newdef = 0;
+		for (int j = 1; j <= pmap.Size(); j++)
+		  if (rule.reused.Get(j))
+		    newdef += sqr (nelonnode[pmap.Get(j)] + 
+				   rule.incelsonnode.Get(j));
+
+		if (newdef > olddef)
+		  continue;
+
+		// calc metric badness
+		double bad1 = 0, bad2 = 0;
+		Vec<3> n;
+
+		SelectSurfaceOfPoint (mesh.Point(pmap.Get(1)), pgi.Get(1));
+		GetNormalVector (surfnr, mesh.Point(pmap.Get(1)), pgi.Elem(1), n);
+		  
+		for (int j = 1; j <= rule.oldels.Size(); j++)
+		  bad1 += mesh.SurfaceElement(elmap.Get(j)).CalcJacobianBadness (mesh.Points(), n);
+		  
+		// check new element:
+		for (int j = 1; j <= rule.newels.Size(); j++)
+		  {
+		    const Element2d & rnel = rule.newels.Get(j);
+		    Element2d nel(rnel.GetNP());
+		    for (int k = 1; k <= rnel.GetNP(); k++)
+		      nel.PNum(k) = pmap.Get(rnel.PNum(k));
+
+		    bad2 += nel.CalcJacobianBadness (mesh.Points(), n);
+		  }
+
+		if (bad2 > 1e3) continue;
+
+		if (newdef == olddef && bad2 > bad1) continue;
+		  
+
+		// generate new element:
+		for (int j = 1; j <= rule.newels.Size(); j++)
+		  {
+		    const Element2d & rnel = rule.newels.Get(j);
+		    Element2d nel(rnel.GetNP());
+		    nel.SetIndex (faceindex);
+		    for (int k = 1; k <= rnel.GetNP(); k++)
+		      {
+			nel.PNum(k) = pmap.Get(rnel.PNum(k));
+			nel.GeomInfoPi(k) = pgi.Get(rnel.PNum(k));
+		      }
+		      
+		    mesh.AddSurfaceElement(nel);
+		  }
+		  
+		for (int j = 0; j < rule.oldels.Size(); j++)
+		  mesh.DeleteSurfaceElement ( elmap[j] );
+
+		for (int j = 1; j <= pmap.Size(); j++)
+		  nelonnode[pmap.Get(j)] += rule.incelsonnode.Get(j);
+
+		used[ri]++;
+	      }
+	  }
+      }
+
+    mesh.Compress();
+
+    for (int ri = 0; ri < rules.Size(); ri++)
+      {
+	PrintMessage (5, "rule ", ri+1, " ",
+		      mapped[ri], "/", used[ri], " mapped/used");
+      }
+  }
+
+
+
+
+}
diff --git a/contrib/Netgen/libsrc/meshing/improve3.cpp b/contrib/Netgen/libsrc/meshing/improve3.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..c2db1e8b49b14cca4304ab58da2193926eae6df2
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/improve3.cpp
@@ -0,0 +1,2820 @@
+#include <mystdlib.h>
+
+#include "meshing.hpp"
+
+#ifdef SOLIDGEOM
+#include <csg.hpp>
+#endif
+#include <opti.hpp>
+
+namespace netgen
+{
+
+/*
+  Combine two points to one.
+  Set new point into the center, if both are
+  inner points.
+  Connect inner point to boundary point, if one
+  point is inner point.
+*/
+
+void MeshOptimize3d :: CombineImprove (Mesh & mesh,
+				       OPTIMIZEGOAL goal)
+{
+  int np = mesh.GetNP();
+  int ne = mesh.GetNE();
+
+  TABLE<ElementIndex, PointIndex::BASE> elementsonnode(np); 
+  ARRAY<ElementIndex> hasonepi, hasbothpi;
+
+  ARRAY<double> oneperr;
+  ARRAY<double> elerrs (ne);
+
+  PrintMessage (3, "CombineImprove");
+  (*testout)  << "Start CombineImprove" << "\n";
+
+  //  mesh.CalcSurfacesOfNode ();
+  const char * savetask = multithread.task;
+  multithread.task = "Combine Improve";
+
+
+  double totalbad = 0;
+  for (ElementIndex ei = 0; ei < ne; ei++)
+    {
+      double elerr = CalcBad (mesh.Points(), mesh[ei], 0);
+      totalbad += elerr;
+      elerrs[ei] = elerr;
+    }
+
+  if (goal == OPT_QUALITY)
+    {
+      totalbad = CalcTotalBad (mesh.Points(), mesh.VolumeElements());
+      (*testout) << "Total badness = " << totalbad << endl;
+      PrintMessage (5, "Total badness = ", totalbad);
+    }
+
+  for (ElementIndex ei = 0; ei < ne; ei++)
+    if (!mesh[ei].IsDeleted())
+      for (int j = 0; j < mesh[ei].GetNP(); j++)
+	elementsonnode.Add (mesh[ei][j], ei);
+  
+  INDEX_2_HASHTABLE<int> edgetested (np+1);
+
+  int cnt = 0;
+
+  for (ElementIndex ei = 0; ei < ne; ei++)
+    {
+      if (multithread.terminate)
+	break;
+      
+      multithread.percent = 100.0 * (ei+1) / ne;
+
+      if (mesh.ElementType(ei) == FIXEDELEMENT)
+	continue;
+
+      for (int j = 0; j < 6; j++)
+	{
+	  Element & elemi = mesh[ei];
+	  if (elemi.IsDeleted()) continue;
+	  
+	  static const int tetedges[6][2] =
+	    { { 0, 1 }, { 0, 2 }, { 0, 3 },
+	      { 1, 2 }, { 1, 3 }, { 2, 3 } };
+
+	  PointIndex pi1 = elemi[tetedges[j][0]];
+	  PointIndex pi2 = elemi[tetedges[j][1]];
+
+	  if (pi2 < pi1) Swap (pi1, pi2);
+	  
+	  INDEX_2 si2 (pi1, pi2);
+	  si2.Sort();
+	  
+	  if (edgetested.Used (si2)) continue;
+	  edgetested.Set (si2, 1);
+
+
+	  // hasonepoint.SetSize(0);
+	  //	  hasbothpoints.SetSize(0);
+	  hasonepi.SetSize(0);
+	  hasbothpi.SetSize(0);
+
+	  FlatArray<ElementIndex> row1 = elementsonnode[pi1];
+	  for (int k = 0; k < row1.Size(); k++)
+	    {
+	      Element & elem = mesh[row1[k]];
+	      if (elem.IsDeleted()) continue;
+
+	      if (elem[0] == pi2 || elem[1] == pi2 ||
+		  elem[2] == pi2 || elem[3] == pi2)
+		{
+		  hasbothpi.Append (row1[k]);
+		}
+	      else
+		{
+		  hasonepi.Append (row1[k]);
+		}
+	    } 
+	  
+	  FlatArray<ElementIndex> row2 = elementsonnode[pi2];	  
+	  for (int k = 0; k < row2.Size(); k++)
+	    {
+	      Element & elem = mesh[row2[k]];
+	      if (elem.IsDeleted()) continue;
+
+	      if (elem[0] == pi1 || elem[1] == pi1 ||
+		  elem[2] == pi1 || elem[3] == pi1)
+		;
+	      else
+		{
+		  hasonepi.Append (row2[k]);
+		}
+	    } 
+	  
+	  double bad1 = 0;
+	  for (int k = 0; k < hasonepi.Size(); k++)
+	    bad1 += elerrs[hasonepi[k]];
+	  for (int k = 0; k < hasbothpi.Size(); k++)
+	    bad1 += elerrs[hasbothpi[k]];
+	  
+	  MeshPoint p1 = mesh[pi1];
+	  MeshPoint p2 = mesh[pi2];
+	  
+
+	  // if (mesh.PointType(pi2) != INNERPOINT)
+	  if (p2.Type() != INNERPOINT)
+	    continue;
+	  
+	  MeshPoint pnew;
+	  // if (mesh.PointType(pi1) != INNERPOINT)
+	  if (p1.Type() != INNERPOINT)
+	    pnew = p1;
+	  else
+	    pnew = Center (p1, p2);
+	    
+	  mesh[pi1] = pnew;
+	  mesh[pi2] = pnew;
+
+	  oneperr.SetSize (hasonepi.Size());
+
+	  double bad2 = 0;
+	  for (int k = 0; k < hasonepi.Size(); k++)
+	    {
+	      const Element & elem = mesh[hasonepi[k]];
+	      double err = CalcTetBadness (mesh[elem[0]], mesh[elem[1]],  
+					   mesh[elem[2]], mesh[elem[3]], 0);
+	      bad2 += err;
+	      oneperr[k] = err;
+	    }
+	  
+	  mesh[pi1] = p1;
+	  mesh[pi2] = p2;
+
+	  // if (mesh.PointType(pi1) != INNERPOINT)
+	  if (p1.Type() != INNERPOINT)
+	    {
+	      for (int k = 0; k < hasonepi.Size(); k++)
+		{
+		  Element & elem = mesh[hasonepi[k]];
+		  int l;
+		  for (l = 0; l < 4; l++)
+		    if (elem[l] == pi2)
+		      {
+			elem[l] = pi1;
+			break;
+		      }
+		      
+		  elem.flags.illegal_valid = 0;
+		  if (!mesh.LegalTet(elem))
+		    bad2 += 1e4;
+		  
+		  if (l < 4)
+		    {
+		      elem.flags.illegal_valid = 0;
+		      elem[l] = pi2;
+		    }
+		}
+	    }
+
+	  if (bad2 / hasonepi.Size()  < 
+	      bad1 / (hasonepi.Size()+hasbothpi.Size()))
+	    {
+	      mesh[pi1] = pnew;
+	      cnt++;
+
+	      FlatArray<ElementIndex> row = elementsonnode[pi2];
+	      for (int k = 0; k < row.Size(); k++)
+		{
+		  Element & elem = mesh[row[k]];
+		  if (elem.IsDeleted()) continue;
+
+		  elementsonnode.Add (pi1, row[k]);
+		  for (int l = 0; l < elem.GetNP(); l++)
+		    if (elem[l] == pi2)
+		      elem[l] = pi1;
+		  
+		  elem.flags.illegal_valid = 0;
+		  if (!mesh.LegalTet (elem))
+		    (*testout) << "illegal tet " << elementsonnode[pi2][k] << endl;
+		}
+
+	      for (int k = 0; k < hasonepi.Size(); k++)
+		elerrs[hasonepi[k]] = oneperr[k];
+	      
+	      for (int k = 0; k < hasbothpi.Size(); k++)
+		{
+		  mesh[hasbothpi[k]].flags.illegal_valid = 0;
+		  mesh[hasbothpi[k]].Delete();
+		}
+	    }
+	}
+    }
+
+  mesh.Compress();
+  mesh.MarkIllegalElements();
+
+  PrintMessage (5, cnt, " elements combined");
+  (*testout) << "CombineImprove done" << "\n";
+
+  totalbad = 0;
+  for (ElementIndex ei = 0; ei < mesh.GetNE(); ei++)
+    totalbad += CalcBad (mesh.Points(), mesh[ei], 0);
+
+  if (goal == OPT_QUALITY)
+    {
+      totalbad = CalcTotalBad (mesh.Points(), mesh.VolumeElements());
+      (*testout) << "Total badness = " << totalbad << endl;
+
+      int cntill = 0;
+      for (ElementIndex ei = 0; ei < ne; ei++)
+	if (!mesh.LegalTet (mesh[ei]))
+	  cntill++;
+
+      PrintMessage (5, cntill, " illegal tets");
+    }
+  multithread.task = savetask;
+} 
+
+
+
+
+
+/*
+  Mesh improvement by edge splitting.
+  If mesh quality is improved by inserting a node into an inner edge,
+  the edge is split into two parts.
+*/
+void MeshOptimize3d :: SplitImprove (Mesh & mesh,
+				     OPTIMIZEGOAL goal)
+{
+  int j, k, l;
+  Point3d p1, p2, pnew;
+
+  ElementIndex ei;
+  SurfaceElementIndex sei;
+  PointIndex pi1, pi2;
+
+  double bad1, bad2, badmax, badlimit;
+
+
+  int cnt = 0;
+  int np = mesh.GetNP();
+  int ne = mesh.GetNE();
+
+  TABLE<ElementIndex,PointIndex::BASE> elementsonnode(np); 
+  ARRAY<ElementIndex> hasbothpoints;
+
+  BitArray origpoint(np), boundp(np);
+  origpoint.Set();
+
+  ARRAY<double> elerrs(ne);
+  BitArray illegaltet(ne);
+  illegaltet.Clear();
+
+  const char * savetask = multithread.task;
+  multithread.task = "Split Improve";
+
+
+  PrintMessage (3, "SplitImprove");
+  (*testout)  << "start SplitImprove" << "\n";
+
+  ARRAY<INDEX_3> locfaces;
+
+  INDEX_2_HASHTABLE<int> edgetested (np);
+
+  bad1 = 0;
+  badmax = 0;
+  for (ei = 0; ei < ne; ei++)
+    {
+      elerrs[ei] = CalcBad (mesh.Points(), mesh[ei], 0);
+      bad1 += elerrs[ei];
+      if (elerrs[ei] > badmax) badmax = elerrs[ei];
+    }
+
+  PrintMessage (5, "badmax = ", badmax);
+  badlimit = 0.5 * badmax;
+
+
+  boundp.Clear();
+  for (sei = 0; sei < mesh.GetNSE(); sei++)
+    for (j = 0; j < 3; j++)
+      boundp.Set (mesh[sei][j]);
+
+  if (goal == OPT_QUALITY)
+    {
+      bad1 = CalcTotalBad (mesh.Points(), mesh.VolumeElements());
+      (*testout) << "Total badness = " << bad1 << endl;
+    }
+
+  for (ei = 0; ei < ne; ei++)
+    for (j = 0; j < mesh[ei].GetNP(); j++)
+      elementsonnode.Add (mesh[ei][j], ei);
+
+
+  mesh.MarkIllegalElements();
+  if (goal == OPT_QUALITY || goal == OPT_LEGAL)
+    {
+      int cntill = 0;
+      for (ei = 0; ei < ne; ei++)
+	{
+	  //	  if (!LegalTet (volelements.Get(i)))
+	  if (mesh[ei].flags.illegal)
+	    {
+	      cntill++;
+	      illegaltet.Set (ei+1);
+	    }
+	}
+      //      (*mycout) << cntill << " illegal tets" << endl;
+    }
+
+
+  for (ei = 0; ei < ne; ei++)
+    {
+      if (multithread.terminate)
+	break;
+
+      multithread.percent = 100.0 * (ei+1) / ne;
+
+      bool ltestmode = 0;
+
+
+      if (elerrs[ei] < badlimit && !illegaltet.Test(ei+1)) continue;
+
+      if ((goal == OPT_LEGAL) &&
+	  !illegaltet.Test(ei+1) &&
+	  CalcBad (mesh.Points(), mesh[ei], 0) < 1e3) 
+	continue;
+
+      
+      Element & elem = mesh[ei];
+
+      if (ltestmode)
+	{
+	  (*testout) << "test el " << ei << endl;
+	  for (j = 0; j < 4; j++)
+	    (*testout) << elem[j] << " ";
+	  (*testout) << endl;
+	}
+
+
+      for (j = 0; j < 6; j++)
+	{
+
+	  static const int tetedges[6][2] =
+	    { { 0, 1 }, { 0, 2 }, { 0, 3 },
+	      { 1, 2 }, { 1, 3 }, { 2, 3 } };
+
+	  pi1 = elem[tetedges[j][0]];
+	  pi2 = elem[tetedges[j][1]];
+
+	  if (pi2 < pi1) Swap (pi1, pi2);
+	  if (pi2 > elementsonnode.Size()) continue;
+
+	  if (!origpoint.Test(pi1) || !origpoint.Test(pi2))
+	    continue;
+
+  
+	  INDEX_2 i2(pi1, pi2);
+	  i2.Sort();
+
+	  if (mesh.BoundaryEdge (pi1, pi2)) continue;
+
+	  if (edgetested.Used (i2) && !illegaltet.Test(ei+1)) continue;
+	  edgetested.Set (i2, 1);
+
+	  hasbothpoints.SetSize (0);
+	  for (k = 1; k <= elementsonnode.EntrySize(pi1); k++)
+	    {
+	      bool has1 = 0, has2 = 0;
+
+	      ElementIndex elnr = elementsonnode.Get(pi1, k);
+	      Element & el = mesh[elnr];
+
+	      for (l = 0; l < el.GetNP(); l++)
+		{
+		  if (el[l] == pi1) has1 = 1;
+		  if (el[l] == pi2) has2 = 1;
+		}
+	      if (has1 && has2) 
+		{ // only once
+		  for (l = 0; l < hasbothpoints.Size(); l++)
+		    if (hasbothpoints[l] == elnr)
+		      has1 = 0;
+		  
+		  if (has1)
+		    hasbothpoints.Append (elnr);
+		}
+	    }
+	  
+	  bad1 = 0;
+	  for (k = 0; k < hasbothpoints.Size(); k++)
+	    bad1 += CalcBad (mesh.Points(), mesh[hasbothpoints[k]], 0);
+	  
+
+	  bool puretet = 1;
+	  for (k = 0; k < hasbothpoints.Size(); k++)
+	    if (mesh[hasbothpoints[k]].GetType() != TET)
+	      puretet = 0;
+	  if (!puretet) continue;
+
+	  p1 = mesh[pi1];
+	  p2 = mesh[pi2];
+
+	  /*
+	    pnew = Center (p1, p2);
+	  
+	    points.Elem(pi1) = pnew;
+	    bad2 = 0;
+	    for (k = 1; k <= hasbothpoints.Size(); k++)
+	    bad2 += CalcBad (points, 
+	    volelements.Get(hasbothpoints.Get(k)), 0);
+
+	    points.Elem(pi1) = p1;
+	    points.Elem(pi2) = pnew;
+	      
+	    for (k = 1; k <= hasbothpoints.Size(); k++)
+	    bad2 += CalcBad (points, 
+	    volelements.Get(hasbothpoints.Get(k)), 0);
+	    points.Elem(pi2) = p2;
+	  */
+
+
+	  locfaces.SetSize (0);
+	  for (k = 0; k < hasbothpoints.Size(); k++)
+	    {
+	      const Element & el = mesh[hasbothpoints[k]];
+
+	      for (l = 0; l < 4; l++)
+		if (el[l] == pi1 || el[l] == pi2)
+		  {
+		    INDEX_3 i3;
+		    Element2d face;
+		    el.GetFace (l+1, face);
+		    for (int kk = 1; kk <= 3; kk++)
+		      i3.I(kk) = face.PNum(kk);
+		    locfaces.Append (i3);
+		  }
+	    }
+
+	  PointFunction1 pf (mesh.Points(), locfaces, -1);
+	  OptiParameters par;
+	  par.maxit_linsearch = 50;
+	  par.maxit_bfgs = 20;
+
+	  pnew = Center (p1, p2);
+	  Vector px(3);
+	  px.Elem(1) = pnew.X();
+	  px.Elem(2) = pnew.Y();
+	  px.Elem(3) = pnew.Z();
+
+	  if (elerrs[ei] > 0.1 * badmax)
+	    BFGS (px, pf, par);
+
+	  bad2 = pf.Func (px);
+
+	  pnew.X() = px.Get(1);
+	  pnew.Y() = px.Get(2);
+	  pnew.Z() = px.Get(3);
+
+
+	  int hpinew = mesh.AddPoint (pnew);
+	  //	  ptyps.Append (INNERPOINT);
+
+	  for (k = 0; k < hasbothpoints.Size(); k++)
+	    {
+	      Element & oldel = mesh[hasbothpoints[k]];
+	      Element newel1 = oldel;
+	      Element newel2 = oldel;
+
+	      oldel.flags.illegal_valid = 0;
+	      newel1.flags.illegal_valid = 0;
+	      newel2.flags.illegal_valid = 0;
+	      
+	      for (l = 0; l < 4; l++)
+		{
+		  if (newel1[l] == pi2) newel1[l] = hpinew;
+		  if (newel2[l] == pi1) newel2[l] = hpinew;
+		}
+	      
+	      if (!mesh.LegalTet (oldel)) bad1 += 1e6;
+	      if (!mesh.LegalTet (newel1)) bad2 += 1e6;
+	      if (!mesh.LegalTet (newel2)) bad2 += 1e6;
+	    }	  
+	  
+	  // mesh.PointTypes().DeleteLast();
+	  mesh.Points().DeleteLast();
+
+	  if (bad2 < bad1) 
+	    /*	      (bad1 > 1e4 && boundp.Test(pi1) && boundp.Test(pi2)) */ 
+	    {
+	      cnt++;
+
+	      PointIndex pinew = mesh.AddPoint (pnew);
+	      
+	      for (k = 0; k < hasbothpoints.Size(); k++)
+		{
+		  Element & oldel = mesh[hasbothpoints[k]];
+		  Element newel = oldel;
+
+		  newel.flags.illegal_valid = 0;
+		  oldel.flags.illegal_valid = 0;
+
+		  for (l = 0; l < 4; l++)
+		    {
+		      origpoint.Clear (oldel[l]);
+
+		      if (oldel[l] == pi2) oldel[l] = pinew;
+		      if (newel[l] == pi1) newel[l] = pinew;
+		    }
+		  mesh.AddVolumeElement (newel);
+		}
+	      
+	      j = 10;
+	    }
+	}
+    }
+
+
+  mesh.Compress();
+  PrintMessage (5, cnt, " splits performed");
+
+  (*testout) << "Splitt - Improve done" << "\n";
+
+  if (goal == OPT_QUALITY)
+    {
+      bad1 = CalcTotalBad (mesh.Points(), mesh.VolumeElements());
+      (*testout) << "Total badness = " << bad1 << endl;
+
+      int cntill = 0;
+      ne = mesh.GetNE();
+      for (ei = 0; ei < ne; ei++)
+	{
+	  if (!mesh.LegalTet (mesh[ei]))
+	    cntill++;
+	}
+      //      cout << cntill << " illegal tets" << endl;
+    }
+
+  multithread.task = savetask;
+}
+
+
+      
+  
+
+void MeshOptimize3d :: SwapImprove (Mesh & mesh, OPTIMIZEGOAL goal,
+				    const BitArray * working_elements)
+{
+  int j, k, l;
+
+  ElementIndex ei;
+  SurfaceElementIndex sei;
+
+  PointIndex pi1(0), pi2(0), pi3(0), pi4(0), pi5(0), pi6(0);
+  int cnt = 0;
+
+  Element el21(TET), el22(TET), el31(TET), el32(TET), el33(TET);
+  Element el1(TET), el2(TET), el3(TET), el4(TET);
+  Element el1b(TET), el2b(TET), el3b(TET), el4b(TET);
+  
+  double bad1, bad2, bad3;
+
+  int np = mesh.GetNP();
+  int ne = mesh.GetNE();
+  //int nse = mesh.GetNSE();
+  
+  // contains at least all elements at node
+  TABLE<ElementIndex,PointIndex::BASE> elementsonnode(np);
+
+  ARRAY<ElementIndex> hasbothpoints;
+
+  PrintMessage (3, "SwapImprove ");
+  (*testout) << "\n" << "Start SwapImprove" << endl;
+
+  const char * savetask = multithread.task;
+  multithread.task = "Swap Improve";
+  
+  //  mesh.CalcSurfacesOfNode ();
+  /*
+    for (i = 1; i <= GetNE(); i++)
+    if (volelements.Get(i).PNum(1))
+    if (!LegalTet (volelements.Get(i)))
+    {
+    cout << "detected illegal tet, 1" << endl;
+    (*testout) << "detected illegal tet1: " << i << endl;
+    }
+  */	
+  
+    
+  INDEX_3_HASHTABLE<int> faces(mesh.GetNOpenElements()/3 + 2);
+  if (goal == OPT_CONFORM)
+    {
+      for (int i = 1; i <= mesh.GetNOpenElements(); i++)
+	{
+	  const Element2d & hel = mesh.OpenElement(i);
+	  INDEX_3 face(hel[0], hel[1], hel[2]);
+	  face.Sort();
+	  faces.Set (face, 1);
+	}
+    }
+  
+  // Calculate total badness
+  if (goal == OPT_QUALITY)
+    {
+      bad1 = CalcTotalBad (mesh.Points(), mesh.VolumeElements());
+      (*testout) << "Total badness = " << bad1 << endl;
+    }
+  
+  // find elements on node
+  for (ei = 0; ei < ne; ei++)
+    for (j = 0; j < mesh[ei].GetNP(); j++)
+      elementsonnode.Add (mesh[ei][j], ei);
+
+  /*
+    BitArray illegaltet(GetNE());
+    MarkIllegalElements();
+    if (goal == OPT_QUALITY || goal == OPT_LEGAL)
+    {
+    int cntill = 0;
+    for (i = 1; i <= GetNE(); i++)
+    {
+    //	  if (!LegalTet (volelements.Get(i)))
+    if (VolumeElement(i).flags.illegal)
+    {
+    cntill++;
+    illegaltet.Set (i);
+    }
+    }
+    //      (*mycout) << cntill << " illegal tets" << endl;
+    }
+  */
+
+  INDEX_2_HASHTABLE<int> edgeused(2 * ne + 5);
+
+  for (ei = 0; ei < ne; ei++)
+    {
+      if (multithread.terminate)
+	break;
+      
+      multithread.percent = 100.0 * (ei+1) / ne;
+
+      if ((mesh.ElementType(ei)) == FIXEDELEMENT)
+	continue;
+
+      if(working_elements && 
+	 ei < working_elements->Size() &&
+	 !working_elements->Test(ei))
+	continue;
+
+      if (mesh[ei].IsDeleted())
+	continue;
+
+      if ((goal == OPT_LEGAL) && 
+	  mesh.LegalTet (mesh[ei]) &&
+	  CalcBad (mesh.Points(), mesh[ei], 0) < 1e3)
+	continue;
+
+      //      int onlybedges = 1;
+
+      for (j = 0; j < 6; j++)
+	{
+	  // loop over edges
+
+	  const Element & elemi = mesh[ei];
+	  if (elemi.IsDeleted()) continue;
+
+
+	  //	  (*testout) << "check element " << elemi << endl;
+
+	  int mattyp = elemi.GetIndex();
+	  
+	  static const int tetedges[6][2] =
+	    { { 0, 1 }, { 0, 2 }, { 0, 3 },
+	      { 1, 2 }, { 1, 3 }, { 2, 3 } };
+
+	  pi1 = elemi[tetedges[j][0]];
+	  pi2 = elemi[tetedges[j][1]];
+	  
+
+	  if (pi2 < pi1) Swap (pi1, pi2);
+	 	  
+	  if (mesh.BoundaryEdge (pi1, pi2)) continue;
+
+
+	  INDEX_2 i2 (pi1, pi2);
+	  i2.Sort();
+	  if (edgeused.Used(i2)) continue;
+	  edgeused.Set (i2, 1);
+	  
+	  hasbothpoints.SetSize (0);
+	  for (k = 0; k < elementsonnode[pi1].Size(); k++)
+	    {
+	      bool has1 = 0, has2 = 0;
+	      ElementIndex elnr = elementsonnode[pi1][k];
+	      const Element & elem = mesh[elnr];
+	      
+	      if (elem.IsDeleted()) continue;
+	      
+	      for (l = 0; l < elem.GetNP(); l++)
+		{
+		  if (elem[l] == pi1) has1 = 1;
+		  if (elem[l] == pi2) has2 = 1;
+		}
+
+	      if (has1 && has2) 
+		{ // only once
+		  for (l = 0; l < hasbothpoints.Size(); l++)
+		    if (hasbothpoints[l] == elnr)
+		      has1 = 0;
+		  
+		  if (has1)
+		    hasbothpoints.Append (elnr);
+		}
+	    }
+	  
+	  bool puretet = 1;
+	  for (k = 0; k < hasbothpoints.Size(); k++)
+	    if (mesh[hasbothpoints[k]].GetType () != TET)
+	      puretet = 0;
+	  if (!puretet)
+	    continue;
+
+	  int nsuround = hasbothpoints.Size();
+
+	  if ( nsuround == 3 )
+	    {
+	      Element & elem = mesh[hasbothpoints[0]];
+	      for (l = 0; l < 4; l++)
+		if (elem[l] != pi1 && elem[l] != pi2)
+		  {
+		    pi4 = pi3;
+		    pi3 = elem[l];
+		  }
+	      
+	      el31[0] = pi1;
+	      el31[1] = pi2;
+	      el31[2] = pi3;
+	      el31[3] = pi4;
+	      el31.SetIndex (mattyp);
+	      
+	      if (WrongOrientation (mesh.Points(), el31))
+		{
+		  Swap (pi3, pi4);
+		  el31[2] = pi3;
+		  el31[3] = pi4;
+		}
+	      
+	      pi5 = 0;
+	      for (k = 1; k < 3; k++)
+		{
+		  const Element & elemk = mesh[hasbothpoints[k]];
+		  bool has1 = 0;
+		  for (l = 0; l < 4; l++)
+		    if (elemk[l] == pi4)
+		      has1 = 1;
+		  if (has1)
+		    {
+		      for (l = 0; l < 4; l++)
+			if (elemk[l] != pi1 && elemk[l] != pi2 && elemk[l] != pi4)
+			  pi5 = elemk[l];
+		    }
+		}
+
+	      if(pi5 == 0)
+                throw NgException("Illegal state observed in SwapImprove");
+
+
+	      
+	      el32[0] = pi1;  
+	      el32[1] = pi2;  
+	      el32[2] = pi4;  
+	      el32[3] = pi5;  
+	      el32.SetIndex (mattyp);
+	      
+	      el33[0] = pi1;  
+	      el33[1] = pi2;  
+	      el33[2] = pi5;  
+	      el33[3] = pi3;  
+	      el33.SetIndex (mattyp);
+	      
+	      elementsonnode.Add (pi4, hasbothpoints[1]);
+	      elementsonnode.Add (pi3, hasbothpoints[2]);
+	      
+	      bad1 = CalcBad (mesh.Points(), el31, 0) + 
+		CalcBad (mesh.Points(), el32, 0) +
+		CalcBad (mesh.Points(), el33, 0);
+
+	      el31.flags.illegal_valid = 0;
+	      el32.flags.illegal_valid = 0;
+	      el33.flags.illegal_valid = 0;
+
+	      if (!mesh.LegalTet(el31) ||
+		  !mesh.LegalTet(el32) ||
+		  !mesh.LegalTet(el33))
+		bad1 += 1e4;
+	      
+	      el21[0] = pi3;
+	      el21[1] = pi4;
+	      el21[2] = pi5;
+	      el21[3] = pi2;
+	      el21.SetIndex (mattyp);
+	      
+	      el22[0] = pi5;
+	      el22[1] = pi4;
+	      el22[2] = pi3;
+	      el22[3] = pi1;
+	      el22.SetIndex (mattyp);	      
+
+	      bad2 = CalcBad (mesh.Points(), el21, 0) + 
+		CalcBad (mesh.Points(), el22, 0);
+
+	      el21.flags.illegal_valid = 0;
+	      el22.flags.illegal_valid = 0;
+
+	      if (!mesh.LegalTet(el21) ||
+		  !mesh.LegalTet(el22))
+		bad2 += 1e4;
+
+
+	      if (goal == OPT_CONFORM && bad2 < 1e4)
+		{
+		  INDEX_3 face(pi3, pi4, pi5);
+		  face.Sort();
+		  if (faces.Used(face))
+		    {
+		      // (*testout) << "3->2 swap, could improve conformity, bad1 = " << bad1
+		      //				 << ", bad2 = " << bad2 << endl;
+		      if (bad2 < 1e4)
+			bad1 = 2 * bad2;
+		    }
+		  /*
+		    else
+		    {
+		    INDEX_2 hi1(pi3, pi4);
+		    hi1.Sort();
+		    INDEX_2 hi2(pi3, pi5);
+		    hi2.Sort();
+		    INDEX_2 hi3(pi4, pi5);
+		    hi3.Sort();
+
+		    if (boundaryedges->Used (hi1) ||
+		    boundaryedges->Used (hi2) ||
+		    boundaryedges->Used (hi3) )
+		    bad1 = 2 * bad2;
+		    }
+		  */
+		}
+
+	      if (bad2 < bad1)
+		{
+		  //		  (*mycout) << "3->2 " << flush;
+		  //		  (*testout) << "3->2 conversion" << endl;
+		  cnt++;
+		  
+
+		  /*
+		  (*testout) << "3->2 swap, old els = " << endl
+			     << mesh[hasbothpoints[0]] << endl
+			     << mesh[hasbothpoints[1]] << endl
+			     << mesh[hasbothpoints[2]] << endl
+			     << "new els = " << endl
+			     << el21 << endl
+			     << el22 << endl;
+		  */
+                  
+		  el21.flags.illegal_valid = 0;
+		  el22.flags.illegal_valid = 0;
+		  mesh[hasbothpoints[0]] = el21;
+		  mesh[hasbothpoints[1]] = el22;
+		  for (l = 0; l < 4; l++)
+		    mesh[hasbothpoints[2]][l] = 0;
+		  mesh[hasbothpoints[2]].Delete();
+
+		  for (k = 0; k < 2; k++)
+		    for (l = 0; l < 4; l++)
+		      elementsonnode.Add (mesh[hasbothpoints[k]][l], hasbothpoints[k]);
+		}
+	    }
+	  
+
+	  if (nsuround == 4)
+	    {
+	      const Element & elem1 = mesh[hasbothpoints[0]];
+	      for (l = 0; l < 4; l++)
+		if (elem1[l] != pi1 && elem1[l] != pi2)
+		  {
+		    pi4 = pi3;
+		    pi3 = elem1[l];
+		  }
+	      
+	      el1[0] = pi1; el1[1] = pi2;
+	      el1[2] = pi3; el1[3] = pi4;
+	      el1.SetIndex (mattyp);
+
+	      if (WrongOrientation (mesh.Points(), el1))
+		{
+		  Swap (pi3, pi4);
+		  el1[2] = pi3;
+		  el1[3] = pi4;
+		}
+	      
+	      pi5 = 0;
+	      for (k = 1; k < 4; k++)
+		{
+		  const Element & elem = mesh[hasbothpoints[k]];
+		  bool has1 = 0;
+		  for (l = 0; l < 4; l++)
+		    if (elem[l] == pi4)
+		      has1 = 1;
+		  if (has1)
+		    {
+		      for (l = 0; l < 4; l++)
+			if (elem[l] != pi1 && elem[l] != pi2 && elem[l] != pi4)
+			  pi5 = elem[l];
+		    }
+		}
+	      
+	      pi6 = 0;
+	      for (k = 1; k < 4; k++)
+		{
+		  const Element & elem = mesh[hasbothpoints[k]];
+		  bool has1 = 0;
+		  for (l = 0; l < 4; l++)
+		    if (elem[l] == pi3)
+		      has1 = 1;
+		  if (has1)
+		    {
+		      for (l = 0; l < 4; l++)
+			if (elem[l] != pi1 && elem[l] != pi2 && elem[l] != pi3)
+			  pi6 = elem[l];
+		    }
+		}
+	      
+	      /*
+	      INDEX_2 i22(pi3, pi5);
+	      i22.Sort();
+	      INDEX_2 i23(pi4, pi6);
+	      i23.Sort();
+	      */
+	      
+	      el1[0] = pi1; el1[1] = pi2;  
+	      el1[2] = pi3; el1[3] = pi4; 
+	      el1.SetIndex (mattyp);
+	      
+	      el2[0] = pi1; el2[1] = pi2;  
+	      el2[2] = pi4; el2[3] = pi5;  
+	      el2.SetIndex (mattyp);
+	      
+	      el3[0] = pi1; el3[1] = pi2;  
+	      el3[2] = pi5; el3[3] = pi6;  
+	      el3.SetIndex (mattyp);
+	      
+	      el4[0] = pi1; el4[1] = pi2;  
+	      el4[2] = pi6; el4[3] = pi3;  
+	      el4.SetIndex (mattyp);
+	      
+	      //        elementsonnode.Add (pi4, hasbothpoints.Elem(2));
+	      //        elementsonnode.Add (pi3, hasbothpoints.Elem(3));
+	      
+	      bad1 = CalcBad (mesh.Points(), el1, 0) + 
+		CalcBad (mesh.Points(), el2, 0) +
+		CalcBad (mesh.Points(), el3, 0) + 
+		CalcBad (mesh.Points(), el4, 0);
+	      
+
+	      el1.flags.illegal_valid = 0;
+	      el2.flags.illegal_valid = 0;
+	      el3.flags.illegal_valid = 0;
+	      el4.flags.illegal_valid = 0;
+
+
+	      if (goal != OPT_CONFORM)
+		{
+		  if (!mesh.LegalTet(el1) ||
+		      !mesh.LegalTet(el2) ||
+		      !mesh.LegalTet(el3) ||
+		      !mesh.LegalTet(el4))
+		    bad1 += 1e4;
+		}
+	      
+	      el1[0] = pi3; el1[1] = pi5;  
+	      el1[2] = pi2; el1[3] = pi4; 
+	      el1.SetIndex (mattyp);
+	 
+	      el2[0] = pi3; el2[1] = pi5;  
+	      el2[2] = pi4; el2[3] = pi1;  
+	      el2.SetIndex (mattyp);
+	      
+	      el3[0] = pi3; el3[1] = pi5;  
+	      el3[2] = pi1; el3[3] = pi6;  
+	      el3.SetIndex (mattyp);
+	      
+	      el4[0] = pi3; el4[1] = pi5;  
+	      el4[2] = pi6; el4[3] = pi2;  	
+	      el4.SetIndex (mattyp);
+      
+	      bad2 = CalcBad (mesh.Points(), el1, 0) + 
+		CalcBad (mesh.Points(), el2, 0) +
+		CalcBad (mesh.Points(), el3, 0) + 
+		CalcBad (mesh.Points(), el4, 0);
+
+	      el1.flags.illegal_valid = 0;
+	      el2.flags.illegal_valid = 0;
+	      el3.flags.illegal_valid = 0;
+	      el4.flags.illegal_valid = 0;
+
+	      if (goal != OPT_CONFORM)
+		{
+		  if (!mesh.LegalTet(el1) ||
+		      !mesh.LegalTet(el2) ||
+		      !mesh.LegalTet(el3) ||
+		      !mesh.LegalTet(el4))
+		    bad2 += 1e4;
+		}
+
+	      
+	      el1b[0] = pi4; el1b[1] = pi6;  
+	      el1b[2] = pi3; el1b[3] = pi2; 
+	      el1b.SetIndex (mattyp);
+	      
+	      el2b[0] = pi4; el2b[1] = pi6;  
+	      el2b[2] = pi2; el2b[3] = pi5;  
+	      el2b.SetIndex (mattyp);
+	      
+	      el3b[0] = pi4; el3b[1] = pi6;  
+	      el3b[2] = pi5; el3b[3] = pi1;  
+	      el3b.SetIndex (mattyp);
+	      
+	      el4b[0] = pi4; el4b[1] = pi6;  
+	      el4b[2] = pi1; el4b[3] = pi3;  
+	      el4b.SetIndex (mattyp);
+	      
+	      bad3 = CalcBad (mesh.Points(), el1b, 0) + 
+		CalcBad (mesh.Points(), el2b, 0) +
+		CalcBad (mesh.Points(), el3b, 0) +
+		CalcBad (mesh.Points(), el4b, 0);
+	      
+	      el1b.flags.illegal_valid = 0;
+	      el2b.flags.illegal_valid = 0;
+	      el3b.flags.illegal_valid = 0;
+	      el4b.flags.illegal_valid = 0;
+
+	      if (goal != OPT_CONFORM)
+		{
+		  if (!mesh.LegalTet(el1b) ||
+		      !mesh.LegalTet(el2b) ||
+		      !mesh.LegalTet(el3b) ||
+		      !mesh.LegalTet(el4b))
+		    bad3 += 1e4;
+		}
+
+
+	      /*
+	      int swap2 = (bad2 < bad1) && (bad2 < bad3);
+	      int swap3 = !swap2 && (bad3 < bad1);
+	      
+	      if ( ((bad2 < 10 * bad1) || 
+		    (bad2 < 1e6)) && mesh.BoundaryEdge (pi3, pi5))
+		swap2 = 1;
+	      else  if ( ((bad3 < 10 * bad1) || 
+			  (bad3 < 1e6)) && mesh.BoundaryEdge (pi4, pi6))
+		{
+		  swap3 = 1;
+		  swap2 = 0;
+		}
+	      */
+	      bool swap2, swap3;
+
+	      if (goal != OPT_CONFORM)
+		{
+		  swap2 = (bad2 < bad1) && (bad2 < bad3);
+		  swap3 = !swap2 && (bad3 < bad1);
+		}
+	      else
+		{
+		  if (mesh.BoundaryEdge (pi3, pi5)) bad2 /= 1e6;
+		  if (mesh.BoundaryEdge (pi4, pi6)) bad3 /= 1e6;
+
+		  swap2 = (bad2 < bad1) && (bad2 < bad3);
+		  swap3 = !swap2 && (bad3 < bad1);
+		}
+		
+
+	      if (swap2 || swap3)
+		{
+		  // (*mycout) << "4->4 " << flush;
+		  cnt++;
+		  //		  (*testout) << "4->4 conversion" << "\n";
+		  /*
+		    (*testout) << "bad1 = " << bad1 
+		    << " bad2 = " << bad2
+		    << " bad3 = " << bad3 << "\n";
+		  
+		    (*testout) << "Points: " << pi1 << " " << pi2 << " " << pi3 
+		    << " " << pi4 << " " << pi5 << " " << pi6 << "\n";
+		    (*testout) << "Elements: " 
+		    << hasbothpoints.Get(1) << "  "
+		    << hasbothpoints.Get(2) << "  "
+		    << hasbothpoints.Get(3) << "  "
+		    << hasbothpoints.Get(4) << "  " << "\n";
+		  */
+
+		  /*
+		    {
+		    int i1, j1;
+		    for (i1 = 1; i1 <= 4; i1++)
+		    {
+		    for (j1 = 1; j1 <= 4; j1++)
+		    (*testout) << volelements.Get(hasbothpoints.Get(i1)).PNum(j1)
+		    << "  ";
+		    (*testout) << "\n";
+		    }
+		    }
+		  */
+		}
+	      
+
+	      if (swap2)
+		{
+		  //		  (*mycout) << "bad1 = " << bad1 << " bad2 = " << bad2 << "\n";
+
+
+		  /*
+		  (*testout) << "4->4 swap A, old els = " << endl
+			     << mesh[hasbothpoints[0]] << endl
+			     << mesh[hasbothpoints[1]] << endl
+			     << mesh[hasbothpoints[2]] << endl
+			     << mesh[hasbothpoints[3]] << endl
+			     << "new els = " << endl
+			     << el1 << endl
+			     << el2 << endl
+			     << el3 << endl
+			     << el4 << endl;
+		  */
+
+
+
+		  el1.flags.illegal_valid = 0;
+		  el2.flags.illegal_valid = 0;
+		  el3.flags.illegal_valid = 0;
+		  el4.flags.illegal_valid = 0;
+		  
+		  mesh[hasbothpoints[0]] = el1;
+		  mesh[hasbothpoints[1]] = el2;
+		  mesh[hasbothpoints[2]] = el3;
+		  mesh[hasbothpoints[3]] = el4;
+		  
+		  for (k = 0; k < 4; k++)
+		    for (l = 0; l < 4; l++)
+		      elementsonnode.Add (mesh[hasbothpoints[k]][l], hasbothpoints[k]);
+		}
+	      else if (swap3)
+		{
+		  // (*mycout) << "bad1 = " << bad1 << " bad3 = " << bad3 << "\n";
+		  el1b.flags.illegal_valid = 0;
+		  el2b.flags.illegal_valid = 0;
+		  el3b.flags.illegal_valid = 0;
+		  el4b.flags.illegal_valid = 0;
+
+
+		  /*
+		  (*testout) << "4->4 swap A, old els = " << endl
+			     << mesh[hasbothpoints[0]] << endl
+			     << mesh[hasbothpoints[1]] << endl
+			     << mesh[hasbothpoints[2]] << endl
+			     << mesh[hasbothpoints[3]] << endl
+			     << "new els = " << endl
+			     << el1b << endl
+			     << el2b << endl
+			     << el3b << endl
+			     << el4b << endl;
+		  */
+
+
+		  mesh[hasbothpoints[0]] = el1b;
+		  mesh[hasbothpoints[1]] = el2b;
+		  mesh[hasbothpoints[2]] = el3b;
+		  mesh[hasbothpoints[3]] = el4b;
+
+
+		  for (k = 0; k < 4; k++)
+		    for (l = 0; l < 4; l++)
+		      elementsonnode.Add (mesh[hasbothpoints[k]][l], hasbothpoints[k]);
+		}
+	    }
+
+	  if (nsuround >= 5) 
+	    {
+	      Element hel(TET);
+
+	      ArrayMem<PointIndex, 50> suroundpts(nsuround);
+	      ArrayMem<char, 50> tetused(nsuround);
+
+	      Element & elem = mesh[hasbothpoints[0]];
+
+	      for (l = 0; l < 4; l++)
+		if (elem[l] != pi1 && elem[l] != pi2)
+		  {
+		    pi4 = pi3;
+		    pi3 = elem[l];
+		  }
+
+	      hel[0] = pi1;
+	      hel[1] = pi2;
+	      hel[2] = pi3;
+	      hel[3] = pi4;
+	      hel.SetIndex (mattyp);
+	      
+	      if (WrongOrientation (mesh.Points(), hel))
+		{
+		  Swap (pi3, pi4);
+		  hel[2] = pi3;
+		  hel[3] = pi4;
+		}
+
+	      
+	      // suroundpts.SetSize (nsuround);
+	      suroundpts[0] = pi3;
+	      suroundpts[1] = pi4;
+
+	      tetused = 0;
+	      tetused[0] = 1;
+
+	      for (l = 2; l < nsuround; l++)
+		{
+		  int oldpi = suroundpts[l-1];
+		  int newpi = 0;
+
+		  for (k = 0; k < nsuround && !newpi; k++)
+		    if (!tetused[k])
+		      {
+			const Element & nel = mesh[hasbothpoints[k]];
+
+			for (int k2 = 0; k2 < 4 && !newpi; k2++)
+			  if (nel[k2] == oldpi)
+			    {
+			      newpi = 
+				nel[0] + nel[1] + nel[2] + nel[3] 
+				- pi1 - pi2 - oldpi;
+			      
+			      tetused[k] = 1; 
+			      suroundpts[l] = newpi;
+			    }			
+		      }
+		}
+
+	      
+	      bad1 = 0;
+	      for (k = 0; k < nsuround; k++)
+		{
+		  hel[0] = pi1;
+		  hel[1] = pi2;
+		  hel[2] = suroundpts[k];
+		  hel[3] = suroundpts[(k+1) % nsuround];
+		  hel.SetIndex (mattyp);
+
+		  bad1 += CalcBad (mesh.Points(), hel, 0);
+		}
+
+	      //  (*testout) << "nsuround = " << nsuround << " bad1 = " << bad1 << endl;
+
+
+	      int bestl = -1;
+	      int confface = -1;
+	      int confedge = -1;
+	      double badopt = bad1;
+
+	      for (l = 0; l < nsuround; l++)
+		{
+		  bad2 = 0;
+
+		  for (k = l+1; k <= nsuround + l - 2; k++)
+		    {
+		      hel[0] = suroundpts[l];
+		      hel[1] = suroundpts[k % nsuround];
+		      hel[2] = suroundpts[(k+1) % nsuround];
+		      hel[3] = pi2;
+
+		      bad2 += CalcBad (mesh.Points(), hel, 0);
+		      hel.flags.illegal_valid = 0;
+		      if (!mesh.LegalTet(hel)) bad2 += 1e4;
+
+		      hel[2] = suroundpts[k % nsuround];
+		      hel[1] = suroundpts[(k+1) % nsuround];
+		      hel[3] = pi1;
+
+		      bad2 += CalcBad (mesh.Points(), hel, 0);
+
+		      hel.flags.illegal_valid = 0;
+		      if (!mesh.LegalTet(hel)) bad2 += 1e4;
+		    }
+		  // (*testout) << "bad2," << l << " = " << bad2 << endl;
+		  
+		  if ( bad2 < badopt )
+		    {
+		      bestl = l;
+		      badopt = bad2;
+		    }
+		  
+		  
+		  if (goal == OPT_CONFORM)
+		       // (bad2 <= 100 * bad1 || bad2 <= 1e6))
+		    {
+		      bool nottoobad =
+			(bad2 <= bad1) ||
+			(bad2 <= 100 * bad1 && bad2 <= 1e18) ||
+			(bad2 <= 1e8);
+		      
+		      for (k = l+1; k <= nsuround + l - 2; k++)
+			{
+			  INDEX_3 hi3(suroundpts[l],
+				      suroundpts[k % nsuround],
+				      suroundpts[(k+1) % nsuround]);
+			  hi3.Sort();
+			  if (faces.Used(hi3))
+			    {
+			      // (*testout) << "could improve face conformity, bad1 = " << bad1
+			      // << ", bad 2 = " << bad2 << ", nottoobad = " << nottoobad << endl;
+			      if (nottoobad)
+				confface = l;
+			    }
+			}
+
+		      for (k = l+2; k <= nsuround+l-2; k++)
+			{
+			  if (mesh.BoundaryEdge (suroundpts[l],
+						 suroundpts[k % nsuround]))
+			    {
+			      /*
+			      *testout << "could improve edge conformity, bad1 = " << bad1
+				   << ", bad 2 = " << bad2 << ", nottoobad = " << nottoobad << endl;
+			      */
+			      if (nottoobad)
+				confedge = l;
+			    }
+			}
+		    }
+		}
+	      
+	      if (confedge != -1)
+		bestl = confedge;
+	      if (confface != -1)
+		bestl = confface;
+
+	      if (bestl != -1)
+		{
+		  // (*mycout) << nsuround << "->" << 2 * (nsuround-2) << " " << flush;
+		  cnt++;
+		  
+		  for (k = bestl+1; k <= nsuround + bestl - 2; k++)
+		    {
+		      int k1;
+
+		      hel[0] = suroundpts[bestl];
+		      hel[1] = suroundpts[k % nsuround];
+		      hel[2] = suroundpts[(k+1) % nsuround];
+		      hel[3] = pi2;
+		      hel.flags.illegal_valid = 0;
+
+		      /*
+		      (*testout) << nsuround << "-swap, new el,top = "
+				 << hel << endl;
+		      */
+		      mesh.AddVolumeElement (hel);
+
+		      for (k1 = 0; k1 < 4; k1++)
+			elementsonnode.Add (hel[k1], mesh.GetNE()-1);
+		      
+
+		      hel[2] = suroundpts[k % nsuround];
+		      hel[1] = suroundpts[(k+1) % nsuround];
+		      hel[3] = pi1;
+
+		      /*
+		      (*testout) << nsuround << "-swap, new el,bot = "
+				 << hel << endl;
+		      */
+
+		      mesh.AddVolumeElement (hel);
+
+		      for (k1 = 0; k1 < 4; k1++)
+			elementsonnode.Add (hel[k1], mesh.GetNE()-1);
+		    }		  
+		  
+		  for (k = 0; k < nsuround; k++)
+		    {
+		      Element & rel = mesh[hasbothpoints[k]];
+		      /*
+		      (*testout) << nsuround << "-swap, old el = "
+				 << rel << endl;
+		      */
+		      rel.Delete();
+		      for (int k1 = 0; k1 < 4; k1++)
+			rel[k1] = 0;
+
+		    }
+		}
+	    }
+	}
+
+      /*
+	if (onlybedges)
+	{
+	(*testout) << "bad tet: " 
+	<< volelements.Get(i)[0] 
+	<< volelements.Get(i)[1] 
+	<< volelements.Get(i)[2] 
+	<< volelements.Get(i)[3] << "\n";
+
+	if (!mesh.LegalTet (volelements.Get(i)))
+	cerr << "Illegal tet" << "\n";
+	}
+      */
+    }
+  //  (*mycout) << endl;
+
+  /*  
+      cout << "edgeused: ";
+      edgeused.PrintMemInfo(cout);
+  */
+  PrintMessage (5, cnt, " swaps performed");
+
+
+
+
+
+  mesh.Compress ();
+
+  /*
+  if (goal == OPT_QUALITY)
+    {
+      bad1 = CalcTotalBad (mesh.Points(), mesh.VolumeElements());
+      //      (*testout) << "Total badness = " << bad1 << endl;
+    }
+  */
+
+  /*
+    for (i = 1; i <= GetNE(); i++)
+    if (volelements.Get(i)[0])
+    if (!mesh.LegalTet (volelements.Get(i)))
+    {
+    cout << "detected illegal tet, 2" << endl;
+    (*testout) << "detected illegal tet1: " << i << endl;
+    }
+  */
+
+  multithread.task = savetask;
+}
+  
+
+
+
+
+
+void MeshOptimize3d :: SwapImproveSurface (Mesh & mesh, OPTIMIZEGOAL goal,
+					   const BitArray * working_elements,
+					   const ARRAY< ARRAY<int,PointIndex::BASE>* > * idmaps)
+{
+  ARRAY< ARRAY<int,PointIndex::BASE>* > locidmaps;
+  const ARRAY< ARRAY<int,PointIndex::BASE>* > * used_idmaps;
+
+  if(idmaps)
+    used_idmaps = idmaps;
+  else
+    {
+      used_idmaps = &locidmaps;
+      
+      for(int i=1; i<=mesh.GetIdentifications().GetMaxNr(); i++)
+	{
+	  if(mesh.GetIdentifications().GetType(i) == Identifications::PERIODIC)
+	    {
+	      locidmaps.Append(new ARRAY<int,PointIndex::BASE>);
+	      mesh.GetIdentifications().GetMap(i,*locidmaps.Last(),true);
+	    }
+	}
+    }
+
+  ElementIndex ei;
+  SurfaceElementIndex sei;
+
+  PointIndex pi1, pi2, pi3, pi4, pi5, pi6;
+  PointIndex pi1other, pi2other;
+  int cnt = 0;
+
+  //double bad1, bad2, bad3, sbad;
+  double bad1, sbad;
+  double h;
+
+  int np = mesh.GetNP();
+  int ne = mesh.GetNE();
+  int nse = mesh.GetNSE();
+
+  int mattype, othermattype;
+
+  
+  // contains at least all elements at node
+  TABLE<ElementIndex,PointIndex::BASE> elementsonnode(np);
+  TABLE<SurfaceElementIndex,PointIndex::BASE> surfaceelementsonnode(np);
+  TABLE<int,PointIndex::BASE> surfaceindicesonnode(np);
+
+  ARRAY<ElementIndex> hasbothpoints;
+  ARRAY<ElementIndex> hasbothpointsother;
+
+  PrintMessage (3, "SwapImproveSurface ");
+  (*testout) << "\n" << "Start SwapImproveSurface" << endl;
+
+  const char * savetask = multithread.task;
+  multithread.task = "Swap Improve Surface";
+    
+      
+  
+  // find elements on node
+  for (ei = 0; ei < ne; ei++)
+    for (int j = 0; j < mesh[ei].GetNP(); j++)
+      elementsonnode.Add (mesh[ei][j], ei);
+
+  for (sei = 0; sei < nse; sei++)
+    for(int j=0; j<mesh[sei].GetNP(); j++)
+      {
+	surfaceelementsonnode.Add(mesh[sei][j], sei);
+	if(!surfaceindicesonnode[mesh[sei][j]].Contains(mesh[sei].GetIndex()))
+	  surfaceindicesonnode.Add(mesh[sei][j],mesh[sei].GetIndex());
+      }
+
+  bool periodic;
+  int idnum(-1);
+
+  INDEX_2_HASHTABLE<int> edgeused(2 * ne + 5);
+
+  for (ei = 0; ei < ne; ei++)
+    {
+      if (multithread.terminate)
+	break;
+      
+      multithread.percent = 100.0 * (ei+1) / ne;
+
+      if (mesh.ElementType(ei) == FIXEDELEMENT)
+	continue;
+      
+      if(working_elements && 
+	 ei < working_elements->Size() &&
+	 !working_elements->Test(ei))
+	continue;
+
+      if (mesh[ei].IsDeleted())
+	continue;
+
+      if ((goal == OPT_LEGAL) && 
+	  mesh.LegalTet (mesh[ei]) &&
+	  CalcBad (mesh.Points(), mesh[ei], 0) < 1e3)
+	continue;
+
+      const Element & elemi = mesh[ei];
+      //Element elemi = mesh[ei];
+      if (elemi.IsDeleted()) continue;
+
+
+      mattype = elemi.GetIndex();
+
+      bool swapped = false;
+
+      for (int j = 0; !swapped && j < 6; j++)
+	{
+	  // loop over edges
+
+	  
+	  static const int tetedges[6][2] =
+	    { { 0, 1 }, { 0, 2 }, { 0, 3 },
+	      { 1, 2 }, { 1, 3 }, { 2, 3 } };
+
+	  pi1 = elemi[tetedges[j][0]];
+	  pi2 = elemi[tetedges[j][1]];
+
+	  
+	  if (pi2 < pi1)
+	    Swap (pi1, pi2);
+	    	  
+	  
+	  bool found = false;
+	  for(int k=0; !found && k<used_idmaps->Size(); k++)
+	    {
+	      if(pi2 < (*used_idmaps)[k]->Size() + PointIndex::BASE)
+		{
+		  pi1other = (*(*used_idmaps)[k])[pi1];
+		  pi2other = (*(*used_idmaps)[k])[pi2];
+		  found = (pi1other != 0 && pi2other != 0 && pi1other != pi1 && pi2other != pi2);
+		  if(found)
+		    idnum = k;
+		}
+	    }
+	  if(found)
+	    periodic = true;
+	  else
+	    {
+	      periodic = false;
+	      pi1other = pi1; pi2other = pi2;
+	    }
+
+
+	 	  
+	  if (!mesh.BoundaryEdge (pi1, pi2) ||
+	      mesh.IsSegment(pi1, pi2)) continue;
+
+	  othermattype = -1;
+
+	  
+	  INDEX_2 i2 (pi1, pi2);
+	  i2.Sort();
+	  if (edgeused.Used(i2)) continue;
+	  edgeused.Set (i2, 1);
+	  if(periodic)
+	    {
+	      i2.I1() = pi1other;
+	      i2.I2() = pi2other;
+	      i2.Sort();
+	      edgeused.Set(i2,1);
+	    }
+	  
+	  
+	  hasbothpoints.SetSize (0);
+	  hasbothpointsother.SetSize (0);
+	  for (int k = 0; k < elementsonnode[pi1].Size(); k++)
+	    {
+	      bool has1 = false, has2 = false;
+	      ElementIndex elnr = elementsonnode[pi1][k];
+	      const Element & elem = mesh[elnr];
+	      
+	      if (elem.IsDeleted()) continue;
+	      
+	      for (int l = 0; l < elem.GetNP(); l++)
+		{
+		  if (elem[l] == pi1) has1 = true;
+		  if (elem[l] == pi2) has2 = true;
+		}
+
+	      if (has1 && has2) 
+		{ 
+		  if(othermattype == -1 && elem.GetIndex() != mattype)
+		    othermattype = elem.GetIndex();
+
+		  if(elem.GetIndex() == mattype)
+		    {
+		      // only once
+		      for (int l = 0; l < hasbothpoints.Size(); l++)
+			if (hasbothpoints[l] == elnr)
+			  has1 = 0;
+		      
+		      if (has1)
+			hasbothpoints.Append (elnr);
+		    }
+		  else if(elem.GetIndex() == othermattype)
+		    {
+		      // only once
+		      for (int l = 0; l < hasbothpointsother.Size(); l++)
+			if (hasbothpointsother[l] == elnr)
+			  has1 = 0;
+		      
+		      if (has1)
+			hasbothpointsother.Append (elnr);
+		    }
+		  else
+		    {
+		      cout << "problem with domain indices" << endl;
+		      (*testout) << "problem: mattype = " << mattype << ", othermattype = " << othermattype 
+				 << " elem " << elem << " mt " << elem.GetIndex() << endl
+				 << " pi1 " << pi1 << " pi2 " << pi2 << endl;
+		      (*testout) << "hasbothpoints:" << endl;
+		      for(int ii=0; ii < hasbothpoints.Size(); ii++)
+			(*testout) << mesh[hasbothpoints[ii]] << endl;
+		      (*testout) << "hasbothpointsother:" << endl;
+		      for(int ii=0; ii < hasbothpointsother.Size(); ii++)
+			(*testout) << mesh[hasbothpointsother[ii]] << endl;
+		    }
+		}
+	    }
+
+	  if(hasbothpointsother.Size() > 0 && periodic)
+	    throw NgException("SwapImproveSurface: Assumption about interface/periodicity wrong!");
+
+	  if(periodic)
+	    {
+	      for (int k = 0; k < elementsonnode[pi1other].Size(); k++)
+		{
+		  bool has1 = false, has2 = false;
+		  ElementIndex elnr = elementsonnode[pi1other][k];
+		  const Element & elem = mesh[elnr];
+	      
+		  if (elem.IsDeleted()) continue;
+	      
+		  for (int l = 0; l < elem.GetNP(); l++)
+		    {
+		      if (elem[l] == pi1other) has1 = true;
+		      if (elem[l] == pi2other) has2 = true;
+		    }
+		  
+		  if (has1 && has2) 
+		    { 
+		      if(othermattype == -1)
+			othermattype = elem.GetIndex();
+
+		      // only once
+		      for (int l = 0; l < hasbothpointsother.Size(); l++)
+			if (hasbothpointsother[l] == elnr)
+			  has1 = 0;
+		      
+		      if (has1)
+			hasbothpointsother.Append (elnr);
+		    }
+		}
+	    }
+
+
+	  //for(k=0; k<hasbothpoints.Size(); k++)
+	  //  (*testout) << "hasbothpoints["<<k<<"]: " << mesh[hasbothpoints[k]] << endl;
+
+	  
+	  SurfaceElementIndex sel1=-1,sel2=-1;
+	  SurfaceElementIndex sel1other=-1,sel2other=-1;
+	  for(int k = 0; k < surfaceelementsonnode[pi1].Size(); k++)
+	    {
+	      bool has1 = false, has2 = false;
+	      SurfaceElementIndex elnr = surfaceelementsonnode[pi1][k];
+	      const Element2d & elem = mesh[elnr];
+
+	      if (elem.IsDeleted()) continue;
+
+	      for (int l = 0; l < elem.GetNP(); l++)
+		{
+		  if (elem[l] == pi1) has1 = true;
+		  if (elem[l] == pi2) has2 = true;
+		}
+
+	      if(has1 && has2 && elnr != sel2)
+		{
+		  sel1 = sel2;
+		  sel2 = elnr;
+		}
+	    }
+
+	  if(periodic)
+	    {
+	      for(int k = 0; k < surfaceelementsonnode[pi1other].Size(); k++)
+		{
+		  bool has1 = false, has2 = false;
+		  SurfaceElementIndex elnr = surfaceelementsonnode[pi1other][k];
+		  const Element2d & elem = mesh[elnr];
+
+		  if (elem.IsDeleted()) continue;
+
+		  for (int l = 0; l < elem.GetNP(); l++)
+		    {
+		      if (elem[l] == pi1other) has1 = true;
+		      if (elem[l] == pi2other) has2 = true;
+		    }
+
+		  if(has1 && has2 && elnr != sel2other)
+		    {
+		      sel1other = sel2other;
+		      sel2other = elnr;
+		    }
+		}
+	    }
+	  else
+	    {
+	      sel1other = sel1; sel2other = sel2;
+	    }
+
+	  //(*testout) << "sel1 " << sel1 << " sel2 " << sel2 << " el " << mesh[sel1] << " resp. " << mesh[sel2] << endl;
+
+	  PointIndex sp1(0), sp2(0);
+	  PointIndex sp1other, sp2other;
+	  for(int l=0; l<mesh[sel1].GetNP(); l++)
+	    if(mesh[sel1][l] != pi1 && mesh[sel1][l] != pi2)
+	      sp1 = mesh[sel1][l];
+	  for(int l=0; l<mesh[sel2].GetNP(); l++)
+	    if(mesh[sel2][l] != pi1 && mesh[sel2][l] != pi2)
+	      sp2 = mesh[sel2][l];
+
+	  if(periodic)
+	    {
+	      sp1other = (*(*used_idmaps)[idnum])[sp1];
+	      sp2other = (*(*used_idmaps)[idnum])[sp2];
+
+	      bool change = false;
+	      for(int l=0; !change && l<mesh[sel1other].GetNP(); l++)
+		change = (sp2other == mesh[sel1other][l]);
+	      
+	      if(change)
+		{
+		  SurfaceElementIndex aux = sel1other;
+		  sel1other = sel2other;
+		  sel2other = aux;
+		}
+
+	    }
+	  else
+	    {
+	      sp1other = sp1; sp2other = sp2;
+	    }
+	  
+	  Vec<3> v1 = mesh[sp1]-mesh[pi1],
+	    v2 = mesh[sp2]-mesh[pi1],
+	    v3 = mesh[sp1]-mesh[pi2],
+	    v4 = mesh[sp2]-mesh[pi2];
+	  double vol = 0.5*(Cross(v1,v2).Length() + Cross(v3,v4).Length());
+	  h = sqrt(vol);
+	  h = 0;
+
+	  sbad = CalcTriangleBadness (mesh[pi1],mesh[pi2],mesh[sp1],0,0) + 
+	    CalcTriangleBadness (mesh[pi2],mesh[pi1],mesh[sp2],0,0);
+	  
+
+
+	  bool puretet = true;
+	  for (int k = 0; puretet && k < hasbothpoints.Size(); k++)
+	    if (mesh[hasbothpoints[k]].GetType () != TET)
+	      puretet = false;
+	  for (int k = 0; puretet && k < hasbothpointsother.Size(); k++)
+	    if (mesh[hasbothpointsother[k]].GetType () != TET)
+	      puretet = false;
+	  if (!puretet)
+	    continue;
+
+	  int nsuround = hasbothpoints.Size();
+	  int nsuroundother = hasbothpointsother.Size();
+
+	  ARRAY < int > outerpoints(nsuround+1);
+	  outerpoints[0] = sp1;
+
+	  for(int i=0; i<nsuround; i++)
+	    {
+	      bool done = false;
+	      for(int jj=i; !done && jj<hasbothpoints.Size(); jj++)
+		{
+		  for(int k=0; !done && k<4; k++)
+		    if(mesh[hasbothpoints[jj]][k] == outerpoints[i])
+		      {
+			done = true;
+			for(int l=0; l<4; l++)
+			  if(mesh[hasbothpoints[jj]][l] != pi1 &&
+			     mesh[hasbothpoints[jj]][l] != pi2 &&
+			     mesh[hasbothpoints[jj]][l] != outerpoints[i])
+			    outerpoints[i+1] = mesh[hasbothpoints[jj]][l];
+		      }
+		  if(done)
+		    {
+		      ElementIndex aux = hasbothpoints[i];
+		      hasbothpoints[i] = hasbothpoints[jj];
+		      hasbothpoints[jj] = aux;
+		    }
+		}
+	    }
+	  if(outerpoints[nsuround] != sp2)
+	    {
+	      cerr << "OJE OJE OJE" << endl;
+	      (*testout) << "OJE OJE OJE" << endl;
+	      (*testout) << "hasbothpoints: " << endl;
+	      for(int ii=0; ii < hasbothpoints.Size(); ii++)
+		{
+		  (*testout) << mesh[hasbothpoints[ii]] << endl;
+		  for(int jj=0; jj<mesh[hasbothpoints[ii]].GetNP(); jj++)
+		    if(mesh.mlbetweennodes[mesh[hasbothpoints[ii]][jj]][0] > 0)
+		      (*testout) << mesh[hasbothpoints[ii]][jj] << " between "
+				 << mesh.mlbetweennodes[mesh[hasbothpoints[ii]][jj]][0] << " and "
+				 << mesh.mlbetweennodes[mesh[hasbothpoints[ii]][jj]][1] << endl;
+		}
+	      (*testout) << "outerpoints: " << outerpoints << endl;
+	      (*testout) << "sel1 " << mesh[sel1] << endl
+			 << "sel2 " << mesh[sel2] << endl;
+	      for(int ii=0; ii<3; ii++)
+		{
+		  if(mesh.mlbetweennodes[mesh[sel1][ii]][0] > 0)
+		    (*testout) << mesh[sel1][ii] << " between "
+			       << mesh.mlbetweennodes[mesh[sel1][ii]][0] << " and "
+			       << mesh.mlbetweennodes[mesh[sel1][ii]][1] << endl;
+		  if(mesh.mlbetweennodes[mesh[sel2][ii]][0] > 0)
+		    (*testout) << mesh[sel2][ii] << " between "
+			       << mesh.mlbetweennodes[mesh[sel2][ii]][0] << " and "
+			       << mesh.mlbetweennodes[mesh[sel2][ii]][1] << endl;
+		}
+	    }
+
+	  
+	  ARRAY < int > outerpointsother;
+
+	  if(nsuroundother > 0)
+	    {
+	      outerpointsother.SetSize(nsuroundother+1);
+	      outerpointsother[0] = sp2other;
+	    }
+
+	  for(int i=0; i<nsuroundother; i++)
+	    {
+	      bool done = false;
+	      for(int jj=i; !done && jj<hasbothpointsother.Size(); jj++)
+		{
+		  for(int k=0; !done && k<4; k++)
+		    if(mesh[hasbothpointsother[jj]][k] == outerpointsother[i])
+		      {
+			done = true;
+			for(int l=0; l<4; l++)
+			  if(mesh[hasbothpointsother[jj]][l] != pi1other &&
+			     mesh[hasbothpointsother[jj]][l] != pi2other &&
+			     mesh[hasbothpointsother[jj]][l] != outerpointsother[i])
+			    outerpointsother[i+1] = mesh[hasbothpointsother[jj]][l];
+		      }
+		  if(done)
+		    {
+		      ElementIndex aux = hasbothpointsother[i];
+		      hasbothpointsother[i] = hasbothpointsother[jj];
+		      hasbothpointsother[jj] = aux;
+		    }
+		}
+	    }
+	  if(nsuroundother > 0 && outerpointsother[nsuroundother] != sp1other)
+	    {
+	      cerr << "OJE OJE OJE (other)" << endl;
+	      (*testout) << "OJE OJE OJE (other)" << endl;
+	      (*testout) << "pi1 " << pi1 << " pi2 " << pi2 << " sp1 " << sp1 << " sp2 " << sp2 << endl;
+	      (*testout) << "hasbothpoints: " << endl;
+	      for(int ii=0; ii < hasbothpoints.Size(); ii++)
+		{
+		  (*testout) << mesh[hasbothpoints[ii]] << endl;
+		  for(int jj=0; jj<mesh[hasbothpoints[ii]].GetNP(); jj++)
+		    if(mesh.mlbetweennodes[mesh[hasbothpoints[ii]][jj]][0] > 0)
+		      (*testout) << mesh[hasbothpoints[ii]][jj] << " between "
+				 << mesh.mlbetweennodes[mesh[hasbothpoints[ii]][jj]][0] << " and "
+				 << mesh.mlbetweennodes[mesh[hasbothpoints[ii]][jj]][1] << endl;
+		}
+	      (*testout) << "outerpoints: " << outerpoints << endl;
+	      (*testout) << "sel1 " << mesh[sel1] << endl
+			 << "sel2 " << mesh[sel2] << endl;
+	      for(int ii=0; ii<3; ii++)
+		{
+		  if(mesh.mlbetweennodes[mesh[sel1][ii]][0] > 0)
+		    (*testout) << mesh[sel1][ii] << " between "
+			       << mesh.mlbetweennodes[mesh[sel1][ii]][0] << " and "
+			       << mesh.mlbetweennodes[mesh[sel1][ii]][1] << endl;
+		  if(mesh.mlbetweennodes[mesh[sel2][ii]][0] > 0)
+		    (*testout) << mesh[sel2][ii] << " between "
+			       << mesh.mlbetweennodes[mesh[sel2][ii]][0] << " and "
+			       << mesh.mlbetweennodes[mesh[sel2][ii]][1] << endl;
+		}
+		  
+	      (*testout) << "pi1other " << pi1other << " pi2other " << pi2other << " sp1other " << sp1other << " sp2other " << sp2other << endl;
+	      (*testout) << "hasbothpointsother: " << endl;
+	      for(int ii=0; ii < hasbothpointsother.Size(); ii++)
+		{
+		  (*testout) << mesh[hasbothpointsother[ii]] << endl;
+		  for(int jj=0; jj<mesh[hasbothpointsother[ii]].GetNP(); jj++)
+		    if(mesh.mlbetweennodes[mesh[hasbothpointsother[ii]][jj]][0] > 0)
+		      (*testout) << mesh[hasbothpointsother[ii]][jj] << " between "
+				 << mesh.mlbetweennodes[mesh[hasbothpointsother[ii]][jj]][0] << " and "
+				 << mesh.mlbetweennodes[mesh[hasbothpointsother[ii]][jj]][1] << endl;
+		}
+	      (*testout) << "outerpoints: " << outerpointsother << endl;
+	      (*testout) << "sel1other " << mesh[sel1other] << endl
+			 << "sel2other " << mesh[sel2other] << endl;
+	      for(int ii=0; ii<3; ii++)
+		{
+		  if(mesh.mlbetweennodes[mesh[sel1other][ii]][0] > 0)
+		    (*testout) << mesh[sel1other][ii] << " between "
+			       << mesh.mlbetweennodes[mesh[sel1other][ii]][0] << " and "
+			       << mesh.mlbetweennodes[mesh[sel1other][ii]][1] << endl;
+		  if(mesh.mlbetweennodes[mesh[sel2other][ii]][0] > 0)
+		    (*testout) << mesh[sel2other][ii] << " between "
+			       << mesh.mlbetweennodes[mesh[sel2other][ii]][0] << " and "
+			       << mesh.mlbetweennodes[mesh[sel2other][ii]][1] << endl;
+		}
+	    }
+
+	  bad1=0;
+	  for(int i=0; i<hasbothpoints.Size(); i++)
+	    bad1 += CalcBad(mesh.Points(), mesh[hasbothpoints[i]],h);
+	  for(int i=0; i<hasbothpointsother.Size(); i++)
+	    bad1 += CalcBad(mesh.Points(), mesh[hasbothpointsother[i]],h);
+	  bad1 /= double(hasbothpoints.Size() + hasbothpointsother.Size());
+
+	  
+	  int startpoints,startpointsother;
+
+
+	  if(outerpoints.Size() == 3)
+	    startpoints = 1;
+	  else if(outerpoints.Size() == 4)
+	    startpoints = 2;
+	  else
+	    startpoints = outerpoints.Size();
+	  
+	  if(outerpointsother.Size() == 3)
+	    startpointsother = 1;
+	  else if(outerpointsother.Size() == 4)
+	    startpointsother = 2;
+	  else
+	    startpointsother = outerpointsother.Size();
+	  
+
+	  ARRAY < ARRAY < Element* > * > newelts(startpoints);
+	  ARRAY < ARRAY < Element* > * > neweltsother(startpointsother);
+
+	  double minbad = 1e50, minbadother = 1e50, currbad;
+	  int minpos = -1, minposother = -1;
+
+	  //(*testout) << "pi1 " << pi1 << " pi2 " << pi2 << " outerpoints " << outerpoints << endl;
+
+	  for(int i=0; i<startpoints; i++)
+	    {
+	      newelts[i] = new ARRAY <Element*>(2*(nsuround-1));
+	      
+	      for(int jj=0; jj<nsuround-1; jj++)
+		{
+		  (*newelts[i])[2*jj] = new Element(TET);
+		  (*newelts[i])[2*jj+1] = new Element(TET);
+		  Element & newel1 = *((*newelts[i])[2*jj]);
+		  Element & newel2 = *((*newelts[i])[2*jj+1]);
+
+		  newel1[0] = pi1;
+		  newel1[1] = outerpoints[i];
+		  newel1[2] = outerpoints[(i+jj+1)%outerpoints.Size()];
+		  newel1[3] = outerpoints[(i+jj+2)%outerpoints.Size()];
+
+		  newel2[0] = pi2;
+		  newel2[1] = outerpoints[i];
+		  newel2[2] = outerpoints[(i+jj+2)%outerpoints.Size()];
+		  newel2[3] = outerpoints[(i+jj+1)%outerpoints.Size()];
+		  
+
+		  //(*testout) << "j " << j << " newel1 " << newel1[0] << " "<< newel1[1] << " "<< newel1[2] << " "<< newel1[3] << endl
+		  //     << " newel2 " << newel2[0] << " "<< newel2[1] << " "<< newel2[2] << " "<< newel2[3] << endl;
+		  
+		  newel1.SetIndex(mattype);
+		  newel2.SetIndex(mattype);
+
+		}
+
+	      bool wrongorientation = true;
+	      for(int jj = 0; wrongorientation && jj<newelts[i]->Size(); jj++)
+		wrongorientation = wrongorientation && WrongOrientation(mesh.Points(), *(*newelts[i])[jj]);
+	      
+	      currbad = 0;
+
+	      for(int jj=0; jj<newelts[i]->Size(); jj++)
+		{
+		  if(wrongorientation)
+		    Swap((*(*newelts[i])[jj])[2],(*(*newelts[i])[jj])[3]);
+
+
+		  // not two new faces on same surface
+		  ARRAY<int> face_index;
+		  for(int k = 0; k<surfaceindicesonnode[(*(*newelts[i])[jj])[0]].Size(); k++)
+		    face_index.Append(surfaceindicesonnode[(*(*newelts[i])[jj])[0]][k]);
+
+		  for(int k=1; k<4; k++)
+		    {
+		      for(int l=0; l<face_index.Size(); l++)
+			{
+			  if(face_index[l] != -1 && 
+			     !(surfaceindicesonnode[(*(*newelts[i])[jj])[k]].Contains(face_index[l])))
+			    face_index[l] = -1;
+			}
+
+		    }
+		      
+		  for(int k=0; k<face_index.Size(); k++)
+		    if(face_index[k] != -1)
+		      currbad += 1e12;
+
+
+		  currbad += CalcBad(mesh.Points(),*(*newelts[i])[jj],h);
+
+
+		}  
+
+	      //currbad /= double(newelts[i]->Size());
+		    
+
+
+	      if(currbad < minbad)
+		{
+		  minbad = currbad;
+		  minpos = i;
+		}
+
+	    }
+
+	  if(startpointsother == 0)
+	    minbadother = 0;
+
+	  for(int i=0; i<startpointsother; i++)
+	    {
+	      neweltsother[i] = new ARRAY <Element*>(2*(nsuroundother));
+	      
+	      for(int jj=0; jj<nsuroundother; jj++)
+		{
+		  (*neweltsother[i])[2*jj] = new Element(TET);
+		  (*neweltsother[i])[2*jj+1] = new Element(TET);
+		  Element & newel1 = *((*neweltsother[i])[2*jj]);
+		  Element & newel2 = *((*neweltsother[i])[2*jj+1]);
+
+		  newel1[0] = pi1other;
+		  newel1[1] = outerpointsother[i];
+		  newel1[2] = outerpointsother[(i+jj+1)%outerpointsother.Size()];
+		  newel1[3] = outerpointsother[(i+jj+2)%outerpointsother.Size()];
+
+		  newel2[0] = pi2other;
+		  newel2[1] = outerpointsother[i];
+		  newel2[2] = outerpointsother[(i+jj+2)%outerpointsother.Size()];
+		  newel2[3] = outerpointsother[(i+jj+1)%outerpointsother.Size()];
+		  
+
+		  //(*testout) << "j " << j << " newel1 " << newel1[0] << " "<< newel1[1] << " "<< newel1[2] << " "<< newel1[3] << endl
+		  //	     << " newel2 " << newel2[0] << " "<< newel2[1] << " "<< newel2[2] << " "<< newel2[3] << endl;
+		  
+		  newel1.SetIndex(othermattype);
+		  newel2.SetIndex(othermattype);
+
+		}
+
+	      bool wrongorientation = true;
+	      for(int jj = 0; wrongorientation && jj<neweltsother[i]->Size(); jj++)
+		wrongorientation = wrongorientation && WrongOrientation(mesh.Points(), *(*neweltsother[i])[jj]);
+	      
+	      currbad = 0;
+
+	      for(int jj=0; jj<neweltsother[i]->Size(); jj++)
+		{
+		  if(wrongorientation)
+		    Swap((*(*neweltsother[i])[jj])[2],(*(*neweltsother[i])[jj])[3]);
+
+		  currbad += CalcBad(mesh.Points(),*(*neweltsother[i])[jj],h);
+		}  
+
+	      //currbad /= double(neweltsother[i]->Size());
+		    
+
+
+	      if(currbad < minbadother)
+		{
+		  minbadother = currbad;
+		  minposother = i;
+		}
+
+	    }
+
+	  //(*testout) << "minbad " << minbad << " bad1 " << bad1 << endl;
+
+	  
+	  double sbadnew = CalcTriangleBadness (mesh[pi1],mesh[sp2],mesh[sp1],0,0) + 
+	    CalcTriangleBadness (mesh[pi2],mesh[sp1],mesh[sp2],0,0);
+	  
+
+	  int denom = newelts[minpos]->Size();
+	  if(minposother >= 0)
+	    denom += neweltsother[minposother]->Size();
+	  
+
+	  if((minbad+minbadother)/double(denom) < bad1 && 
+	     sbadnew < sbad)
+	    {
+	      cnt++;
+
+	      swapped = true;
+
+
+	      int start1 = -1;
+	      for(int l=0; l<3; l++)
+		if(mesh[sel1][l] == pi1)
+		  start1 = l;
+	      if(mesh[sel1][(start1+1)%3] == pi2)
+		{
+		  mesh[sel1][0] = pi1;
+		  mesh[sel1][1] = sp2;
+		  mesh[sel1][2] = sp1;
+		  mesh[sel2][0] = pi2;
+		  mesh[sel2][1] = sp1;
+		  mesh[sel2][2] = sp2;
+		}
+	      else
+		{
+		  mesh[sel1][0] = pi2;
+		  mesh[sel1][1] = sp2;
+		  mesh[sel1][2] = sp1;
+		  mesh[sel2][0] = pi1;
+		  mesh[sel2][1] = sp1;
+		  mesh[sel2][2] = sp2;
+		}
+	      //(*testout) << "changed surface element " << sel1 << " to " << mesh[sel1] << ", " << sel2 << " to " << mesh[sel2] << endl;
+
+	      for(int l=0; l<3; l++)
+		{
+		  surfaceelementsonnode.Add(mesh[sel1][l],sel1);
+		  surfaceelementsonnode.Add(mesh[sel2][l],sel2);
+		}
+	      
+
+
+	      if(periodic)
+		{
+		  start1 = -1;
+		  for(int l=0; l<3; l++)
+		    if(mesh[sel1other][l] == pi1other)
+		      start1 = l;
+		  
+
+
+		  //(*testout) << "changed surface elements " << mesh[sel1other] << " and " << mesh[sel2other] << endl;
+		  if(mesh[sel1other][(start1+1)%3] == pi2other)
+		    {
+		      mesh[sel1other][0] = pi1other;
+		      mesh[sel1other][1] = sp2other;
+		      mesh[sel1other][2] = sp1other;
+		      mesh[sel2other][0] = pi2other;
+		      mesh[sel2other][1] = sp1other;
+		      mesh[sel2other][2] = sp2other;
+		      //(*testout) << "       with rule 1" << endl;
+		    }
+		  else
+		    {
+		      mesh[sel1other][0] = pi2other;
+		      mesh[sel1other][1] = sp2other;
+		      mesh[sel1other][2] = sp1other;
+		      mesh[sel2other][0] = pi1other;
+		      mesh[sel2other][1] = sp1other;
+		      mesh[sel2other][2] = sp2other;
+		      //(*testout) << "       with rule 2" << endl;
+		    }
+		  //(*testout) << "         to " << mesh[sel1other] << " and " << mesh[sel2other] << endl;
+		  
+		  //(*testout) << "  and surface element " << sel1other << " to " << mesh[sel1other] << ", " << sel2other << " to " << mesh[sel2other] << endl;
+
+		  for(int l=0; l<3; l++)
+		    {
+		      surfaceelementsonnode.Add(mesh[sel1other][l],sel1other);
+		      surfaceelementsonnode.Add(mesh[sel2other][l],sel2other);
+		    }
+		}
+
+
+
+
+	      for(int i=0; i<hasbothpoints.Size(); i++)
+		{
+		  mesh[hasbothpoints[i]] = *(*newelts[minpos])[i];
+
+		  for(int l=0; l<4; l++)
+		    elementsonnode.Add((*(*newelts[minpos])[i])[l],hasbothpoints[i]);
+		}
+
+	      for(int i=hasbothpoints.Size(); i<(*newelts[minpos]).Size(); i++)
+		{
+		  ElementIndex ni = mesh.AddVolumeElement(*(*newelts[minpos])[i]);
+		  
+		  for(int l=0; l<4; l++)
+		    elementsonnode.Add((*(*newelts[minpos])[i])[l],ni);
+		}
+
+	      if(hasbothpointsother.Size() > 0)
+		{
+		  for(int i=0; i<hasbothpointsother.Size(); i++)
+		    {
+		      mesh[hasbothpointsother[i]] = *(*neweltsother[minposother])[i];
+		      for(int l=0; l<4; l++)
+			elementsonnode.Add((*(*neweltsother[minposother])[i])[l],hasbothpointsother[i]);
+		    }
+		  
+		  for(int i=hasbothpointsother.Size(); i<(*neweltsother[minposother]).Size(); i++)
+		    {
+		      ElementIndex ni = mesh.AddVolumeElement(*(*neweltsother[minposother])[i]);
+		      for(int l=0; l<4; l++)
+			elementsonnode.Add((*(*neweltsother[minposother])[i])[l],ni);
+		    }
+		}
+
+	      
+
+	    }
+
+	  for(int i=0; i<newelts.Size(); i++)
+	    {
+	      for(int jj=0; jj<newelts[i]->Size(); jj++)
+		delete (*newelts[i])[jj];
+	      delete newelts[i];
+	    }
+
+	  for(int i=0; i<neweltsother.Size(); i++)
+	    {
+	      for(int jj=0; jj<neweltsother[i]->Size(); jj++)
+		delete (*neweltsother[i])[jj];
+	      delete neweltsother[i];
+	    }
+	
+	}
+    }
+
+  PrintMessage (5, cnt, " swaps performed");
+
+
+  for(int i=0; i<locidmaps.Size(); i++)
+    delete locidmaps[i];
+
+
+  mesh.Compress ();
+
+  multithread.task = savetask;
+}
+  
+
+
+
+
+
+
+
+/*
+  2 -> 3 conversion
+*/
+
+
+
+void MeshOptimize3d :: SwapImprove2 (Mesh & mesh, OPTIMIZEGOAL goal)
+{
+  int j, k, l;
+  ElementIndex ei, eli1, eli2, elnr;
+  SurfaceElementIndex sei;
+  PointIndex pi1(0), pi2(0), pi3(0), pi4(0), pi5(0);
+
+  int cnt = 0;
+
+  Element el21(TET), el22(TET), el31(TET), el32(TET), el33(TET);
+
+  double bad1, bad2;
+
+  int np = mesh.GetNP();
+  int ne = mesh.GetNE();
+  int nse = mesh.GetNSE();
+
+  if (goal == OPT_CONFORM) return;
+
+  // contains at least all elements at node
+  TABLE<ElementIndex, PointIndex::BASE> elementsonnode(np); 
+  TABLE<SurfaceElementIndex, PointIndex::BASE> belementsonnode(np);
+
+  PrintMessage (3, "SwapImprove2 ");
+  (*testout) << "\n" << "Start SwapImprove2" << "\n";
+  //  TestOk();
+
+
+
+  /*
+    CalcSurfacesOfNode ();
+    for (i = 1; i <= GetNE(); i++)
+    if (volelements.Get(i)[0])
+    if (!mesh.LegalTet (volelements.Get(i)))
+    {
+    cout << "detected illegal tet, 1" << endl;
+    (*testout) << "detected illegal tet1: " << i << endl;
+    }
+  */
+
+  
+  // Calculate total badness
+
+  bad1 = CalcTotalBad (mesh.Points(), mesh.VolumeElements());
+  (*testout) << "Total badness = " << bad1 << endl;
+  //  cout << "tot bad = " << bad1 << endl;
+
+  // find elements on node
+
+  for (ei = 0; ei < ne; ei++)
+    for (j = 0; j < mesh[ei].GetNP(); j++)
+      elementsonnode.Add (mesh[ei][j], ei);
+
+  for (sei = 0; sei < nse; sei++)
+    for (j = 0; j < 3; j++)
+      belementsonnode.Add (mesh[sei][j], sei);
+
+  for (eli1 = 0; eli1 < ne; eli1++)
+    {
+      if (multithread.terminate)
+	break;
+
+      if (mesh.ElementType (eli1) == FIXEDELEMENT)
+	continue;
+
+      if (mesh[eli1].GetType() != TET)
+	continue;
+
+      if ((goal == OPT_LEGAL) && 
+	  mesh.LegalTet (mesh[eli1]) &&
+	  CalcBad (mesh.Points(), mesh[eli1], 0) < 1e3)
+	continue;
+
+      // cout << "eli = " << eli1 << endl;
+      //      (*testout) << "swapimp2, eli = " << eli1 << "; el = " << mesh[eli1] << endl;
+
+      for (j = 0; j < 4; j++)
+	{
+	  // loop over faces
+      
+	  Element & elem = mesh[eli1];
+	  // if (elem[0] < PointIndex::BASE) continue;
+	  if (elem.IsDeleted()) continue;
+
+	  int mattyp = elem.GetIndex();
+	  
+	  switch (j)
+	    {
+	    case 0:
+	      pi1 = elem.PNum(1); pi2 = elem.PNum(2); 
+	      pi3 = elem.PNum(3); pi4 = elem.PNum(4);
+	      break;
+	    case 1:
+	      pi1 = elem.PNum(1); pi2 = elem.PNum(4); 
+	      pi3 = elem.PNum(2); pi4 = elem.PNum(3);
+	      break;
+	    case 2:
+	      pi1 = elem.PNum(1); pi2 = elem.PNum(3); 
+	      pi3 = elem.PNum(4); pi4 = elem.PNum(2);
+	      break;
+	    case 3:
+	      pi1 = elem.PNum(2); pi2 = elem.PNum(4); 
+	      pi3 = elem.PNum(3); pi4 = elem.PNum(1);
+	      break;
+	    }
+	  
+
+	  bool bface = 0;
+	  for (k = 0; k < belementsonnode[pi1].Size(); k++)
+	    {
+	      const Element2d & bel = 
+		mesh[belementsonnode[pi1][k]];
+
+	      bool bface1 = 1;
+	      for (l = 0; l < 3; l++)
+		if (bel[l] != pi1 && bel[l] != pi2 && bel[l] != pi3)
+		  {
+		    bface1 = 0;
+		    break;
+		  }
+
+	      if (bface1) 
+		{
+		  bface = 1;
+		  break;
+		}
+	    }
+	  
+	  if (bface) continue;
+
+
+	  FlatArray<ElementIndex> row = elementsonnode[pi1];
+	  for (k = 0; k < row.Size(); k++)
+	    {
+	      eli2 = row[k];
+
+	      // cout << "\rei1 = " << eli1 << ", pi1 = " << pi1 << ", k = " << k << ", ei2 = " << eli2 
+	      // << ", getne = " << mesh.GetNE();
+
+	      if ( eli1 != eli2 )
+		{
+		  Element & elem2 = mesh[eli2];
+		  if (elem2.IsDeleted()) continue;
+		  if (elem2.GetType() != TET)
+		    continue;
+		  
+		  int comnodes=0;
+		  for (l = 1; l <= 4; l++)
+		    if (elem2.PNum(l) == pi1 || elem2.PNum(l) == pi2 ||
+			elem2.PNum(l) == pi3)
+		      {
+			comnodes++;
+		      }
+		    else
+		      {
+			pi5 = elem2.PNum(l);
+		      }
+		  
+		  if (comnodes == 3)
+		    {
+		      bad1 = CalcBad (mesh.Points(), elem, 0) + 
+			CalcBad (mesh.Points(), elem2, 0); 
+		      
+		      if (!mesh.LegalTet(elem) || 
+			  !mesh.LegalTet(elem2))
+			bad1 += 1e4;
+
+		      
+		      el31.PNum(1) = pi1;
+		      el31.PNum(2) = pi2;
+		      el31.PNum(3) = pi5;
+		      el31.PNum(4) = pi4;
+		      el31.SetIndex (mattyp);
+		      
+		      el32.PNum(1) = pi2;
+		      el32.PNum(2) = pi3;
+		      el32.PNum(3) = pi5;
+		      el32.PNum(4) = pi4;
+		      el32.SetIndex (mattyp);
+		      
+		      el33.PNum(1) = pi3;
+		      el33.PNum(2) = pi1;
+		      el33.PNum(3) = pi5;
+		      el33.PNum(4) = pi4;
+		      el33.SetIndex (mattyp);
+		      
+		      bad2 = CalcBad (mesh.Points(), el31, 0) + 
+			CalcBad (mesh.Points(), el32, 0) +
+			CalcBad (mesh.Points(), el33, 0); 
+		      
+
+		      el31.flags.illegal_valid = 0;
+		      el32.flags.illegal_valid = 0;
+		      el33.flags.illegal_valid = 0;
+
+		      if (!mesh.LegalTet(el31) || 
+			  !mesh.LegalTet(el32) ||
+			  !mesh.LegalTet(el33))
+			bad2 += 1e4;
+
+
+		      bool do_swap = (bad2 < bad1);
+
+		      if ( ((bad2 < 1e6) || (bad2 < 10 * bad1)) &&
+			   mesh.BoundaryEdge (pi4, pi5))
+			do_swap = 1;
+			   
+		      if (do_swap)
+			{
+			  //			  cout << "do swap, eli1 = " << eli1 << "; eli2 = " << eli2 << endl;
+			  //			  (*mycout) << "2->3 " << flush;
+			  cnt++;
+
+			  el31.flags.illegal_valid = 0;
+			  el32.flags.illegal_valid = 0;
+			  el33.flags.illegal_valid = 0;
+
+			  mesh[eli1] = el31;
+			  mesh[eli2] = el32;
+			  
+			  ElementIndex neli =
+			    mesh.AddVolumeElement (el33);
+			  
+			  /*
+			    if (!LegalTet(el31) || !LegalTet(el32) ||
+			    !LegalTet(el33))
+			    {
+			    cout << "Swap to illegal tets !!!" << endl;
+			    }
+			  */
+			  // cout << "neli = " << neli << endl;
+			  for (l = 0; l < 4; l++)
+			    {
+			      elementsonnode.Add (el31[l], eli1);
+			      elementsonnode.Add (el32[l], eli2);
+			      elementsonnode.Add (el33[l], neli);
+			    }
+
+			  break;
+			}
+		    }
+		}
+	    }
+	}
+    }
+
+
+  PrintMessage (5, cnt, " swaps performed");
+
+
+
+  /*
+    CalcSurfacesOfNode ();
+    for (i = 1; i <= GetNE(); i++)
+    if (volelements.Get(i).PNum(1))
+    if (!LegalTet (volelements.Get(i)))
+    {
+    cout << "detected illegal tet, 2" << endl;
+    (*testout) << "detected illegal tet2: " << i << endl;
+    }
+  */
+
+
+  bad1 = CalcTotalBad (mesh.Points(), mesh.VolumeElements());
+  (*testout) << "Total badness = " << bad1 << endl;
+  (*testout) << "swapimprove2 done" << "\n";
+  //  (*mycout) << "Vol = " << CalcVolume (points, volelements) << "\n";
+}
+
+
+/*
+  void Mesh :: SwapImprove2 (OPTIMIZEGOAL goal)
+  {
+  int i, j;
+  int eli1, eli2;
+  int mattyp;
+
+  Element el31(4), el32(4), el33(4);
+  double bad1, bad2;
+
+
+  INDEX_3_HASHTABLE<INDEX_2> elsonface (GetNE());
+
+  (*mycout) << "SwapImprove2 " << endl;
+  (*testout) << "\n" << "Start SwapImprove2" << "\n";
+
+  // Calculate total badness
+
+  if (goal == OPT_QUALITY)
+  {
+  double bad1 = CalcTotalBad (points, volelements);
+  (*testout) << "Total badness = " << bad1 << endl;
+  }
+
+  // find elements on node
+
+
+  Element2d face;
+  for (i = 1; i <= GetNE(); i++)
+  if ( (i > eltyps.Size()) || (eltyps.Get(i) != FIXEDELEMENT) )
+  {
+  const Element & el = VolumeElement(i);
+  if (!el.PNum(1)) continue;
+
+  for (j = 1; j <= 4; j++)
+  {
+  el.GetFace (j, face);
+  INDEX_3 i3 (face.PNum(1), face.PNum(2), face.PNum(3));
+  i3.Sort();
+
+
+  int bnr, posnr;
+  if (!elsonface.PositionCreate (i3, bnr, posnr))
+  {
+  INDEX_2 i2;
+  elsonface.GetData (bnr, posnr, i3, i2);
+  i2.I2() = i;
+  elsonface.SetData (bnr, posnr, i3, i2);
+  }
+  else
+  {
+  INDEX_2 i2 (i, 0);
+  elsonface.SetData (bnr, posnr, i3, i2);
+  }
+
+  //  	    if (elsonface.Used (i3))
+  //  	      {
+  //  		INDEX_2 i2 = elsonface.Get(i3);
+  //  		i2.I2() = i;
+  //  		elsonface.Set (i3, i2);
+  //  	      }
+  //  	    else
+  //  	      {
+  //  		INDEX_2 i2 (i, 0);
+  //  		elsonface.Set (i3, i2);
+  //  	      }
+
+  }
+  }
+
+  BitArray original(GetNE());
+  original.Set();
+
+  for (i = 1; i <= GetNSE(); i++)
+  {
+  const Element2d & sface = SurfaceElement(i);
+  INDEX_3 i3 (sface.PNum(1), sface.PNum(2), sface.PNum(3));
+  i3.Sort();
+  INDEX_2 i2(0,0);
+  elsonface.Set (i3, i2);
+  }
+
+
+  for (i = 1; i <= elsonface.GetNBags(); i++)
+  for (j = 1; j <= elsonface.GetBagSize(i); j++)
+  {
+  INDEX_3 i3;
+  INDEX_2 i2;
+  elsonface.GetData (i, j, i3, i2);
+
+
+  int eli1 = i2.I1();
+  int eli2 = i2.I2();
+
+  if (eli1 && eli2 && original.Test(eli1) && original.Test(eli2) )
+  {
+  Element & elem = volelements.Elem(eli1);
+  Element & elem2 = volelements.Elem(eli2);
+
+  int pi1 = i3.I1();
+  int pi2 = i3.I2();
+  int pi3 = i3.I3();
+
+  int pi4 = elem.PNum(1) + elem.PNum(2) + elem.PNum(3) + elem.PNum(4) - pi1 - pi2 - pi3;
+  int pi5 = elem2.PNum(1) + elem2.PNum(2) + elem2.PNum(3) + elem2.PNum(4) - pi1 - pi2 - pi3;
+
+
+
+
+
+
+  el31.PNum(1) = pi1;
+  el31.PNum(2) = pi2;
+  el31.PNum(3) = pi3;
+  el31.PNum(4) = pi4;
+  el31.SetIndex (mattyp);
+	    
+  if (WrongOrientation (points, el31))
+  swap (pi1, pi2);
+
+
+  bad1 = CalcBad (points, elem, 0) + 
+  CalcBad (points, elem2, 0); 
+	    
+  //	    if (!LegalTet(elem) || !LegalTet(elem2))
+  //	      bad1 += 1e4;
+
+	    
+  el31.PNum(1) = pi1;
+  el31.PNum(2) = pi2;
+  el31.PNum(3) = pi5;
+  el31.PNum(4) = pi4;
+  el31.SetIndex (mattyp);
+	    
+  el32.PNum(1) = pi2;
+  el32.PNum(2) = pi3;
+  el32.PNum(3) = pi5;
+  el32.PNum(4) = pi4;
+  el32.SetIndex (mattyp);
+		      
+  el33.PNum(1) = pi3;
+  el33.PNum(2) = pi1;
+  el33.PNum(3) = pi5;
+  el33.PNum(4) = pi4;
+  el33.SetIndex (mattyp);
+	    
+  bad2 = CalcBad (points, el31, 0) + 
+  CalcBad (points, el32, 0) +
+  CalcBad (points, el33, 0); 
+	    
+  //	    if (!LegalTet(el31) || !LegalTet(el32) ||
+  //		!LegalTet(el33))
+  //	      bad2 += 1e4;
+	    
+	    
+  int swap = (bad2 < bad1);
+
+  INDEX_2 hi2b(pi4, pi5);
+  hi2b.Sort();
+	    
+  if ( ((bad2 < 1e6) || (bad2 < 10 * bad1)) &&
+  boundaryedges->Used (hi2b) )
+  swap = 1;
+	    
+  if (swap)
+  {
+  (*mycout) << "2->3 " << flush;
+		
+  volelements.Elem(eli1) = el31;
+  volelements.Elem(eli2) = el32;
+  volelements.Append (el33);
+		
+  original.Clear (eli1);
+  original.Clear (eli2);
+  }
+  }
+  }
+  
+  (*mycout) << endl;
+
+  if (goal == OPT_QUALITY)
+  {
+  bad1 = CalcTotalBad (points, volelements);
+  (*testout) << "Total badness = " << bad1 << endl;
+  }
+
+  //  FindOpenElements ();
+
+  (*testout) << "swapimprove2 done" << "\n";
+  }
+
+*/
+}
diff --git a/contrib/Netgen/libsrc/meshing/improve3.hpp b/contrib/Netgen/libsrc/meshing/improve3.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..e82f37b028f86edd369620f52333b6d3120d5265
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/improve3.hpp
@@ -0,0 +1,99 @@
+#ifndef FILE_IMPROVE3
+#define FILE_IMPROVE3
+
+
+
+
+///
+class MeshOptimize3d
+{
+public:
+  void CombineImprove (Mesh & mesh, OPTIMIZEGOAL goal = OPT_QUALITY);
+  void SplitImprove (Mesh & mesh, OPTIMIZEGOAL goal = OPT_QUALITY);
+  void SwapImprove (Mesh & mesh, OPTIMIZEGOAL goal = OPT_QUALITY,
+		    const BitArray * working_elements = NULL);
+  void SwapImproveSurface (Mesh & mesh, OPTIMIZEGOAL goal = OPT_QUALITY,
+			   const BitArray * working_elements = NULL,
+			   const ARRAY< ARRAY<int,PointIndex::BASE>* > * idmaps = NULL);
+  void SwapImprove2 (Mesh & mesh, OPTIMIZEGOAL goal = OPT_QUALITY);
+};
+
+
+
+extern double CalcBad (const Mesh::T_POINTS & points, const Element & elem,
+		       double h);
+
+extern double CalcTotalBad (const Mesh::T_POINTS & points, 
+			    const Mesh::T_VOLELEMENTS & elements);
+
+extern int WrongOrientation (const Mesh::T_POINTS & points, const Element & el);
+
+
+/* Functional depending of inner point inside triangular surface */
+
+
+class MinFunctionSum : public MinFunction
+{
+protected:
+  ARRAY<MinFunction*> functions;
+ 
+public:
+  
+  virtual double Func (const Vector & x) const;
+  virtual void Grad (const Vector & x, Vector & g) const;
+  virtual double FuncGrad (const Vector & x, Vector & g) const;
+  virtual double FuncDeriv (const Vector & x, const Vector & dir, double & deriv) const;
+  virtual double GradStopping (const Vector & x) const;
+
+  void AddFunction(MinFunction & fun);
+  
+  const MinFunction & Function(int i) const;
+  MinFunction & Function(int i);  
+};
+  
+
+
+class PointFunction1 : public MinFunction
+{
+  Mesh::T_POINTS & points;
+  const ARRAY<INDEX_3> & faces;
+  double h;
+public:
+  PointFunction1 (Mesh::T_POINTS & apoints, 
+		  const ARRAY<INDEX_3> & afaces,
+		  double ah);
+  
+  virtual double Func (const Vector & x) const;
+  virtual double FuncDeriv (const Vector & x, const Vector & dir, double & deriv) const;
+  virtual double FuncGrad (const Vector & x, Vector & g) const;
+  virtual double GradStopping (const Vector & x) const;
+};
+
+
+class JacobianPointFunction : public MinFunction
+{
+public:
+  Mesh::T_POINTS & points;
+  const Mesh::T_VOLELEMENTS & elements;
+  TABLE<INDEX> elementsonpoint;
+  PointIndex actpind;
+
+  bool onplane;
+  Vec<3> nv;
+  
+public:
+  JacobianPointFunction (Mesh::T_POINTS & apoints, 
+			 const Mesh::T_VOLELEMENTS & aelements);
+  
+  virtual void SetPointIndex (PointIndex aactpind);
+  virtual double Func (const Vector & x) const;
+  virtual double FuncGrad (const Vector & x, Vector & g) const;
+  virtual double FuncDeriv (const Vector & x, const Vector & dir, double & deriv) const;
+
+  inline void SetNV(const Vec<3> & anv) {nv = anv; onplane = true;}
+  inline void UnSetNV(void) {onplane = false;}
+};
+
+
+
+#endif
diff --git a/contrib/Netgen/libsrc/meshing/localh.cpp b/contrib/Netgen/libsrc/meshing/localh.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..1a9f3d340da7294cc8f709a214ecd6c44661da77
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/localh.cpp
@@ -0,0 +1,680 @@
+#include <mystdlib.h>
+#include "meshing.hpp"
+
+
+namespace netgen
+{
+
+GradingBox :: GradingBox (const double * ax1, const double * ax2)
+{
+  h2 = 0.5 * (ax2[0] - ax1[0]);
+  for (int i = 0; i <= 2; i++)
+    {
+      /*
+      x1[i] = ax1[i];
+      x2[i] = ax2[i];
+      */
+      xmid[i] = 0.5 * (ax1[i] + ax2[i]);
+    }
+
+  /*
+  (*testout) << "new box: " << xmid[0] << "-" << xmid[1] << "-" << xmid[2] 
+	     << " h = " << (x2[0] - x1[0]) << endl;
+  */
+
+  for (int i = 0; i < 8; i++)
+    childs[i] = NULL;
+  father = NULL;
+
+  flags.cutboundary = 0;
+  flags.isinner = 0;
+  flags.oldcell = 0;
+  flags.pinner = 0;
+
+  //  hopt = x2[0] - x1[0];
+  hopt = 2 * h2;
+}
+
+
+
+BlockAllocator GradingBox :: ball(sizeof (GradingBox));
+
+void * GradingBox :: operator new(size_t)
+{
+  return ball.Alloc();
+}
+
+void GradingBox :: operator delete (void * p)
+{
+  ball.Free (p);
+}
+
+
+
+
+
+
+
+void GradingBox :: DeleteChilds()
+{
+  int i;
+  for (i = 0; i < 8; i++)
+    if (childs[i])
+      {
+	childs[i]->DeleteChilds();
+	delete childs[i];
+	childs[i] = NULL;
+      }
+}
+
+
+LocalH :: LocalH (const Point3d & pmin, const Point3d & pmax, double agrading)
+{
+  double x1[3], x2[3];
+  double hmax;
+  int i;
+
+  boundingbox = Box3d (pmin, pmax);
+  grading = agrading;
+
+  // a small enlargement, non-regular points 
+  double val = 0.0879;
+  for (i = 1; i <= 3; i++)
+    {
+
+      x1[i-1] = (1 + val * i) * pmin.X(i) - val * i * pmax.X(i);
+      x2[i-1] = 1.1 * pmax.X(i) - 0.1 * pmin.X(i);
+    }
+
+  hmax = x2[0] - x1[0];
+  for (i = 1; i <= 2; i++)
+    if (x2[i] - x1[i] > hmax)
+      hmax = x2[i] - x1[i];
+
+  for (i = 0; i <= 2; i++)
+    x2[i] = x1[i] + hmax;
+
+  root = new GradingBox (x1, x2);
+  boxes.Append (root);
+}
+
+LocalH :: ~LocalH ()
+{
+  root->DeleteChilds();
+  delete root;
+}
+
+void LocalH :: Delete ()
+{
+  root->DeleteChilds();
+}
+
+void LocalH :: SetH (const Point3d & p, double h)
+{
+  /*
+  (*testout) << "Set h at " << p << " to " << h << endl;
+  if (h < 1e-8)
+    {
+      cout << "do not set h to " << h << endl;
+      return;
+    }
+  */
+
+  if (fabs (p.X() - root->xmid[0]) > root->h2 ||
+      fabs (p.Y() - root->xmid[1]) > root->h2 ||
+      fabs (p.Z() - root->xmid[2]) > root->h2)
+    return;
+
+  /*      
+  if (p.X() < root->x1[0] || p.X() > root->x2[0] ||
+      p.Y() < root->x1[1] || p.Y() > root->x2[1] ||
+      p.Z() < root->x1[2] || p.Z() > root->x2[2])
+    return;
+  */
+
+
+  if (GetH(p) <= 1.2 * h) return;
+
+
+  GradingBox * box = root;
+  GradingBox * nbox = root;
+  GradingBox * ngb;
+  int childnr;
+  double x1[3], x2[3];
+
+  while (nbox)
+    {
+      box = nbox;
+      childnr = 0;
+      if (p.X() > box->xmid[0]) childnr += 1;
+      if (p.Y() > box->xmid[1]) childnr += 2;
+      if (p.Z() > box->xmid[2]) childnr += 4;
+      nbox = box->childs[childnr];
+    };
+
+
+  while (2 * box->h2 > h)
+    {
+      childnr = 0;
+      if (p.X() > box->xmid[0]) childnr += 1;
+      if (p.Y() > box->xmid[1]) childnr += 2;
+      if (p.Z() > box->xmid[2]) childnr += 4;
+
+      double h2 = box->h2;
+      if (childnr & 1)
+	{
+	  x1[0] = box->xmid[0];
+	  x2[0] = x1[0]+h2;   // box->x2[0];
+	}
+      else
+	{
+	  x2[0] = box->xmid[0];
+	  x1[0] = x2[0]-h2;   // box->x1[0];
+	}
+
+      if (childnr & 2)
+	{
+	  x1[1] = box->xmid[1];
+	  x2[1] = x1[1]+h2;   // box->x2[1];
+	}
+      else
+	{
+	  x2[1] = box->xmid[1];
+	  x1[1] = x2[1]-h2;   // box->x1[1];
+	}
+
+      if (childnr & 4)
+	{
+	  x1[2] = box->xmid[2];
+	  x2[2] = x1[2]+h2;  // box->x2[2];
+	}
+      else
+	{
+	  x2[2] = box->xmid[2];
+	  x1[2] = x2[2]-h2;  // box->x1[2];
+	}
+
+      ngb = new GradingBox (x1, x2);
+      box->childs[childnr] = ngb;
+      ngb->father = box;
+
+      boxes.Append (ngb);
+      box = box->childs[childnr];
+    }
+
+  box->hopt = h;
+
+
+  double hbox = 2 * box->h2;  // box->x2[0] - box->x1[0];
+  double hnp = h + grading * hbox;
+
+  Point3d np;
+  int i;
+  for (i = 1; i <= 3; i++)
+    {
+      np = p;
+      np.X(i) = p.X(i) + hbox;
+      SetH (np, hnp);
+
+      np.X(i) = p.X(i) - hbox;
+      SetH (np, hnp);
+    }
+  /*
+  Point3d np;
+  int i1, i2, i3;
+  for (i1 = -1; i1 <= 1; i1++)
+    for (i2 = -1; i2 <= 1; i2++)
+      for (i3 = -1; i3 <= 1; i3++)
+	{
+	  np.X() = p.X() + hbox * i1;
+	  np.Y() = p.Y() + hbox * i2;
+	  np.Z() = p.Z() + hbox * i3;
+
+	  SetH (np, hnp);
+	}
+  */
+}
+
+
+
+double LocalH :: GetH (const Point3d & x) const
+{
+  const GradingBox * box = root;
+  const GradingBox * nbox;
+  int childnr;
+
+  while (1)
+    {
+      childnr = 0;
+      if (x.X() > box->xmid[0]) childnr += 1;
+      if (x.Y() > box->xmid[1]) childnr += 2;
+      if (x.Z() > box->xmid[2]) childnr += 4;
+      nbox = box->childs[childnr];
+      if (nbox)
+	box = nbox;
+      else
+	{
+	  //	  (*testout) << "diam = " << (box->x2[0] - box->x1[0])
+	  //		     << " h = " << box->hopt << endl;
+	  return box->hopt;
+	}
+    }
+}
+
+
+/// minimal h in box (pmin, pmax)
+double LocalH :: GetMinH (const Point3d & pmin, const Point3d & pmax) const
+{ 
+  Point3d pmin2, pmax2;
+  for (int j = 1; j <= 3; j++)
+    if (pmin.X(j) < pmax.X(j))
+      { pmin2.X(j) = pmin.X(j); pmax2.X(j) = pmax.X(j); }
+    else
+      { pmin2.X(j) = pmax.X(j); pmax2.X(j) = pmin.X(j); }
+
+  return GetMinHRec (pmin2, pmax2, root); 
+}
+
+
+double LocalH :: GetMinHRec (const Point3d & pmin, const Point3d & pmax,
+			     const GradingBox * box) const
+{
+  double h2 = box->h2;
+  if (pmax.X() < box->xmid[0]-h2 || pmin.X() > box->xmid[0]+h2 ||
+      pmax.Y() < box->xmid[1]-h2 || pmin.Y() > box->xmid[1]+h2 ||
+      pmax.Z() < box->xmid[2]-h2 || pmin.Z() > box->xmid[2]+h2)
+    return 1e8;
+  /*
+  if (pmax.X() < box->x1[0] || pmin.X() > box->x2[0] ||
+      pmax.Y() < box->x1[1] || pmin.Y() > box->x2[1] ||
+      pmax.Z() < box->x1[2] || pmin.Z() > box->x2[2])
+    return 1e8;
+  */
+
+      
+  double hmin = 2 * box->h2; // box->x2[0] - box->x1[0];
+  int i;
+  
+  for (i = 0; i <= 7; i++)
+    {
+      if (box->childs[i])
+	{
+	  double hi = GetMinHRec (pmin, pmax, box->childs[i]);
+	  if (hi < hmin)
+	    hmin = hi;
+	}	  
+    }
+
+  return hmin;
+}
+
+
+void LocalH :: CutBoundaryRec (const Point3d & pmin, const Point3d & pmax,
+			       GradingBox * box)
+{
+  double h2 = box->h2;
+  if (pmax.X() < box->xmid[0]-h2 || pmin.X() > box->xmid[0]+h2 ||
+      pmax.Y() < box->xmid[1]-h2 || pmin.Y() > box->xmid[1]+h2 ||
+      pmax.Z() < box->xmid[2]-h2 || pmin.Z() > box->xmid[2]+h2)
+    return;
+  /*
+  if (pmax.X() < box->x1[0] || pmin.X() > box->x2[0] ||
+      pmax.Y() < box->x1[1] || pmin.Y() > box->x2[1] ||
+      pmax.Z() < box->x1[2] || pmin.Z() > box->x2[2])
+    return;
+  */
+
+  box->flags.cutboundary = 1;
+  for (int i = 0; i < 8; i++)
+    if (box->childs[i])
+      CutBoundaryRec (pmin, pmax, box->childs[i]);
+}
+
+
+
+
+void LocalH :: FindInnerBoxes ( // int (*sameside)(const Point3d & p1, const Point3d & p2),
+			       AdFront3 * adfront,
+			       int (*testinner)(const Point3d & p1))
+{
+  int i;
+
+  int nf = adfront->GetNF();
+
+  for (i = 0; i < boxes.Size(); i++)
+    boxes[i] -> flags.isinner = 0;
+
+  root->flags.isinner = 0;
+
+  Point3d rpmid(root->xmid[0], root->xmid[1], root->xmid[2]);
+  Vec3d rv(root->h2, root->h2, root->h2);
+  Point3d rx2 = rpmid + rv;
+  Point3d rx1 = rpmid - rv;
+
+
+  root->flags.pinner = !adfront->SameSide (rpmid, rx2);
+  
+  if (testinner)
+    (*testout) << "inner = " << root->flags.pinner << " =?= " 
+	       << testinner(Point3d(root->xmid[0], root->xmid[1], root->xmid[2])) << endl;
+  
+  ARRAY<int> faceinds(nf);
+  ARRAY<Box3d> faceboxes(nf);
+
+  for (i = 1; i <= nf; i++)
+    {
+      faceinds.Elem(i) = i;
+      adfront->GetFaceBoundingBox(i, faceboxes.Elem(i));
+    }
+  
+  for (i = 0; i < 8; i++)
+    FindInnerBoxesRec2 (root->childs[i], adfront, faceboxes, faceinds, nf);
+}
+
+
+void LocalH :: 
+FindInnerBoxesRec2 (GradingBox * box,
+		    class AdFront3 * adfront, 
+		    ARRAY<Box3d> & faceboxes,
+		    ARRAY<int> & faceinds, int nfinbox)
+{
+  if (!box) return;
+  
+  int i, j;
+  
+  GradingBox * father = box -> father;
+  
+  Point3d c(box->xmid[0], box->xmid[1], box->xmid[2]);
+  Vec3d v(box->h2, box->h2, box->h2);
+  Box3d boxc(c-v, c+v);
+
+  Point3d fc(father->xmid[0], father->xmid[1], father->xmid[2]);
+  Vec3d fv(father->h2, father->h2, father->h2);
+  Box3d fboxc(fc-fv, fc+fv);
+
+  Box3d boxcfc(c,fc);
+
+
+  static ARRAY<int> faceused;
+  static ARRAY<int> faceused2;
+  static ARRAY<int> facenotused;
+
+  faceused.SetSize(0);
+  facenotused.SetSize(0);
+  faceused2.SetSize(0);
+
+  for (j = 1; j <= nfinbox; j++)
+    {
+      //      adfront->GetFaceBoundingBox (faceinds.Get(j), facebox);
+      const Box3d & facebox = faceboxes.Get(faceinds.Get(j));
+  
+      if (boxc.Intersect (facebox))
+	faceused.Append(faceinds.Get(j));
+      else
+	facenotused.Append(faceinds.Get(j));
+
+      if (boxcfc.Intersect (facebox))
+	faceused2.Append (faceinds.Get(j));
+    }
+  
+  for (j = 1; j <= faceused.Size(); j++)
+    faceinds.Elem(j) = faceused.Get(j);
+  for (j = 1; j <= facenotused.Size(); j++)
+    faceinds.Elem(j+faceused.Size()) = facenotused.Get(j);
+
+  
+  if (!father->flags.cutboundary)
+    {
+      box->flags.isinner = father->flags.isinner;
+      box->flags.pinner = father->flags.pinner;
+    }
+  else
+    {
+      Point3d cf(father->xmid[0], father->xmid[1], father->xmid[2]);
+      
+      if (father->flags.isinner)
+	box->flags.pinner = 1;
+      else
+	{
+	  if (adfront->SameSide (c, cf, &faceused2))
+	    box->flags.pinner = father->flags.pinner;
+	  else
+	    box->flags.pinner = 1 - father->flags.pinner;
+	}
+      
+      if (box->flags.cutboundary)
+	box->flags.isinner = 0;
+      else
+	box->flags.isinner = box->flags.pinner;
+    }
+
+  int nf = faceused.Size();
+  for (i = 0; i < 8; i++)
+    FindInnerBoxesRec2 (box->childs[i], adfront, faceboxes, faceinds, nf);
+}
+
+
+
+
+
+
+
+
+
+
+
+
+/*
+void LocalH :: FindInnerBoxes ( // int (*sameside)(const Point3d & p1, const Point3d & p2),
+			       AdFront3 * adfront,
+			       int (*testinner)(const Point3d & p1))
+{
+  int i;
+  for (i = 1; i <= boxes.Size(); i++)
+    boxes.Elem(i)->flags.isinner = 0;
+
+  root->flags.isinner = 0;
+
+  Point3d rpmid(root->xmid[0], root->xmid[1], root->xmid[2]);
+  Point3d rx2 = rpmid + Vec3d (root->h2, root->h2, root->h2);
+
+  root->flags.pinner = !adfront->SameSide (rpmid, rx2);
+  
+  if (testinner)
+    (*testout) << "inner = " << root->flags.pinner << " =?= " 
+	       << testinner(Point3d(root->xmid[0], root->xmid[1], root->xmid[2])) << endl;
+  
+
+  for (i = 2; i <= boxes.Size(); i++)
+    {
+      GradingBox * box = boxes.Elem(i);
+      GradingBox * father = box -> father;
+
+      Point3d c(box->xmid[0], box->xmid[1], box->xmid[2]);
+      Vec3d v(box->h2, box->h2, box->h2);
+      Point3d x1 = c-v;
+      Point3d x2 = c+v;
+
+
+      if (!father->flags.cutboundary)
+	{
+	  box->flags.isinner = father->flags.isinner;
+	  box->flags.pinner = father->flags.pinner;
+	}
+      else
+	{
+	  Point3d cf(father->xmid[0], father->xmid[1], father->xmid[2]);
+
+	  if (father->flags.isinner)
+	    box->flags.pinner = 1;
+	  else
+	    {
+	      if (adfront->SameSide (c, cf))
+		box->flags.pinner = father->flags.pinner;
+	      else
+		box->flags.pinner = 1 - father->flags.pinner;
+	    }
+
+	  if (box->flags.cutboundary)
+	    box->flags.isinner = 0;
+	  else
+	    box->flags.isinner = box->flags.pinner;
+	}
+    }
+  //  FindInnerBoxesRec (inner, root);
+}
+*/
+
+
+void LocalH :: FindInnerBoxesRec ( int (*inner)(const Point3d & p),
+				   GradingBox * box)
+{
+  int i;
+  if (box->flags.cutboundary)
+    {
+      for (i = 0; i < 8; i++)
+	if (box->childs[i])
+	  FindInnerBoxesRec (inner, box->childs[i]);
+    }
+  else
+    {
+      if (inner (Point3d (box->xmid[0], box->xmid[1], box->xmid[2])))
+	SetInnerBoxesRec (box);
+    }
+}
+
+
+void LocalH :: SetInnerBoxesRec (GradingBox * box)
+{
+  box->flags.isinner = 1;
+  for (int i = 0; i < 8; i++)
+    if (box->childs[i])
+      ClearFlagsRec (box->childs[i]);
+}
+
+void LocalH :: ClearFlagsRec (GradingBox * box)
+{
+  box->flags.cutboundary = 0;
+  box->flags.isinner = 0;
+  for (int i = 0; i < 8; i++)
+    if (box->childs[i])
+      ClearFlagsRec (box->childs[i]);
+}
+
+
+void LocalH :: WidenRefinement ()
+{
+  int nb = boxes.Size(); 
+  int i;
+  //  (*testout) << "old boxes: " << nb << endl;
+  for (i = 1; i <= nb; i++)
+    {
+      GradingBox * box = boxes.Get(i);
+      //      double h = box->x2[0] - box->x1[0];
+      double h = box->hopt;
+      Point3d c(box->xmid[0], box->xmid[1], box->xmid[2]);
+      //      (*testout) << " i = " << i 
+      //		 << " c = " << c << " h = " << h << endl;
+
+      for (int i1 = -1; i1 <= 1; i1++)
+	for (int i2 = -1; i2 <= 1; i2++)
+	  for (int i3 = -1; i3 <= 1; i3++)
+	    SetH (Point3d (c.X() + i1 * h, 
+			   c.Y() + i2 * h,
+			   c.Z() + i3 * h), 1.001 * h);     
+    }
+}
+
+void LocalH :: GetInnerPoints (ARRAY<Point3d> & points)
+{
+  int i, nb = boxes.Size(); 
+
+  for (i = 1; i <= nb; i++)
+    {
+      GradingBox * box = boxes.Get(i);
+      /*
+      if (box->flags.pinner)
+	points.Append (box->randomip);
+      */
+      //      if (box->flags.pinner)
+      if (box->flags.isinner)
+	{
+	  Point3d c(box->xmid[0], box->xmid[1], box->xmid[2]);
+	  points.Append (c);
+	  /*
+	  cout << "add point " << c << "; h = " << box->hopt
+	       << "; max-min = " << (box->x2[0]-box->x1[0]) << endl;
+	  */
+	}
+    }
+}
+
+
+
+void LocalH :: GetOuterPoints (ARRAY<Point3d> & points)
+{
+  int i, nb = boxes.Size(); 
+
+  for (i = 1; i <= nb; i++)
+    {
+      GradingBox * box = boxes.Get(i);
+      if (!box->flags.isinner &&
+	  !box->flags.cutboundary)
+	{
+	  Point3d c(box->xmid[0], box->xmid[1], box->xmid[2]);
+	  points.Append (c);
+	}
+    }
+}
+
+
+
+void LocalH :: Convexify ()
+{
+  ConvexifyRec (root);
+}
+
+void LocalH :: ConvexifyRec (GradingBox * box)
+{
+  Point3d center(box->xmid[0], box->xmid[1], box->xmid[2]);
+  Point3d hp;
+
+  double size = 2 * box->h2; // box->x2[0] - box->x1[0];
+  double dx = 0.6 * size;
+
+  double maxh = box->hopt;
+  int i;
+
+  
+  
+  for (i = 1; i <= 6; i++)
+    {
+      hp = center;
+      switch (i)
+	{
+	case 1: hp.X() += dx; break;
+	case 2: hp.X() -= dx; break;
+	case 3: hp.Y() += dx; break;
+	case 4: hp.Y() -= dx; break;
+	case 5: hp.Z() += dx; break;
+	case 6: hp.Z() -= dx; break;
+	}
+      
+      double hh = GetH (hp);
+      if (hh > maxh) maxh = hh;
+    }
+
+  if (maxh < 0.95 * box->hopt)
+    SetH (center, maxh);
+
+  for (i = 0; i < 8; i++)
+    if (box->childs[i])
+      ConvexifyRec (box->childs[i]);  
+}
+
+void LocalH :: PrintMemInfo (ostream & ost) const
+{
+  ost << "LocalH: " << boxes.Size() << " boxes of " << sizeof(GradingBox)
+      << " bytes = " << boxes.Size()*sizeof(GradingBox) << " bytes" << endl;
+}
+}
diff --git a/contrib/Netgen/libsrc/meshing/localh.hpp b/contrib/Netgen/libsrc/meshing/localh.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..7531bc7faf8b71107857cd19606e6cb7764e71b8
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/localh.hpp
@@ -0,0 +1,145 @@
+#ifndef LOCALH
+#define LOCALH
+
+/**************************************************************************/
+/* File:   localh.hh                                                      */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   29. Jan. 97                                                    */
+/**************************************************************************/
+
+
+
+
+/// box for grading
+class GradingBox
+{
+  /*
+  /// xmin
+  float x1[3];
+  /// xmax
+  float x2[3];
+  */
+  /// xmid
+  float xmid[3];
+  /// half edgelength
+  float h2;
+  ///
+  GradingBox * childs[8];
+  ///
+  GradingBox * father;
+  ///
+  double hopt;
+  ///
+  struct 
+  {
+    unsigned int cutboundary:1;
+    unsigned int isinner:1;
+    unsigned int oldcell:1;
+    unsigned int pinner:1;
+  } flags;
+public:
+  ///
+  GradingBox (const double * ax1, const double * ax2);
+  ///
+  void DeleteChilds();
+  ///
+  friend class LocalH;
+
+
+  static BlockAllocator ball;
+  void * operator new(size_t);
+  void operator delete (void *);
+};
+
+
+
+/**
+   Control of 3D mesh grading
+ */
+class LocalH 
+{
+  ///
+  GradingBox * root;
+  ///
+  double grading;
+  ///
+  ARRAY<GradingBox*> boxes;
+  ///
+  Box3d boundingbox;
+public:
+  ///
+  LocalH (const Point3d & pmin, const Point3d & pmax, double grading);
+  ///
+  ~LocalH();
+  ///
+  void Delete();
+  ///
+  void SetGrading (double agrading) { grading = agrading; }
+  ///
+  void SetH (const Point3d & x, double h);
+  ///
+  double GetH (const Point3d & x) const;
+  /// minimal h in box (pmin, pmax)
+  double GetMinH (const Point3d & pmin, const Point3d & pmax) const;
+
+  /// mark boxes intersecting with boundary-box
+  void CutBoundary (const Point3d & pmin, const Point3d & pmax)
+    { CutBoundaryRec (pmin, pmax, root); }
+
+  /// find inner boxes
+  void FindInnerBoxes ( // int (*sameside)(const Point3d & p1, const Point3d & p2),
+		       class AdFront3 * adfront,
+		       int (*testinner)(const Point3d & p1));
+
+  /// clears all flags 
+  void ClearFlags ()
+    { ClearFlagsRec(root); }
+
+  /// widen refinement zone
+  void WidenRefinement ();
+
+  /// get points in inner elements
+  void GetInnerPoints (ARRAY<Point3d> & points);
+
+  /// get points in outer closure
+  void GetOuterPoints (ARRAY<Point3d> & points);
+
+  ///
+  void Convexify ();
+  ///
+  int GetNBoxes () { return boxes.Size(); } 
+  const Box3d & GetBoundingBox () const
+  { return boundingbox; }
+  ///
+  void PrintMemInfo (ostream & ost) const;
+private:
+  /// 
+  double GetMinHRec (const Point3d & pmin, const Point3d & pmax,
+		     const GradingBox * box) const;
+  ///
+  void CutBoundaryRec (const Point3d & pmin, const Point3d & pmax,
+		       GradingBox * box);
+
+  ///
+  void FindInnerBoxesRec ( int (*inner)(const Point3d & p),
+			   GradingBox * box);
+
+  ///
+  void FindInnerBoxesRec2 (GradingBox * box,
+			   class AdFront3 * adfront,
+			   ARRAY<Box3d> & faceboxes,
+			   ARRAY<int> & finds, int nfinbox);
+
+
+  ///
+  void SetInnerBoxesRec (GradingBox * box);
+
+  ///
+  void ClearFlagsRec (GradingBox * box);
+  
+  ///
+  void ConvexifyRec (GradingBox * box);
+};
+
+
+#endif
diff --git a/contrib/Netgen/libsrc/meshing/meshclass.cpp b/contrib/Netgen/libsrc/meshing/meshclass.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..7dbec43e959bc56cb5fc3052aaa3129231b6d58a
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/meshclass.cpp
@@ -0,0 +1,5582 @@
+#include <mystdlib.h>
+#include "meshing.hpp"
+
+#ifdef PARALLEL
+#include <parallel.hpp>
+#endif
+
+namespace netgen
+{
+
+  Mesh :: Mesh ()
+  {
+    volelements.SetName ("vol elements");
+    surfelements.SetName ("surf elements");
+    points.SetName ("meshpoints");
+
+    boundaryedges = NULL;
+    surfelementht = NULL; 
+    segmentht = NULL;
+
+    lochfunc = NULL;
+    mglevels = 1;
+    elementsearchtree = NULL;
+    elementsearchtreets = NextTimeStamp();
+    majortimestamp = timestamp = NextTimeStamp();
+    hglob = 1e10;
+    hmin = 0;
+    numvertices = -1;
+    dimension = 3;
+
+    topology = new MeshTopology (*this);
+    curvedelems = new CurvedElements (*this);
+    clusters = new AnisotropicClusters (*this);
+    ident = new Identifications (*this);
+
+    hpelements = NULL;
+    coarsemesh = NULL;
+
+    ps_startelement = 0;
+
+    geomtype = NO_GEOM;
+
+    bcnames.SetSize(0);
+#ifdef PARALLEL
+    paralleltop = new ParallelMeshTopology (*this);
+#endif
+  }
+
+
+  Mesh :: ~Mesh()
+  {
+    delete lochfunc;
+    delete boundaryedges;
+    delete surfelementht;
+    delete segmentht;
+    delete curvedelems;
+    delete clusters;
+    delete topology;
+    delete ident;
+    delete elementsearchtree;
+
+    delete coarsemesh;
+    delete hpelements;
+    
+    for (int i = 0; i < materials.Size(); i++)
+      delete [] materials[i];
+
+    for(int i = 0; i < userdata_int.Size(); i++)
+      delete userdata_int[i];
+    for(int i = 0; i < userdata_double.Size(); i++)
+      delete userdata_double[i];
+
+    for (int i = 0; i < bcnames.Size(); i++ )
+      if ( bcnames[i] ) delete bcnames[i];
+
+#ifdef PARALLEL
+    delete paralleltop;
+#endif
+  }
+
+
+  Mesh & Mesh :: operator= (const Mesh & mesh2)
+  {
+    points = mesh2.points;
+    // eltyps = mesh2.eltyps;
+    segments = mesh2.segments;
+    surfelements = mesh2.surfelements;
+    volelements = mesh2.volelements;
+    lockedpoints = mesh2.lockedpoints;
+    facedecoding = mesh2.facedecoding;
+    dimension = mesh2.dimension;
+
+    bcnames.SetSize( mesh2.bcnames.Size() );
+    for ( int i = 0; i < mesh2.bcnames.Size(); i++ )
+      if ( mesh2.bcnames[i] ) bcnames[i] = new string ( *mesh2.bcnames[i] );
+      else bcnames[i] = 0;
+
+    return *this;
+  }
+
+
+  void Mesh :: DeleteMesh()
+  {
+    points.SetSize(0);
+    segments.SetSize(0);
+    surfelements.SetSize(0);
+    volelements.SetSize(0);
+    lockedpoints.SetSize(0);
+    surfacesonnode.SetSize(0);
+
+    delete boundaryedges;
+    boundaryedges = NULL;
+
+    openelements.SetSize(0);
+    facedecoding.SetSize(0);
+
+    delete ident;
+    ident = new Identifications (*this);
+    delete topology;
+    topology = new MeshTopology (*this);
+    delete curvedelems;
+    curvedelems = new CurvedElements (*this);
+    delete clusters;
+    clusters = new AnisotropicClusters (*this);
+
+    for ( int i = 0; i < bcnames.Size(); i++ )
+      if ( bcnames[i] ) delete bcnames[i];
+
+#ifdef PARALLEL
+    delete paralleltop;
+    paralleltop = new ParallelMeshTopology (*this);
+#endif
+
+
+    timestamp = NextTimeStamp();
+  }
+
+
+
+  PointIndex Mesh :: AddPoint (const Point3d & p, int layer)
+  { 
+    NgLock lock(mutex);
+    lock.Lock();
+
+    timestamp = NextTimeStamp();
+
+    PointIndex pi = points.Size() + PointIndex::BASE;
+    points.Append ( MeshPoint (p, layer, INNERPOINT) ); 
+
+#ifdef PARALLEL
+    points.Last().SetGhost(0);
+#endif
+
+    lock.UnLock();
+
+    return pi;
+  }
+
+  PointIndex Mesh :: AddPoint (const Point3d & p, int layer, POINTTYPE type)
+  { 
+    NgLock lock(mutex);
+    lock.Lock();
+
+    timestamp = NextTimeStamp();
+
+    PointIndex pi = points.Size() + PointIndex::BASE;
+    points.Append ( MeshPoint (p, layer, type) ); 
+
+#ifdef PARALLEL
+    points.Last().SetGhost(0);
+#endif
+
+    lock.UnLock();
+
+    return pi;
+  }
+
+
+#ifdef PARALLEL
+  PointIndex Mesh :: AddPoint (const Point3d & p, bool isghost,  int layer)
+  { 
+    NgLock lock(mutex);
+    lock.Lock();
+
+    timestamp = NextTimeStamp();
+
+    PointIndex pi = points.Size() + PointIndex::BASE;
+    points.Append ( MeshPoint (p, layer, INNERPOINT) ); 
+
+    points.Last().SetGhost(isghost);
+
+    lock.UnLock();
+
+    return pi;
+  }
+
+  PointIndex Mesh :: AddPoint (const Point3d & p, bool isghost, int layer, POINTTYPE type)
+  { 
+    NgLock lock(mutex);
+    lock.Lock();
+
+    timestamp = NextTimeStamp();
+
+    PointIndex pi = points.Size() + PointIndex::BASE;
+    points.Append ( MeshPoint (p, layer, type) ); 
+
+    points.Last().SetGhost(isghost);
+
+    lock.UnLock();
+
+    return pi;
+  }
+
+#endif
+
+
+
+  SegmentIndex Mesh :: AddSegment (const Segment & s)
+  { 
+    NgLock lock(mutex);	
+    lock.Lock();
+    timestamp = NextTimeStamp();
+
+    int maxn = max2 (s.p1, s.p2);
+    maxn += 1-PointIndex::BASE;
+
+    /*
+      if (maxn > ptyps.Size())
+      {
+      int maxo = ptyps.Size();
+      ptyps.SetSize (maxn);
+      for (int i = maxo; i < maxn; i++)
+      ptyps[i] = INNERPOINT;
+      }
+
+      if (ptyps[s.p1] > EDGEPOINT) ptyps[s.p1] = EDGEPOINT;
+      if (ptyps[s.p2] > EDGEPOINT) ptyps[s.p2] = EDGEPOINT;
+    */
+
+    if (maxn <= points.Size())
+      {
+	if (points[s.p1].Type() > EDGEPOINT)
+	  points[s.p1].SetType (EDGEPOINT);
+	if (points[s.p2].Type() > EDGEPOINT)
+	  points[s.p2].SetType (EDGEPOINT);
+      }
+    /*
+      else
+      {
+      cerr << "edge points nrs > points.Size" << endl;
+      }
+    */
+
+    SegmentIndex si = segments.Size();
+    segments.Append (s); 
+  
+    lock.UnLock();
+    return si;
+  }
+
+  SurfaceElementIndex Mesh :: AddSurfaceElement (const Element2d & el)
+  {     
+    NgLock lock(mutex);
+    lock.Lock();
+    timestamp = NextTimeStamp();
+
+    int maxn = el[0];
+    for (int i = 1; i < el.GetNP(); i++)
+      if (el[i] > maxn) maxn = el[i];
+
+    maxn += 1-PointIndex::BASE;
+
+    /*
+      if (maxn > ptyps.Size())
+      {
+      int maxo = ptyps.Size();
+      ptyps.SetSize (maxn);
+      for (i = maxo+PointIndex::BASE; 
+      i < maxn+PointIndex::BASE; i++)
+      ptyps[i] = INNERPOINT;
+      
+      }
+    */
+    if (maxn <= points.Size())
+      {
+	for (int i = 0; i < el.GetNP(); i++)
+	  if (points[el[i]].Type() > SURFACEPOINT)
+	    points[el[i]].SetType(SURFACEPOINT);
+      }
+    /*
+      else
+      {
+      cerr << "surf points nrs > points.Size" << endl;      
+      }
+    */
+
+    SurfaceElementIndex si = surfelements.Size();
+    surfelements.Append (el); 
+
+    if (el.index > facedecoding.Size())
+      cerr << "has no facedecoding: fd.size = " << facedecoding.Size() << ", ind = " << el.index << endl;
+
+    surfelements.Last().next = facedecoding[el.index-1].firstelement;
+    facedecoding[el.index-1].firstelement = si;
+
+#ifdef PARALLEL
+    surfelements.Last().SetGhost ( el.IsGhost() );
+#endif
+
+    lock.UnLock();
+    return si;
+  }
+
+
+  ElementIndex Mesh :: AddVolumeElement (const Element & el)
+  { 
+    NgLock lock(mutex);
+    lock.Lock();
+
+    int maxn = el[0];
+    for (int i = 1; i < el.GetNP(); i++)
+      if (el[i] > maxn) maxn = el[i];
+
+    maxn += 1-PointIndex::BASE;
+
+    /*
+      if (maxn > ptyps.Size())
+      {
+      int maxo = ptyps.Size();
+      ptyps.SetSize (maxn);
+      for (i = maxo+PointIndex::BASE; 
+      i < maxn+PointIndex::BASE; i++)
+      ptyps[i] = INNERPOINT;
+      }
+    */
+    /*
+      if (maxn > points.Size())
+      {
+      cerr << "add vol element before point" << endl;
+      }
+    */
+
+    int ve = volelements.Size();
+
+    volelements.Append (el); 
+    volelements.Last().flags.illegal_valid = 0;
+
+#ifdef PARALLEL
+    volelements.Last().SetGhost ( el.IsGhost() );
+#endif
+
+    // while (volelements.Size() > eltyps.Size())
+    // eltyps.Append (FREEELEMENT);
+  
+    timestamp = NextTimeStamp();
+
+    lock.UnLock();
+    return ve;
+  }
+
+
+
+
+
+
+  void Mesh :: Save (const string & filename) const
+  {
+    
+    ofstream outfile(filename.c_str());
+
+    Save(outfile);
+  }
+
+
+
+  void Mesh :: Save (ostream & outfile) const
+  {
+    int i, j;
+
+    double scale = 1;  // globflags.GetNumFlag ("scale", 1);
+    int inverttets = 0;  // globflags.GetDefineFlag ("inverttets");
+    int invertsurf = 0;  // globflags.GetDefineFlag ("invertsurfacemesh");
+
+
+
+    outfile << "mesh3d" << "\n";
+
+    outfile << "dimension\n" << GetDimension() << "\n";
+
+    outfile << "geomtype\n" << int(geomtype) << "\n";
+
+
+    outfile << "\n";
+    outfile << "# surfnr    bcnr   domin  domout      np      p1      p2      p3"
+	    << "\n";
+
+    
+    switch (geomtype)
+      {
+      case GEOM_STL:
+        outfile << "surfaceelementsgi" << "\n";
+        break;
+      case GEOM_OCC: case GEOM_ACIS:
+        outfile << "surfaceelementsuv" << "\n";
+        break;
+      default:
+        outfile << "surfaceelements" << "\n";
+      }
+
+    outfile << GetNSE() << "\n";
+
+    SurfaceElementIndex sei;
+    for (sei = 0; sei < GetNSE(); sei++)
+      {
+	if ((*this)[sei].GetIndex())
+	  {
+	    outfile.width(8);
+	    outfile << GetFaceDescriptor((*this)[sei].GetIndex ()).SurfNr()+1;
+	    outfile.width(8);
+	    outfile << GetFaceDescriptor((*this)[sei].GetIndex ()).BCProperty();
+	    outfile.width(8);	  
+	    outfile << GetFaceDescriptor((*this)[sei].GetIndex ()).DomainIn();
+	    outfile.width(8);	  
+	    outfile << GetFaceDescriptor((*this)[sei].GetIndex ()).DomainOut();
+	  }
+	else
+	  outfile << "       0       0       0";
+
+	Element2d sel = (*this)[sei];
+	if (invertsurf)
+	  sel.Invert();
+
+	outfile.width(8);
+	outfile << sel.GetNP();
+
+	for (j = 0; j < sel.GetNP(); j++)
+	  {
+	    outfile.width(8);	  
+	    outfile << sel[j];
+	  }
+
+
+        switch (geomtype)
+          {
+          case GEOM_STL:
+            for (j = 1; j <= sel.GetNP(); j++)
+              {
+                outfile.width(7);	  
+                outfile << " " << sel.GeomInfoPi(j).trignum;
+              }
+            break;
+          case GEOM_OCC: case GEOM_ACIS:
+            for (j = 1; j <= sel.GetNP(); j++)
+              {
+                outfile.width(7);	  
+                outfile << " " << sel.GeomInfoPi(j).u;
+                outfile << " " << sel.GeomInfoPi(j).v;
+              }
+            break;
+          default:
+            outfile << "\n";
+          }
+
+
+	outfile << endl;
+      }
+
+    outfile << "\n" << "\n";
+    outfile << "#  matnr      np      p1      p2      p3      p4" << "\n";
+    outfile << "volumeelements" << "\n";
+    outfile << GetNE() << "\n";
+
+    for (ElementIndex ei = 0; ei < GetNE(); ei++)
+      {
+	outfile.width(8);
+	outfile << (*this)[ei].GetIndex();
+	outfile.width(8);
+	outfile << (*this)[ei].GetNP();
+
+	Element el = (*this)[ei];
+	if (inverttets)
+	  el.Invert();
+
+	/*
+	  for (j = 0; j < el.GetNP(); j++)
+	  for (int k = 0; k < el.GetNP()-1; k++)
+	  if (el[k] > el[k+1]) swap (el[k], el[k+1]);
+	*/
+
+	for (j = 0; j < el.GetNP(); j++)
+	  {
+	    outfile.width(8);
+	    outfile << el[j];
+	  }
+	outfile << "\n";
+      }
+
+
+    outfile << "\n" << "\n";
+//     outfile << "   surf1   surf2      p1      p2" << "\n";
+    outfile << "# surfid  0   p1   p2   trignum1    trignum2   domin/surfnr1    domout/surfnr2   ednr1   dist1   ednr2   dist2 \n";
+    outfile << "edgesegmentsgi2" << "\n";
+    outfile << GetNSeg() << "\n";
+
+    for (i = 1; i <= GetNSeg(); i++)
+      {
+	const Segment & seg = LineSegment (i);
+	outfile.width(8);
+	outfile << seg.si; // 2D: bc number, 3D: wievielte Kante
+	outfile.width(8);
+	outfile << 0;
+	outfile.width(8);
+	outfile << seg.p1;
+	outfile.width(8);
+	outfile << seg.p2;
+	outfile << " ";
+	outfile.width(8);
+	outfile << seg.geominfo[0].trignum;  // stl dreiecke
+	outfile << " ";
+	outfile.width(8);
+	outfile << seg.geominfo[1].trignum; // << endl;  // stl dreieck
+	
+	if (dimension == 3)
+	  {
+	    outfile << " ";
+	    outfile.width(8);
+	    outfile << seg.surfnr1+1;
+	    outfile << " ";
+	    outfile.width(8);
+	    outfile << seg.surfnr2+1;
+	  }
+	else
+	  {
+	    outfile << " ";
+	    outfile.width(8);
+	    outfile << seg.domin;
+	    outfile << " ";
+	    outfile.width(8);
+	    outfile << seg.domout;
+	  }
+
+	outfile << " ";
+	outfile.width(8);
+	outfile << seg.edgenr;
+	outfile << " ";
+	outfile.width(12);
+	outfile.precision(16);
+	outfile << seg.epgeominfo[0].dist;  // splineparameter (2D)
+	outfile << " ";
+	outfile.width(8);
+	outfile.precision(16);
+	outfile << seg.epgeominfo[1].edgenr;  // geometry dependent
+	outfile << " ";
+	outfile.width(12);
+	outfile << seg.epgeominfo[1].dist;
+
+	outfile << "\n";
+      }
+
+
+    outfile << "\n" << "\n";
+    outfile << "#          X             Y             Z" << "\n";
+    outfile << "points" << "\n";
+    outfile << GetNP() << "\n";
+    outfile.precision(16);
+    outfile.setf (ios::fixed, ios::floatfield);
+    outfile.setf (ios::showpoint);
+
+    PointIndex pi;
+    for (pi = PointIndex::BASE; 
+	 pi < GetNP()+PointIndex::BASE; pi++)
+      {
+	outfile.width(22);
+	outfile << (*this)[pi](0)/scale << "  ";
+	outfile.width(22);
+	outfile << (*this)[pi](1)/scale << "  ";
+	outfile.width(22);
+	outfile << (*this)[pi](2)/scale << "\n";
+      }      
+
+    if (ident -> GetMaxNr() > 0)
+      {
+	outfile << "identifications\n";
+	ARRAY<INDEX_2> identpairs;
+	int cnt = 0;
+	for (i = 1; i <= ident -> GetMaxNr(); i++)
+	  {
+	    ident -> GetPairs (i, identpairs);
+	    cnt += identpairs.Size();
+	  }
+	outfile << cnt << "\n";
+	for (i = 1; i <= ident -> GetMaxNr(); i++)
+	  {
+	    ident -> GetPairs (i, identpairs);
+	    for (j = 1; j <= identpairs.Size(); j++)
+	      {
+		outfile.width (8);
+		outfile << identpairs.Get(j).I1();
+		outfile.width (8);
+		outfile << identpairs.Get(j).I2();
+		outfile.width (8);
+		outfile << i << "\n";
+	      }
+	  }
+
+	outfile << "identificationtypes\n";
+	outfile << ident -> GetMaxNr() << "\n";
+	for (i = 1; i <= ident -> GetMaxNr(); i++)
+	  {
+	    int type = ident -> GetType(i);
+	    outfile << " " << type;
+	  }
+	outfile << "\n";
+      }
+
+    int cntmat = 0;
+    for (i = 1; i <= materials.Size(); i++)
+      if (materials.Get(i) && strlen (materials.Get(i)))
+	cntmat++;
+
+    if (cntmat)
+      {
+	outfile << "materials" << endl;
+	outfile << cntmat << endl;
+	for (i = 1; i <= materials.Size(); i++)
+	  if (materials.Get(i) && strlen (materials.Get(i)))
+	    outfile << i << " " << materials.Get(i) << endl;
+      }
+
+    
+    int cntbcnames = 0;
+    for ( int ii = 0; ii < bcnames.Size(); ii++ )
+      if ( bcnames[ii] ) cntbcnames++;
+
+    if ( cntbcnames )
+      {
+	outfile << "\n\nbcnames" << endl << bcnames.Size() << endl;
+	for ( i = 0; i < bcnames.Size(); i++ )
+	  outfile << i+1 << "\t" << GetBCName(i) << endl;
+	outfile << endl << endl;
+      }
+
+    /*
+    if ( GetDimension() == 2 )
+      {
+	for (i = 1; i <= GetNSeg(); i++)
+	  {
+	    const Segment & seg = LineSegment (i);
+	    if ( ! bcprops.Contains(seg.si) && seg.GetBCName() != "" )
+	      {
+		bcprops.Append(seg.si);
+		cntbcnames++;
+	      }
+	  }
+      }
+    else
+      {
+	for (sei = 0; sei < GetNSE(); sei++)
+	  {
+	    if ((*this)[sei].GetIndex())
+	      {
+		int bcp = GetFaceDescriptor((*this)[sei].GetIndex ()).BCProperty();
+		string name = GetFaceDescriptor((*this)[sei].GetIndex ()).BCName();
+		if ( !bcprops.Contains(bcp) &&
+		     name != "" )
+		  {
+		    bcprops.Append(bcp);
+		    cntbcnames++;
+		  }
+	      }
+	  }
+      }
+
+    bcprops.SetSize(0);
+    if ( cntbcnames )
+      {
+	outfile << "\nbcnames" << endl << cntbcnames << endl;
+	if ( GetDimension() == 2 )
+	  {
+	    for (i = 1; i <= GetNSeg(); i++)
+	      {
+		const Segment & seg = LineSegment (i);
+		if ( ! bcprops.Contains(seg.si) && seg.GetBCName() != "" )
+		  {
+		    bcprops.Append(seg.si);
+		    outfile << seg.si << "\t" << seg.GetBCName() << endl;
+		  }
+	      }
+	  }
+	else
+	  {
+	    for (sei = 0; sei < GetNSE(); sei++)
+	      {
+		if ((*this)[sei].GetIndex())
+		  {
+		    int bcp = GetFaceDescriptor((*this)[sei].GetIndex ()).BCProperty();
+		    string name = GetFaceDescriptor((*this)[sei].GetIndex ()).BCName();
+		    if ( !bcprops.Contains(bcp) &&
+			 name != "" )
+		      {
+			bcprops.Append(bcp);
+			outfile << bcp << "\t" << name << endl;
+		      }
+		  }
+	      }
+	  }
+	outfile << endl << endl;
+      }
+    */
+
+    int cnt_sing = 0;
+    for (PointIndex pi = PointIndex::BASE; pi < GetNP()+PointIndex::BASE; pi++)
+      if ((*this)[pi].Singularity()>=1.) cnt_sing++;
+    
+    if (cnt_sing)
+      {
+	outfile << "singular_points" << endl << cnt_sing << endl;
+	for (PointIndex pi = PointIndex::BASE; pi < GetNP()+PointIndex::BASE; pi++)
+	  if ((*this)[pi].Singularity()>=1.) 
+	    outfile << int(pi) << "\t" << (*this)[pi].Singularity() << endl;
+      }
+
+    cnt_sing = 0;
+    for (SegmentIndex si = 0; si < GetNSeg(); si++)
+      if ( segments[si].singedge_left ) cnt_sing++;
+    if (cnt_sing)
+      {
+	outfile << "singular_edge_left" << endl << cnt_sing << endl;
+	for (SegmentIndex si = 0; si < GetNSeg(); si++)
+	  if ( segments[si].singedge_left )
+	    outfile << int(si) << "\t" << segments[si].singedge_left << endl;
+      }
+
+    cnt_sing = 0;
+    for (SegmentIndex si = 0; si < GetNSeg(); si++)
+      if ( segments[si].singedge_right ) cnt_sing++;
+    if (cnt_sing)
+      {
+	outfile << "singular_edge_right" << endl << cnt_sing << endl;
+	for (SegmentIndex si = 0; si < GetNSeg(); si++)
+	  if ( segments[si].singedge_right  )
+	    outfile << int(si) << "\t" << segments[si].singedge_right << endl;
+      }
+
+
+    cnt_sing = 0;
+    for (SurfaceElementIndex sei = 0; sei < GetNSE(); sei++)
+      if ( GetFaceDescriptor ((*this)[sei].GetIndex()).domin_singular) 
+	cnt_sing++;
+
+    if (cnt_sing)
+      {
+	outfile << "singular_face_inside" << endl << cnt_sing << endl;
+	for (SurfaceElementIndex sei = 0; sei < GetNSE(); sei++)
+	  if ( GetFaceDescriptor ((*this)[sei].GetIndex()).domin_singular) 
+	    outfile << int(sei)  << "\t" << 
+	      GetFaceDescriptor ((*this)[sei].GetIndex()).domin_singular  << endl;
+      }
+
+    cnt_sing = 0;
+    for (SurfaceElementIndex sei = 0; sei < GetNSE(); sei++)
+      if ( GetFaceDescriptor ((*this)[sei].GetIndex()).domout_singular) cnt_sing++;
+    if (cnt_sing)
+      {
+	outfile << "singular_face_outside" << endl << cnt_sing << endl;
+	for (SurfaceElementIndex sei = 0; sei < GetNSE(); sei++)
+	  if ( GetFaceDescriptor ((*this)[sei].GetIndex()).domout_singular) 
+	    outfile << int(sei) << "\t" 
+		    << GetFaceDescriptor ((*this)[sei].GetIndex()).domout_singular << endl;
+      }
+
+
+  }
+
+
+  
+  void Mesh :: Load (const string & filename)
+  {
+    
+    ifstream infile(filename.c_str());
+    if (!infile.good())
+      throw NgException ("mesh file not found");
+
+    Load(infile);
+  }
+
+
+
+ 
+  void Mesh :: Load (istream & infile)
+  {
+
+    char str[100];
+    int i, n;
+
+    double scale = 1;  // globflags.GetNumFlag ("scale", 1);
+    int inverttets = 0;  // globflags.GetDefineFlag ("inverttets");
+    int invertsurf = 0;  // globflags.GetDefineFlag ("invertsurfacemesh");
+
+
+    facedecoding.SetSize(0);
+
+    bool endmesh = false;
+
+    while (infile.good() && !endmesh)
+      {
+	infile >> str;
+
+	if (strcmp (str, "dimension") == 0)
+	  {
+	    infile >> dimension;
+	  }
+
+	if (strcmp (str, "geomtype") == 0)
+	  {
+            int hi;
+	    infile >> hi;
+            geomtype = GEOM_TYPE(hi);
+	  }
+
+
+	if (strcmp (str, "surfaceelements") == 0)
+	  {
+	    infile >> n;
+	    PrintMessage (3, n, " surface elements");
+	    for (i = 1; i <= n; i++)
+	      {
+		int j;
+		int surfnr, bcp, domin, domout, nep, faceind = 0;
+
+		infile >> surfnr >> bcp >> domin >> domout;
+		surfnr--;
+
+		for (j = 1; j <= facedecoding.Size(); j++)
+		  if (GetFaceDescriptor(j).SurfNr() == surfnr &&
+		      GetFaceDescriptor(j).BCProperty() == bcp &&
+		      GetFaceDescriptor(j).DomainIn() == domin &&
+		      GetFaceDescriptor(j).DomainOut() == domout)
+		    faceind = j;
+
+		if (!faceind)
+		  {
+		    faceind = AddFaceDescriptor (FaceDescriptor(surfnr, domin, domout, 0));
+		    GetFaceDescriptor(faceind).SetBCProperty (bcp);
+		  }
+
+		infile >> nep;
+		if (!nep) nep = 3;
+
+		Element2d tri(nep);
+		tri.SetIndex(faceind);
+
+		for (j = 1; j <= nep; j++)
+		  infile >> tri.PNum(j);
+
+		if (invertsurf)
+		  tri.Invert();
+
+		AddSurfaceElement (tri);
+	      }
+	  }
+      
+	if (strcmp (str, "surfaceelementsgi") == 0)
+	  {
+	    infile >> n;
+	    PrintMessage (3, n, " surface elements");
+	    for (i = 1; i <= n; i++)
+	      {
+		int j;
+		int surfnr, bcp, domin, domout, nep, faceind = 0;
+		infile >> surfnr >> bcp >> domin >> domout;
+		surfnr--;
+
+		for (j = 1; j <= facedecoding.Size(); j++)
+		  if (GetFaceDescriptor(j).SurfNr() == surfnr &&
+		      GetFaceDescriptor(j).BCProperty() == bcp &&
+		      GetFaceDescriptor(j).DomainIn() == domin &&
+		      GetFaceDescriptor(j).DomainOut() == domout)
+		    faceind = j;
+
+		if (!faceind)
+		  {
+		    faceind = AddFaceDescriptor (FaceDescriptor(surfnr, domin, domout, 0));
+		    GetFaceDescriptor(faceind).SetBCProperty (bcp);
+		  }
+
+		infile >> nep;
+		if (!nep) nep = 3;
+
+		Element2d tri(nep);
+		tri.SetIndex(faceind);
+
+		for (j = 1; j <= nep; j++)
+		  infile >> tri.PNum(j);
+
+		for (j = 1; j <= nep; j++)
+		  infile >> tri.GeomInfoPi(j).trignum;
+
+		if (invertsurf)
+		  tri.Invert();
+
+		AddSurfaceElement (tri);
+	      }
+	  }
+
+	if (strcmp (str, "surfaceelementsuv") == 0)
+	  {
+	    infile >> n;
+	    PrintMessage (3, n, " surface elements");
+	    for (i = 1; i <= n; i++)
+	      {
+		int j;
+		int surfnr, bcp, domin, domout, nep, faceind = 0;
+		infile >> surfnr >> bcp >> domin >> domout;
+		surfnr--;
+
+		for (j = 1; j <= facedecoding.Size(); j++)
+		  if (GetFaceDescriptor(j).SurfNr() == surfnr &&
+		      GetFaceDescriptor(j).BCProperty() == bcp &&
+		      GetFaceDescriptor(j).DomainIn() == domin &&
+		      GetFaceDescriptor(j).DomainOut() == domout)
+		    faceind = j;
+
+		if (!faceind)
+		  {
+		    faceind = AddFaceDescriptor (FaceDescriptor(surfnr, domin, domout, 0));
+		    GetFaceDescriptor(faceind).SetBCProperty (bcp);
+		  }
+
+		infile >> nep;
+		if (!nep) nep = 3;
+
+		Element2d tri(nep);
+		tri.SetIndex(faceind);
+
+		for (j = 1; j <= nep; j++)
+		  infile >> tri.PNum(j);
+
+		for (j = 1; j <= nep; j++)
+		  infile >> tri.GeomInfoPi(j).u >> tri.GeomInfoPi(j).v;
+
+		if (invertsurf)
+		  tri.Invert();
+
+		AddSurfaceElement (tri);
+	      }
+          }
+
+
+	if (strcmp (str, "volumeelements") == 0)
+	  {
+	    infile >> n;
+	    PrintMessage (3, n, " volume elements");
+	    for (i = 1; i <= n; i++)
+	      {
+		Element el;
+		int hi, nep;
+		infile >> hi;
+		if (hi == 0) hi = 1;
+		el.SetIndex(hi);
+		infile >> nep;
+		el.SetNP(nep);
+	      
+		for (int j = 0; j < nep; j++)
+		  infile >> (int&)(el[j]);
+	      
+		if (inverttets)
+		  el.Invert();
+
+		AddVolumeElement (el);
+	      }
+	  }
+    
+
+	if (strcmp (str, "edgesegments") == 0)
+	  {
+	    infile >> n;
+	    for (i = 1; i <= n; i++)
+	      {
+		Segment seg;
+		int hi;
+		infile >> seg.si >> hi >> seg.p1 >> seg.p2;
+		AddSegment (seg);
+	      }
+	  }
+      
+
+
+	if (strcmp (str, "edgesegmentsgi") == 0)
+	  {
+	    infile >> n;
+	    for (i = 1; i <= n; i++)
+	      {
+		Segment seg;
+		int hi;
+		infile >> seg.si >> hi >> seg.p1 >> seg.p2
+		       >> seg.geominfo[0].trignum
+		       >> seg.geominfo[1].trignum;
+		AddSegment (seg);
+	      }
+	  }
+	
+	if (strcmp (str, "edgesegmentsgi2") == 0)
+	  {
+	    int a; 
+	    infile >> a;
+	    n=a; 
+
+	    PrintMessage (3, n, " curve elements");
+
+	    for (i = 1; i <= n; i++)
+	      {
+		Segment seg;
+		int hi;
+		infile >> seg.si >> hi >> seg.p1 >> seg.p2
+		       >> seg.geominfo[0].trignum
+		       >> seg.geominfo[1].trignum
+		       >> seg.surfnr1 >> seg.surfnr2
+		       >> seg.edgenr
+		       >> seg.epgeominfo[0].dist
+		       >> seg.epgeominfo[1].edgenr
+		       >> seg.epgeominfo[1].dist;
+
+		seg.epgeominfo[0].edgenr = seg.epgeominfo[1].edgenr;
+
+		seg.domin = seg.surfnr1;
+		seg.domout = seg.surfnr2;
+
+		seg.surfnr1--;
+		seg.surfnr2--;
+	      
+		AddSegment (seg);
+	      }
+	  }
+      
+	if (strcmp (str, "points") == 0)
+	  {
+	    infile >> n;
+	    PrintMessage (3, n, " points");
+	    for (i = 1; i <= n; i++)
+	      {
+		Point3d p;
+		infile >> p.X() >> p.Y() >> p.Z();
+		p.X() *= scale;
+		p.Y() *= scale;
+		p.Z() *= scale;
+		AddPoint (p);
+	      }
+	  }
+
+	if (strcmp (str, "identifications") == 0)
+	  {
+	    infile >> n;
+	    for (i = 1; i <= n; i++)
+	      {
+		PointIndex pi1, pi2;
+		int ind;
+		infile >> pi1 >> pi2 >> ind;
+		ident -> Add (pi1, pi2, ind);
+	      }
+	  }
+       
+	if (strcmp (str, "identificationtypes") == 0)
+	  {
+	    infile >> n;
+	    for (i = 1; i <= n; i++)
+	      {
+		int type;
+		infile >> type;
+		ident -> SetType(i,Identifications::ID_TYPE(type));
+	      }
+	  }
+
+	if (strcmp (str, "materials") == 0)
+	  {
+	    infile >> n;
+	    for (i = 1; i <= n; i++)
+	      {
+		int nr;
+		string mat;
+		infile >> nr >> mat;
+		SetMaterial (nr, mat.c_str());
+	      }
+	  }
+
+	if ( strcmp (str, "bcnames" ) == 0 )
+	  {
+	    infile >> n;
+	    ARRAY<int,0> bcnrs(n);
+
+	    SetNBCNames(n);
+	    for ( i = 1; i <= n; i++ )
+	      {
+		string nextbcname;
+		infile >> bcnrs[i-1] >> nextbcname;
+		bcnames[bcnrs[i-1]-1] = new string(nextbcname);
+	      }
+	    
+	    if ( GetDimension() == 2 )
+	      {
+		for (i = 1; i <= GetNSeg(); i++)
+		  {
+		    Segment & seg = LineSegment (i);
+		    if ( seg.si <= n )
+		      seg.SetBCName (bcnames[seg.si-1]);
+		    else
+		      seg.SetBCName(0);
+		  }
+	      }
+	    else
+	      {
+		for (SurfaceElementIndex sei = 0; sei < GetNSE(); sei++)
+		  {
+		    if ((*this)[sei].GetIndex())
+		      {
+			int bcp = GetFaceDescriptor((*this)[sei].GetIndex ()).BCProperty();
+			if ( bcp <= n )
+			  GetFaceDescriptor((*this)[sei].GetIndex ()).SetBCName(bcnames[bcp-1]);
+			else
+			  GetFaceDescriptor((*this)[sei].GetIndex ()).SetBCName(0);
+
+		      }
+		  }
+
+	      }
+	    
+
+	  }
+	
+	if (strcmp (str, "singular_points") == 0)
+	  {
+	    infile >> n;
+	    for (i = 1; i <= n; i++)
+	      {
+		PointIndex pi;
+		double s; 
+		infile >> pi;
+		infile >> s; 
+		(*this)[pi].Singularity (s);
+	      }
+	  }
+
+	if (strcmp (str, "singular_edge_left") == 0)
+	  {
+	    infile >> n;
+	    for (i = 1; i <= n; i++)
+	      {
+		SegmentIndex si;
+		double s; 
+		infile >> si;
+		infile >> s; 
+		(*this)[si].singedge_left = s;
+	      }
+	  }
+	if (strcmp (str, "singular_edge_right") == 0)
+	  {
+	    infile >> n;
+	    for (i = 1; i <= n; i++)
+	      {
+		SegmentIndex si;
+		double s; 
+		infile >> si;
+		infile >> s; 
+		(*this)[si].singedge_right = s;
+	      }
+	  }
+
+	if (strcmp (str, "singular_face_inside") == 0)
+	  {
+	    infile >> n;
+	    for (i = 1; i <= n; i++)
+	      {
+		SurfaceElementIndex sei;
+		double s; 
+		infile >> sei;
+		infile >> s; 
+		GetFaceDescriptor((*this)[sei].GetIndex()).domin_singular = s;
+	      }
+	  }
+
+	if (strcmp (str, "singular_face_outside") == 0)
+	  {
+	    infile >> n;
+	    for (i = 1; i <= n; i++)
+	      {
+		SurfaceElementIndex sei;
+		double s; 
+		infile >> sei;
+		infile >> s; 
+		GetFaceDescriptor((*this)[sei].GetIndex()).domout_singular = s;
+	      }
+	  }
+
+	if (strcmp (str, "endmesh") == 0)
+	  endmesh = true;
+	  
+
+
+	strcpy (str, "");
+      }
+  
+    CalcSurfacesOfNode ();
+    //  BuildConnectedNodes ();
+    topology -> Update();
+    clusters -> Update();
+  
+    SetNextMajorTimeStamp();
+    //  PrintMemInfo (cout);
+
+
+#ifdef PARALLEL
+    if ( ntasks > 1 )
+      {
+	// for parallel processing
+	Distribute ();
+	return;
+      }
+#endif
+
+  }
+  
+
+  
+
+
+  void Mesh :: Merge (const string & filename, const int surfindex_offset)
+  {
+    ifstream infile(filename.c_str());
+    if (!infile.good())
+      throw NgException ("mesh file not found");
+
+    Merge(infile,surfindex_offset);
+
+  }
+
+
+
+  void Mesh :: Merge (istream & infile, const int surfindex_offset)
+  {
+    char str[100];
+    int i, n;
+
+    
+    int inverttets = 0;  // globflags.GetDefineFlag ("inverttets");
+
+    int oldnp = GetNP();
+    int oldne = GetNSeg();
+    int oldnd = GetNDomains();
+    
+    for(SurfaceElementIndex si = 0; si < GetNSE(); si++)
+      for(int j=1; j<=(*this)[si].GetNP(); j++) (*this)[si].GeomInfoPi(j).trignum = -1;
+    
+    int max_surfnr = 0;
+    for (i = 1; i <= GetNFD(); i++)
+      max_surfnr = max2 (max_surfnr, GetFaceDescriptor(i).SurfNr());
+    max_surfnr++;
+
+    if(max_surfnr < surfindex_offset) max_surfnr = surfindex_offset;
+
+
+    bool endmesh = false;
+
+    while (infile.good() && !endmesh)
+      {
+	infile >> str;
+
+	if (strcmp (str, "surfaceelementsgi") == 0)
+	  {
+	    infile >> n;
+	    PrintMessage (3, n, " surface elements");
+	    for (i = 1; i <= n; i++)
+	      {
+		int j;
+		int surfnr, bcp, domin, domout, nep, faceind = 0;
+		infile >> surfnr >> bcp >> domin >> domout;
+
+		surfnr--;
+
+		if(domin > 0) domin += oldnd;
+		if(domout > 0) domout += oldnd;
+		surfnr += max_surfnr;
+		
+		
+		for (j = 1; j <= facedecoding.Size(); j++)
+		  if (GetFaceDescriptor(j).SurfNr() == surfnr &&
+		      GetFaceDescriptor(j).BCProperty() == bcp &&
+		      GetFaceDescriptor(j).DomainIn() == domin &&
+		      GetFaceDescriptor(j).DomainOut() == domout)
+		    faceind = j;
+
+		if (!faceind)
+		  {
+		    faceind = AddFaceDescriptor (FaceDescriptor(surfnr, domin, domout, 0));
+		    if(GetDimension() == 2) bcp++;
+		    GetFaceDescriptor(faceind).SetBCProperty (bcp);
+		  }
+
+		infile >> nep;
+		if (!nep) nep = 3;
+
+		Element2d tri(nep);
+		tri.SetIndex(faceind);
+
+		for (j = 1; j <= nep; j++)
+		  {
+		    infile >> tri.PNum(j);
+		    tri.PNum(j) = tri.PNum(j) + oldnp;
+		  }
+
+		for (j = 1; j <= nep; j++)
+		  {
+		    infile >> tri.GeomInfoPi(j).trignum;
+		    tri.GeomInfoPi(j).trignum = -1;
+		  }
+
+		AddSurfaceElement (tri);
+	      }
+	  }
+
+	
+	if (strcmp (str, "edgesegments") == 0)
+	  {
+	    infile >> n;
+	    for (i = 1; i <= n; i++)
+	      {
+		Segment seg;
+		int hi;
+		infile >> seg.si >> hi >> seg.p1 >> seg.p2;
+		seg.p1 = seg.p1 + oldnp;
+		seg.p2 = seg.p2 + oldnp;
+		AddSegment (seg);
+	      }
+	  }
+      
+
+
+	if (strcmp (str, "edgesegmentsgi") == 0)
+	  {
+	    infile >> n;
+	    for (i = 1; i <= n; i++)
+	      {
+		Segment seg;
+		int hi;
+		infile >> seg.si >> hi >> seg.p1 >> seg.p2
+		       >> seg.geominfo[0].trignum
+		       >> seg.geominfo[1].trignum;
+		seg.p1 = seg.p1 + oldnp;
+		seg.p2 = seg.p2 + oldnp;
+		AddSegment (seg);
+	      }
+	  }
+	if (strcmp (str, "edgesegmentsgi2") == 0)
+	  {
+	    infile >> n;
+	    PrintMessage (3, n, " curve elements");
+
+	    for (i = 1; i <= n; i++)
+	      {
+		Segment seg;
+		int hi;
+		infile >> seg.si >> hi >> seg.p1 >> seg.p2
+		       >> seg.geominfo[0].trignum
+		       >> seg.geominfo[1].trignum
+		       >> seg.surfnr1 >> seg.surfnr2
+		       >> seg.edgenr
+		       >> seg.epgeominfo[0].dist
+		       >> seg.epgeominfo[1].edgenr
+		       >> seg.epgeominfo[1].dist;
+		seg.epgeominfo[0].edgenr = seg.epgeominfo[1].edgenr;
+
+		seg.surfnr1--;
+		seg.surfnr2--;
+
+		if(seg.surfnr1 >= 0)  seg.surfnr1 = seg.surfnr1 + max_surfnr;
+		if(seg.surfnr2 >= 0)  seg.surfnr2 = seg.surfnr2 + max_surfnr;
+		seg.p1 = seg.p1 +oldnp;
+		seg.p2 = seg.p2 +oldnp;
+		seg.edgenr = seg.edgenr + oldne;
+		seg.epgeominfo[1].edgenr = seg.epgeominfo[1].edgenr + oldne;
+
+		AddSegment (seg);
+	      }
+	  }
+ 
+	if (strcmp (str, "volumeelements") == 0)
+	  {
+	    infile >> n;
+	    PrintMessage (3, n, " volume elements");
+	    for (i = 1; i <= n; i++)
+	      {
+		Element el;
+		int hi, nep;
+		infile >> hi;
+		if (hi == 0) hi = 1;
+		el.SetIndex(hi+oldnd);
+		infile >> nep;
+		el.SetNP(nep);
+	      
+		for (int j = 0; j < nep; j++)
+		  {
+		    infile >> (int&)(el[j]);
+		    el[j] = el[j]+oldnp;
+		  }
+	      
+		if (inverttets)
+		  el.Invert();
+
+		AddVolumeElement (el);
+	      }
+	  }
+         
+
+	if (strcmp (str, "points") == 0)
+	  {
+	    infile >> n;
+	    PrintMessage (3, n, " points");
+	    for (i = 1; i <= n; i++)
+	      {
+		Point3d p;
+		infile >> p.X() >> p.Y() >> p.Z();
+		AddPoint (p);
+	      }
+	  }
+
+
+	if (strcmp (str, "endmesh") == 0)
+	  {
+	    endmesh = true;
+	  }
+
+
+	if (strcmp (str, "materials") == 0)
+	  {
+	    infile >> n;
+	    for (i = 1; i <= n; i++)
+	      {
+		int nr;
+		string mat;
+		infile >> nr >> mat;
+		SetMaterial (nr+oldnd, mat.c_str());
+	      }
+	  }
+
+
+	strcpy (str, "");
+      }
+  
+    CalcSurfacesOfNode ();
+
+    topology -> Update();
+    clusters -> Update();
+  
+    SetNextMajorTimeStamp();
+  }
+  
+
+
+
+
+
+
+
+   
+
+  bool Mesh :: TestOk () const
+  {
+    for (ElementIndex ei = 0; ei < volelements.Size(); ei++)
+      {
+	for (int j = 0; j < 4; j++)
+	  if ( (*this)[ei][j] <= PointIndex::BASE-1)
+	    {
+	      (*testout) << "El " << ei << " has 0 nodes: ";
+	      for (int k = 0; k < 4; k++)
+		(*testout) << (*this)[ei][k];
+	      break;
+	    }
+      }
+    CheckMesh3D (*this);
+    return 1;
+  }
+
+  void Mesh :: SetAllocSize(int nnodes, int nsegs, int nsel, int nel)
+  {
+    points.SetAllocSize(nnodes);
+    segments.SetAllocSize(nsegs);
+    surfelements.SetAllocSize(nsel);
+    volelements.SetAllocSize(nel);
+  }
+  
+
+  void Mesh :: BuildBoundaryEdges(void)
+  {
+    delete boundaryedges;
+
+    boundaryedges = new INDEX_2_CLOSED_HASHTABLE<int>
+      (3 * (GetNSE() + GetNOpenElements()) + GetNSeg() + 1);
+
+
+    for (SurfaceElementIndex sei = 0; sei < GetNSE(); sei++)
+      {
+	const Element2d & sel = surfelements[sei];
+	if (sel.IsDeleted()) continue;
+
+	int si = sel.GetIndex();
+      
+	for (int j = 0; j < sel.GetNP(); j++)
+	  {
+	    INDEX_2 i2;
+	    i2.I1() = sel.PNumMod(j+1);
+	    i2.I2() = sel.PNumMod(j+2);
+	    i2.Sort();
+	    if (sel.GetNP() <= 4)
+	      boundaryedges->Set (i2, 1);
+	  }
+      }
+
+
+    for (int i = 0; i < openelements.Size(); i++)
+      {
+	const Element2d & sel = openelements[i];
+	for (int j = 0; j < sel.GetNP(); j++)
+	  {
+	    INDEX_2 i2;
+	    i2.I1() = sel.PNumMod(j+1);
+	    i2.I2() = sel.PNumMod(j+2);
+	    i2.Sort();
+	    boundaryedges->Set (i2, 1);
+
+	    points[sel[j]].SetType(FIXEDPOINT);
+	  }
+      }
+
+    for (int i = 0; i < GetNSeg(); i++)
+      {
+	const Segment & seg = segments[i];
+	INDEX_2 i2(seg.p1, seg.p2);
+	i2.Sort();
+
+	boundaryedges -> Set (i2, 2);
+	//segmentht -> Set (i2, i);
+      }
+    
+    
+  }
+
+  void Mesh :: CalcSurfacesOfNode ()
+  {
+    int i, j, k;
+    SurfaceElementIndex sei;
+
+    surfacesonnode.SetSize (GetNP());
+
+    delete boundaryedges;
+    boundaryedges = NULL;
+
+    delete surfelementht;
+    delete segmentht;
+
+    /*
+      surfelementht = new INDEX_3_HASHTABLE<int> (GetNSE()/4 + 1);
+      segmentht = new INDEX_2_HASHTABLE<int> (GetNSeg() + 1);
+    */
+
+    surfelementht = new INDEX_3_CLOSED_HASHTABLE<int> (3*GetNSE() + 1);
+    segmentht = new INDEX_2_CLOSED_HASHTABLE<int> (3*GetNSeg() + 1);
+
+    for (sei = 0; sei < GetNSE(); sei++)
+      {
+	const Element2d & sel = surfelements[sei];
+	if (sel.IsDeleted()) continue;
+
+	int si = sel.GetIndex();
+      
+	for (j = 0; j < sel.GetNP(); j++)
+	  {
+	    PointIndex pi = sel[j];
+	    bool found = 0;
+	    for (k = 0; k < surfacesonnode[pi].Size(); k++)
+	      if (surfacesonnode[pi][k] == si)
+		{
+		  found = 1;
+		  break;
+		}
+	  
+	    if (!found)
+	      surfacesonnode.Add (pi, si);
+
+	  }
+      }
+    /*
+      for (sei = 0; sei < GetNSE(); sei++)
+      {
+      const Element2d & sel = surfelements[sei];
+      if (sel.IsDeleted()) continue;
+
+      INDEX_3 i3;
+      i3.I1() = sel.PNum(1);
+      i3.I2() = sel.PNum(2);
+      i3.I3() = sel.PNum(3);
+      i3.Sort();
+      surfelementht -> PrepareSet (i3);
+      }
+
+      surfelementht -> AllocateElements();
+    */
+    for (sei = 0; sei < GetNSE(); sei++)
+      {
+	const Element2d & sel = surfelements[sei];
+	if (sel.IsDeleted()) continue;
+
+	INDEX_3 i3;
+	i3.I1() = sel.PNum(1);
+	i3.I2() = sel.PNum(2);
+	i3.I3() = sel.PNum(3);
+	i3.Sort();
+	surfelementht -> Set (i3, sei);   // war das wichtig ???    sel.GetIndex());
+      }
+
+    int np = GetNP();
+
+    if (dimension == 3)
+      {
+        for (PointIndex pi = PointIndex::BASE; 
+             pi < np+PointIndex::BASE; pi++)
+          points[pi].SetType (INNERPOINT);
+        
+        if (GetNFD() == 0) 
+          {
+            for (sei = 0; sei < GetNSE(); sei++)
+              {
+                const Element2d & sel = surfelements[sei];
+                if (sel.IsDeleted()) continue;
+                for (j = 0;  j < sel.GetNP(); j++)
+                  {
+                    PointIndex pi = SurfaceElement(sei)[j];
+                    points[pi].SetType(FIXEDPOINT);
+                  }
+              }
+          }
+        else
+          {
+            for (sei = 0; sei < GetNSE(); sei++)
+              {
+                const Element2d & sel = surfelements[sei];
+                if (sel.IsDeleted()) continue;
+                for (j = 0; j < sel.GetNP(); j++)
+                  {
+                    PointIndex pi = sel[j];
+                    int ns = surfacesonnode[pi].Size();
+                    if (ns == 1)
+                      points[pi].SetType(SURFACEPOINT);
+                    if (ns == 2)
+                      points[pi].SetType(EDGEPOINT);
+                    if (ns >= 3)
+                      points[pi].SetType(FIXEDPOINT);
+                  }      
+              }
+          }
+
+    for (i = 0; i < segments.Size(); i++)
+      {
+	const Segment & seg = segments[i];
+	for (j = 1; j <= 2; j++)
+	  {
+	    PointIndex hi = (j == 1) ? seg.p1 : seg.p2;
+	  
+	    if (points[hi].Type() == INNERPOINT ||
+		points[hi].Type() == SURFACEPOINT)
+	      points[hi].SetType(EDGEPOINT);
+	  }
+      }
+
+
+    for (i = 0; i < lockedpoints.Size(); i++)
+      points[lockedpoints[i]].SetType(FIXEDPOINT);
+      }
+
+  
+    /*
+    for (i = 0; i < openelements.Size(); i++)
+      {
+	const Element2d & sel = openelements[i];
+	for (j = 0; j < sel.GetNP(); j++)
+	  {
+	    INDEX_2 i2;
+	    i2.I1() = sel.PNumMod(j+1);
+	    i2.I2() = sel.PNumMod(j+2);
+	    i2.Sort();
+	    boundaryedges->Set (i2, 1);
+
+	    points[sel[j]].SetType(FIXEDPOINT);
+	  }
+      }
+    */
+
+    // eltyps.SetSize (GetNE());
+    // eltyps = FREEELEMENT;
+
+    for (i = 0; i < GetNSeg(); i++)
+      {
+	const Segment & seg = segments[i];
+	INDEX_2 i2(seg.p1, seg.p2);
+	i2.Sort();
+
+	//boundaryedges -> Set (i2, 2);
+	segmentht -> Set (i2, i);
+      }
+  }
+
+
+  void Mesh :: FixPoints (const BitArray & fixpoints)
+  {
+    if (fixpoints.Size() != GetNP())
+      {
+	cerr << "Mesh::FixPoints: sizes don't fit" << endl;
+	return;
+      }
+    int np = GetNP();
+    for (int i = 1; i <= np; i++)
+      if (fixpoints.Test(i))
+	{
+	  points.Elem(i).SetType (FIXEDPOINT);
+	}
+  }
+
+
+  void Mesh :: FindOpenElements (int dom)
+  {
+    static int timer = NgProfiler::CreateTimer ("Mesh::FindOpenElements");
+    static int timera = NgProfiler::CreateTimer ("Mesh::FindOpenElements A");
+    static int timerb = NgProfiler::CreateTimer ("Mesh::FindOpenElements B");
+    static int timerc = NgProfiler::CreateTimer ("Mesh::FindOpenElements C");
+    static int timerd = NgProfiler::CreateTimer ("Mesh::FindOpenElements D");
+    static int timere = NgProfiler::CreateTimer ("Mesh::FindOpenElements E");
+
+    NgProfiler::RegionTimer reg (timer);
+
+    int np = GetNP();
+    int ne = GetNE();
+    int nse = GetNSE();
+    
+    ARRAY<int,PointIndex::BASE> numonpoint(np);
+
+    numonpoint = 0;
+
+    NgProfiler::StartTimer (timera);
+    for (ElementIndex ei = 0; ei < ne; ei++)
+      {
+	const Element & el = (*this)[ei];
+	if (dom == 0 || dom == el.GetIndex())
+	  {
+	    if (el.GetNP() == 4)
+	      {
+		INDEX_4 i4(el[0], el[1], el[2], el[3]);
+		i4.Sort();
+		numonpoint[i4.I1()]++;
+		numonpoint[i4.I2()]++;
+	      }
+	    else
+	      for (int j = 0; j < el.GetNP(); j++)
+		numonpoint[el[j]]++;
+	  }
+      }
+
+    TABLE<ElementIndex,PointIndex::BASE> elsonpoint(numonpoint);
+    for (ElementIndex ei = 0; ei < ne; ei++)
+      {
+	const Element & el = (*this)[ei];
+	if (dom == 0 || dom == el.GetIndex())
+	  {
+	    if (el.GetNP() == 4)
+	      {
+		INDEX_4 i4(el[0], el[1], el[2], el[3]);
+		i4.Sort();
+		elsonpoint.Add (i4.I1(), ei);
+		elsonpoint.Add (i4.I2(), ei);
+	      }
+	    else
+	      for (int j = 0; j < el.GetNP(); j++)
+		elsonpoint.Add (el[j], ei);
+	  }
+      }
+    NgProfiler::StopTimer (timera);
+
+
+
+
+    NgProfiler::StartTimer (timerb);	
+
+
+
+    ARRAY<char, 1> hasface(GetNFD());
+
+    int i;
+    for (i = 1; i <= GetNFD(); i++)
+      {
+	int domin = GetFaceDescriptor(i).DomainIn();
+	int domout = GetFaceDescriptor(i).DomainOut();
+	hasface[i] = 
+	  dom == 0 && (domin != 0 || domout != 0) ||
+	  dom != 0 && (domin == dom || domout == dom);
+      }
+
+    numonpoint = 0;
+    for (SurfaceElementIndex sii = 0; sii < nse; sii++)
+      {
+	int ind = surfelements[sii].GetIndex();
+	/*
+	  if (
+	  GetFaceDescriptor(ind).DomainIn() && 
+	  (dom == 0 || dom == GetFaceDescriptor(ind).DomainIn())
+	  ||
+	  GetFaceDescriptor(ind).DomainOut() && 
+	  (dom == 0 || dom == GetFaceDescriptor(ind).DomainOut())
+	  )
+	*/
+	if (hasface[ind])
+	  {
+	    /*
+	      Element2d hel = surfelements[i];
+	      hel.NormalizeNumbering();	  
+	      numonpoint[hel[0]]++;
+	    */
+	    const Element2d & hel = surfelements[sii];
+	    int mini = 0;
+	    for (int j = 1; j < hel.GetNP(); j++)
+	      if (hel[j] < hel[mini])
+		mini = j;
+	    numonpoint[hel[mini]]++;
+	  }
+      }
+
+    TABLE<SurfaceElementIndex,PointIndex::BASE> selsonpoint(numonpoint);
+    for (SurfaceElementIndex sii = 0; sii < nse; sii++)
+      {
+	int ind = surfelements[sii].GetIndex();
+
+	/*
+	  if (
+	  GetFaceDescriptor(ind).DomainIn() && 
+	  (dom == 0 || dom == GetFaceDescriptor(ind).DomainIn())
+	  ||
+	  GetFaceDescriptor(ind).DomainOut() && 
+	  (dom == 0 || dom == GetFaceDescriptor(ind).DomainOut())
+	  )
+	*/
+	if (hasface[ind])
+	  {
+	    /*
+	      Element2d hel = surfelements[i];
+	      hel.NormalizeNumbering();	  
+	      selsonpoint.Add (hel[0], i);
+	    */
+	    const Element2d & hel = surfelements[sii];
+	    int mini = 0;
+	    for (int j = 1; j < hel.GetNP(); j++)
+	      if (hel[j] < hel[mini])
+		mini = j;
+	    selsonpoint.Add (hel[mini], sii);
+	  }
+      }
+
+
+    NgProfiler::StopTimer (timerb);
+
+    int ii, j, k, l;
+    PointIndex pi;
+    SurfaceElementIndex sei;
+    Element2d hel;
+
+    NgProfiler::RegionTimer regc (timerc);
+
+
+    INDEX_3_CLOSED_HASHTABLE<INDEX_2> faceht(100);   
+    openelements.SetSize(0);
+      
+    for (pi = PointIndex::BASE; pi < np+PointIndex::BASE; pi++)
+      if (selsonpoint[pi].Size()+elsonpoint[pi].Size())
+	{
+	  faceht.SetSize (2 * selsonpoint[pi].Size() + 4 * elsonpoint[pi].Size());
+
+	  FlatArray<SurfaceElementIndex> row = selsonpoint[pi];
+	  for (ii = 0; ii < row.Size(); ii++)
+	    {
+	      hel = SurfaceElement(row[ii]);
+	      int ind = hel.GetIndex();	  
+  
+	      if (GetFaceDescriptor(ind).DomainIn() && 
+		  (dom == 0 || dom == GetFaceDescriptor(ind).DomainIn()) )
+		{
+		  hel.NormalizeNumbering();
+		  if (hel.PNum(1) == pi)
+		    {
+		      INDEX_3 i3(hel[0], hel[1], hel[2]);
+		      INDEX_2 i2 (GetFaceDescriptor(ind).DomainIn(), 
+				  (hel.GetNP() == 3) 
+				  ? PointIndex (PointIndex::BASE-1)
+				  : hel.PNum(4));
+		      faceht.Set (i3, i2);
+		    }
+		}
+	      if (GetFaceDescriptor(ind).DomainOut() &&
+		  (dom == 0 || dom == GetFaceDescriptor(ind).DomainOut()) )
+		{
+		  hel.Invert();
+		  hel.NormalizeNumbering();
+		  if (hel.PNum(1) == pi)
+		    {
+		      INDEX_3 i3(hel[0], hel[1], hel[2]);
+		      INDEX_2 i2 (GetFaceDescriptor(ind).DomainOut(), 
+				  (hel.GetNP() == 3) 
+				  ? PointIndex (PointIndex::BASE-1)
+				  : hel.PNum(4));
+		      faceht.Set (i3, i2);
+		    }
+		}
+	    }
+
+	  
+	  FlatArray<ElementIndex> rowel = elsonpoint[pi];
+	  for (ii = 0; ii < rowel.Size(); ii++)
+	    {
+	      const Element & el = VolumeElement(rowel[ii]);
+
+	      if (dom == 0 || el.GetIndex() == dom)
+		{
+		  for (j = 1; j <= el.GetNFaces(); j++)
+		    {
+		      el.GetFace (j, hel);
+		      hel.Invert();
+		      hel.NormalizeNumbering();
+
+		      if (hel[0] == pi)
+			{
+			  INDEX_3 i3(hel[0], hel[1], hel[2]);
+			  
+			  if (faceht.Used (i3))
+			    {
+			      INDEX_2 i2 = faceht.Get(i3);
+			      if (i2.I1() == el.GetIndex())
+				{
+				  i2.I1() = PointIndex::BASE-1;
+				  faceht.Set (i3, i2);
+				}
+			      else
+				{
+				  if (i2.I1() == 0)
+				    {
+				      PrintSysError ("more elements on face");
+				      (*testout)  << "more elements on face!!!" << endl;
+				      (*testout) << "el = " << el << endl;
+				      (*testout) << "hel = " << hel << endl;
+				      (*testout) << "face = " << i3 << endl;
+				      (*testout) << "points = " << endl;
+				      for (int jj = 1; jj <= 3; jj++)
+					(*testout) << "p = " << Point(i3.I(jj)) << endl;
+				    }
+				}
+			    }
+			  else
+			    {
+			      hel.Invert();
+			      hel.NormalizeNumbering();
+			      INDEX_3 i3(hel[0], hel[1], hel[2]);
+			      INDEX_2 i2(el.GetIndex(), 
+					 (hel.GetNP() == 3) 
+					 ? PointIndex (PointIndex::BASE-1)
+					 : hel[3]);
+			      faceht.Set (i3, i2);
+			    }
+			}
+		    }
+		}
+	    }
+	  for (i = 0; i < faceht.Size(); i++)
+	    if (faceht.UsedPos (i))
+	      {
+		INDEX_3 i3;
+		INDEX_2 i2;
+		faceht.GetData (i, i3, i2);
+		if (i2.I1() != PointIndex::BASE-1)
+		  {
+		    Element2d tri;
+		    tri.SetType ( (i2.I2() == PointIndex::BASE-1) ? TRIG : QUAD);
+		    for (l = 0; l < 3; l++)
+		      tri[l] = i3.I(l+1);
+		    tri.PNum(4) = i2.I2();
+		    tri.SetIndex (i2.I1());
+
+		    //	tri.Invert();
+		    
+		    openelements.Append (tri);
+		  }
+	      }
+	}
+
+    int cnt3 = 0;
+    for (i = 0; i < openelements.Size(); i++)
+      if (openelements[i].GetNP() == 3)
+	cnt3++;
+
+    int cnt4 = openelements.Size() - cnt3;
+
+
+    MyStr treequad;
+    if (cnt4)
+      treequad = MyStr(" (") + MyStr(cnt3) + MyStr (" + ") + 
+	MyStr(cnt4) + MyStr(")");
+
+    PrintMessage (5, openelements.Size(), treequad, " open elements");
+
+    BuildBoundaryEdges();
+
+
+    NgProfiler::RegionTimer regd (timerd);
+
+    for (i = 1; i <= openelements.Size(); i++)
+      {
+	const Element2d & sel = openelements.Get(i);
+
+	if (boundaryedges)
+	  for (j = 1; j <= sel.GetNP(); j++)
+	    {
+	      INDEX_2 i2;
+	      i2.I1() = sel.PNumMod(j);
+	      i2.I2() = sel.PNumMod(j+1);
+	      i2.Sort();
+	      boundaryedges->Set (i2, 1);
+	    }
+      
+	for (j = 1; j <= 3; j++)
+	  {
+	    int pi = sel.PNum(j);
+	    if (pi < points.Size()+PointIndex::BASE)
+	      points[pi].SetType (FIXEDPOINT);
+	  }
+      }
+
+
+    NgProfiler::RegionTimer rege (timere);
+
+    /*
+      for (i = 1; i <= GetNSeg(); i++)
+      {
+      const Segment & seg = LineSegment(i);
+      INDEX_2 i2(seg.p1, seg.p2);
+      i2.Sort();
+
+      if (!boundaryedges->Used (i2))
+      cerr << "WARNING: no boundedge, but seg edge: " << i2 << endl;
+
+      boundaryedges -> Set (i2, 2);
+      segmentht -> Set (i2, i-1);
+      }
+    */
+  }
+
+  bool Mesh :: HasOpenQuads () const
+  {
+    int no = GetNOpenElements();
+    for (int i = 0; i < no; i++)
+      if (openelements[i].GetNP() == 4)
+	return true;
+    return false;
+  }
+
+
+
+
+
+  void Mesh :: FindOpenSegments (int surfnr)
+  {
+    int i, j, k;
+
+    // new version, general elemetns
+    // hash index: pnum1-2
+    // hash data : surfnr,  surfel-nr (pos) or segment nr(neg)
+    INDEX_2_HASHTABLE<INDEX_2> faceht(4 * GetNSE()+GetNSeg()+1);   
+  
+    PrintMessage (5, "Test Opensegments");
+    for (i = 1; i <= GetNSeg(); i++)
+      {
+	const Segment & seg = LineSegment (i);
+
+	if (surfnr == 0 || seg.si == surfnr)
+	  {
+	    INDEX_2 key(seg.p1, seg.p2);
+	    INDEX_2 data(seg.si, -i);
+
+	    if (faceht.Used (key))
+	      {
+		cerr << "ERROR: Segment " << seg << " already used" << endl;
+		(*testout) << "ERROR: Segment " << seg << " already used" << endl;
+	      }
+
+	    faceht.Set (key, data);
+	  }
+      }
+
+
+    for (i = 1; i <= GetNSeg(); i++)
+      {
+	const Segment & seg = LineSegment (i);
+
+	if (surfnr == 0 || seg.si == surfnr)
+	  {
+	    INDEX_2 key(seg.p2, seg.p1);
+	    if (!faceht.Used(key))
+	      {
+		cerr << "ERROR: Segment " << seg << " brother not used" << endl;
+		(*testout) << "ERROR: Segment " << seg << " brother not used" << endl;
+	      }
+	  }
+      }
+
+
+    for (i = 1; i <= GetNSE(); i++)
+      {
+	const Element2d & el = SurfaceElement(i);
+	if (el.IsDeleted()) continue;
+
+	if (surfnr == 0 || el.GetIndex() == surfnr)
+	  {
+	    for (j = 1; j <= el.GetNP(); j++)
+	      {
+		INDEX_2 seg (el.PNumMod(j), el.PNumMod(j+1));
+		INDEX_2 data;
+
+		if (seg.I1() <= 0 || seg.I2() <= 0)
+		  cerr << "seg = " << seg << endl;
+
+		if (faceht.Used(seg))
+		  {
+		    data = faceht.Get(seg);
+		    if (data.I1() == el.GetIndex())
+		      {
+			data.I1() = 0;
+			faceht.Set (seg, data);
+		      }
+		    else
+		      {
+			PrintSysError ("hash table si not fitting for segment: ",
+				       seg.I1(), "-", seg.I2(), " other = ",
+				       data.I2());
+		      }
+		  }
+		else
+		  {
+		    Swap (seg.I1(), seg.I2());
+		    data.I1() = el.GetIndex();
+		    data.I2() = i;
+
+		    faceht.Set (seg, data);
+		  }
+	      }
+	  }
+      }  
+
+    (*testout) << "open segments: " << endl;
+    opensegments.SetSize(0);
+    for (i = 1; i <= faceht.GetNBags(); i++)
+      for (j = 1; j <= faceht.GetBagSize(i); j++)
+	{
+	  INDEX_2 i2;
+	  INDEX_2 data;
+	  faceht.GetData (i, j, i2, data);
+	  if (data.I1())  // surfnr
+	    {
+	      Segment seg;
+	      seg.p1 = i2.I1();
+	      seg.p2 = i2.I2();
+	      seg.si = data.I1();
+
+	      // find geomdata:
+	      if (data.I2() > 0)
+		{
+		  // segment due to triangle
+		  const Element2d & el = SurfaceElement (data.I2());
+		  for (k = 1; k <= el.GetNP(); k++)
+		    {
+		      if (seg.p1 == el.PNum(k))
+			seg.geominfo[0] = el.GeomInfoPi(k);
+		      if (seg.p2 == el.PNum(k))
+			seg.geominfo[1] = el.GeomInfoPi(k);
+		    }
+
+		  (*testout) << "trig seg: ";
+		}
+	      else
+		{
+		  // segment due to line
+		  const Segment & lseg = LineSegment (-data.I2());
+		  seg.geominfo[0] = lseg.geominfo[0];
+		  seg.geominfo[1] = lseg.geominfo[1];
+
+		  (*testout) << "line seg: ";
+		}
+	    
+	      (*testout) << seg.p1 << " - " << seg.p2 
+			 << " len = " << Dist (Point(seg.p1), Point(seg.p2))
+			 << endl;
+
+	      opensegments.Append (seg);
+	      if (seg.geominfo[0].trignum <= 0 || seg.geominfo[1].trignum <= 0)
+		{
+		  (*testout) << "Problem with open segment: " << seg << endl;
+		}
+
+	    }
+	}
+
+    PrintMessage (3, opensegments.Size(), " open segments found");
+    (*testout) << opensegments.Size() << " open segments found" << endl;
+  
+    /*
+      ptyps.SetSize (GetNP());
+      for (i = 1; i <= ptyps.Size(); i++)
+      ptyps.Elem(i) = SURFACEPOINT;
+
+      for (i = 1; i <= GetNSeg(); i++)
+      {
+      const Segment & seg = LineSegment (i);
+      ptyps.Elem(seg.p1) = EDGEPOINT;
+      ptyps.Elem(seg.p2) = EDGEPOINT;
+      }
+      for (i = 1; i <= GetNOpenSegments(); i++)
+      {
+      const Segment & seg = GetOpenSegment (i);
+      ptyps.Elem(seg.p1) = EDGEPOINT;
+      ptyps.Elem(seg.p2) = EDGEPOINT;
+      }
+    */
+    for (i = 1; i <= points.Size(); i++)
+      points.Elem(i).SetType(SURFACEPOINT);
+
+    for (i = 1; i <= GetNSeg(); i++)
+      {
+	const Segment & seg = LineSegment (i);
+	points[seg.p1].SetType(EDGEPOINT);
+	points[seg.p2].SetType(EDGEPOINT);
+      }
+    for (i = 1; i <= GetNOpenSegments(); i++)
+      {
+	const Segment & seg = GetOpenSegment (i);
+	points[seg.p1].SetType (EDGEPOINT);
+	points[seg.p2].SetType (EDGEPOINT);
+      }
+  
+  
+  
+    /*
+
+    for (i = 1; i <= openelements.Size(); i++)
+    {
+    const Element2d & sel = openelements.Get(i);
+
+    if (boundaryedges)
+    for (j = 1; j <= sel.GetNP(); j++)
+    {
+    INDEX_2 i2;
+    i2.I1() = sel.PNumMod(j);
+    i2.I2() = sel.PNumMod(j+1);
+    i2.Sort();
+    boundaryedges->Set (i2, 1);
+    }
+      
+    for (j = 1; j <= 3; j++)
+    {
+    int pi = sel.PNum(j);
+    if (pi <= ptyps.Size())
+    ptyps.Elem(pi) = FIXEDPOINT;
+    }
+    }
+    */
+  }
+
+
+  void Mesh :: RemoveOneLayerSurfaceElements ()
+  {
+    int i, j;
+    int np = GetNP();
+
+    FindOpenSegments();
+    BitArray frontpoints(np);
+
+    frontpoints.Clear();
+    for (i = 1; i <= GetNOpenSegments(); i++)
+      {
+	const Segment & seg = GetOpenSegment(i);
+	frontpoints.Set (seg.p1);
+	frontpoints.Set (seg.p2);
+      }
+
+    for (i = 1; i <= GetNSE(); i++)
+      {
+	Element2d & sel = surfelements.Elem(i);
+	int remove = 0;
+	for (j = 1; j <= sel.GetNP(); j++)
+	  if (frontpoints.Test(sel.PNum(j)))
+	    remove = 1;
+	if (remove)
+	  sel.PNum(1) = 0;
+      }
+
+    for (i = surfelements.Size(); i >= 1; i--)
+      {
+	if (surfelements.Elem(i).PNum(1) == 0)
+	  {
+	    surfelements.Elem(i) = surfelements.Last();
+	    surfelements.DeleteLast();
+	  }
+      }
+
+    for (int i = 0; i < facedecoding.Size(); i++)
+      facedecoding[i].firstelement = -1;
+    for (int i = surfelements.Size()-1; i >= 0; i--)
+      {
+        int ind = surfelements[i].GetIndex();
+        surfelements[i].next = facedecoding[ind-1].firstelement;
+        facedecoding[ind-1].firstelement = i;
+      }
+
+
+    timestamp = NextTimeStamp();
+    //  Compress();
+  }
+
+
+
+
+
+  void Mesh :: FreeOpenElementsEnvironment (int layers)
+  {
+    int i, j, k;
+    PointIndex pi;
+    const int large = 9999;
+    ARRAY<int,PointIndex::BASE> dist(GetNP());
+
+    dist = large;
+
+    for (int i = 1; i <= GetNOpenElements(); i++)
+      {
+	const Element2d & face = OpenElement(i);
+	for (j = 0; j < face.GetNP(); j++)
+	  dist[face[j]] = 1;
+      }
+
+    for (k = 1; k <= layers; k++)
+      for (i = 1; i <= GetNE(); i++)
+	{
+	  const Element & el = VolumeElement(i);
+	  if (el[0] == -1 || el.IsDeleted()) continue;
+
+	  int elmin = large;
+	  for (j = 0; j < el.GetNP(); j++)
+	    if (dist[el[j]] < elmin)
+	      elmin = dist[el[j]];
+
+	  if (elmin < large)
+	    {
+	      for (j = 0; j < el.GetNP(); j++)
+		if (dist[el[j]] > elmin+1)
+		  dist[el[j]] = elmin+1;
+	    }
+	}
+
+    int cntfree = 0;
+    for (i = 1; i <= GetNE(); i++)
+      {
+	Element & el = VolumeElement(i);
+	if (el[0] == -1 || el.IsDeleted()) continue;
+	
+	int elmin = large;
+	for (j = 0; j < el.GetNP(); j++)
+	  if (dist[el[j]] < elmin)
+	    elmin = dist[el[j]];
+      
+        el.flags.fixed = elmin > layers;
+	// eltyps.Elem(i) = (elmin <= layers) ? 
+        // FREEELEMENT : FIXEDELEMENT;
+	if (elmin <= layers)
+	  cntfree++;
+      }
+
+    PrintMessage (5, "free: ", cntfree, ", fixed: ", GetNE()-cntfree);
+    (*testout) << "free: " << cntfree << ", fixed: " << GetNE()-cntfree << endl;
+
+    for (pi = PointIndex::BASE; 
+	 pi < GetNP()+PointIndex::BASE; pi++)
+      {
+	if (dist[pi] > layers+1)
+	  points[pi].SetType(FIXEDPOINT);
+      }
+  }
+
+
+
+  void Mesh :: SetLocalH (const Point3d & pmin, const Point3d & pmax, double grading)
+  {
+    Point3d c = Center (pmin, pmax);
+    double d = max3 (pmax.X()-pmin.X(),
+		     pmax.Y()-pmin.Y(),
+		     pmax.Z()-pmin.Z());
+    d /= 2;
+    Point3d pmin2 = c - Vec3d (d, d, d);
+    Point3d pmax2 = c + Vec3d (d, d, d);
+  
+
+    delete lochfunc;
+    lochfunc = new LocalH (pmin2, pmax2, grading);
+  }
+
+  void Mesh :: RestrictLocalH (const Point3d & p, double hloc)
+  {
+    if(hloc < hmin)
+      hloc = hmin;
+
+    //cout << "restrict h in " << p << " to " << hloc << endl;
+    if (!lochfunc)
+      {
+	PrintWarning("RestrictLocalH called, creating mesh-size tree");
+
+	Point3d boxmin, boxmax;
+	GetBox (boxmin, boxmax);
+	SetLocalH (boxmin, boxmax, 0.8);
+      }
+
+    lochfunc -> SetH (p, hloc);
+  }
+
+  void Mesh :: RestrictLocalHLine (const Point3d & p1, 
+				   const Point3d & p2,
+				   double hloc)
+  {
+    if(hloc < hmin)
+      hloc = hmin;
+
+    // cout << "restrict h along " << p1 << " - " << p2 << " to " << hloc << endl;
+    int i;
+    int steps = int (Dist (p1, p2) / hloc) + 2;
+    Vec3d v(p1, p2);
+  
+    for (i = 0; i <= steps; i++)
+      {
+	Point3d p = p1 + (double(i)/double(steps) * v);
+	RestrictLocalH (p, hloc);
+      }
+  }
+
+
+  void Mesh :: SetMinimalH (double h)
+  {
+    hmin = h;
+  }
+
+
+  void Mesh :: SetGlobalH (double h)
+  {
+    hglob = h;
+  }
+
+  double Mesh :: MaxHDomain (int dom) const
+  {
+    if (maxhdomain.Size())
+      return maxhdomain.Get(dom);
+    else
+      return 1e10;
+  }
+
+  void Mesh :: SetMaxHDomain (const ARRAY<double> & mhd)
+  {
+    maxhdomain.SetSize(mhd.Size());
+    for (int i = 1; i <= mhd.Size(); i++)
+      maxhdomain.Elem(i) = mhd.Get(i);
+  }
+
+
+  double Mesh :: GetH (const Point3d & p) const
+  {
+    double hmin = hglob;
+    if (lochfunc)
+      {
+	double hl = lochfunc->GetH (p);
+	if (hl < hglob)
+	  hmin = hl;
+      }
+    return hmin;
+  }
+
+  double Mesh :: GetMinH (const Point3d & pmin, const Point3d & pmax)
+  {
+    double hmin = hglob;
+    if (lochfunc)
+      {
+	double hl = lochfunc->GetMinH (pmin, pmax);
+	if (hl < hmin)
+	  hmin = hl;
+      }
+    return hmin;
+  }
+
+
+
+
+
+  double Mesh :: AverageH (int surfnr) const
+  {
+    int i, j, n;
+    double hi, hsum;
+    double maxh = 0, minh = 1e10;
+
+    hsum = 0;
+    n = 0;
+    for (i = 1; i <= GetNSE(); i++)
+      {
+	const Element2d & el = SurfaceElement(i);
+	if (surfnr == 0 || el.GetIndex() == surfnr)
+	  {
+	    for (j = 1; j <= 3; j++)
+	      {
+		hi = Dist (Point (el.PNumMod(j)), 
+			   Point (el.PNumMod(j+1)));
+
+		hsum += hi;
+
+		if (hi > maxh) maxh = hi;
+		if (hi < minh) minh = hi;
+		n++;
+	      }
+	  }
+      }
+
+    PrintMessage (5, "minh = ", minh, " avh = ", (hsum/n), " maxh = ", maxh);
+    return (hsum / n);
+  }
+
+
+
+  void Mesh :: CalcLocalH () 
+  {
+    if (!lochfunc)
+      {
+	Point3d pmin, pmax;
+	GetBox (pmin, pmax);
+	SetLocalH (pmin, pmax, mparam.grading);
+      }
+
+    PrintMessage (3,
+		  "CalcLocalH: ", 
+		  GetNP(), " Points ", 
+		  GetNE(), " Elements ", 
+		  GetNSE(), " Surface Elements");
+
+
+    int i;
+    for (i = 0; i < GetNSE(); i++)
+      {
+	const Element2d & el = surfelements[i];
+	int j;
+
+	if (el.GetNP() == 3)
+	  {
+	    double hel = -1;
+	    for (j = 1; j <= 3; j++)
+	      {
+		const Point3d & p1 = points[el.PNumMod(j)];
+		const Point3d & p2 = points[el.PNumMod(j+1)];
+	      
+		/*
+		  INDEX_2 i21(el.PNumMod(j), el.PNumMod(j+1));
+		  INDEX_2 i22(el.PNumMod(j+1), el.PNumMod(j));
+		  if (! identifiedpoints->Used (i21) &&
+		  ! identifiedpoints->Used (i22) )
+		*/
+		if (!ident -> UsedSymmetric (el.PNumMod(j),
+					     el.PNumMod(j+1)))
+		  {
+		    double hedge = Dist (p1, p2);
+		    if (hedge > hel)
+		      hel = hedge;
+		    //		  lochfunc->SetH (Center (p1, p2), 2 * Dist (p1, p2));
+		    //		  (*testout) << "trigseth, p1,2 = " << el.PNumMod(j) << ", " << el.PNumMod(j+1) 
+		    //			     << " h = " << (2 * Dist(p1, p2)) << endl;
+		  }
+	      }
+	  
+	    if (hel > 0)
+	      {
+		const Point3d & p1 = points[el.PNum(1)];
+		const Point3d & p2 = points[el.PNum(2)];
+		const Point3d & p3 = points[el.PNum(3)];
+		lochfunc->SetH (Center (p1, p2, p3), hel);
+	      }
+	  }
+	else
+	  {
+	    {
+	      const Point3d & p1 = points[el.PNum(1)];
+	      const Point3d & p2 = points[el.PNum(2)];
+	      lochfunc->SetH (Center (p1, p2), 2 * Dist (p1, p2));
+	    }
+	    {
+	      const Point3d & p1 = points[el.PNum(3)];
+	      const Point3d & p2 = points[el.PNum(4)];
+	      lochfunc->SetH (Center (p1, p2), 2 * Dist (p1, p2));
+	    }
+	  }
+      }
+
+    for (i = 0; i < GetNSeg(); i++)
+      {
+	const Segment & seg = segments[i];
+	const Point3d & p1 = points[seg.p1];
+	const Point3d & p2 = points[seg.p2];
+	/*
+	  INDEX_2 i21(seg.p1, seg.p2);
+	  INDEX_2 i22(seg.p2, seg.p1);
+	  if (identifiedpoints)
+	  if (!identifiedpoints->Used (i21) && !identifiedpoints->Used (i22))
+	*/
+	if (!ident -> UsedSymmetric (seg.p1, seg.p2))
+	  {
+	    lochfunc->SetH (Center (p1, p2), Dist (p1, p2));
+	  }
+      }
+    /*
+      cerr << "do vol" << endl;
+      for (i = 1; i <= GetNE(); i++)
+      {
+      const Element & el = VolumeElement(i);
+      if (el.GetType() == TET)
+      {
+      int j, k;
+      for (j = 2; j <= 4; j++)
+      for (k = 1; k < j; k++)  
+      {
+      const Point3d & p1 = Point (el.PNum(j));
+      const Point3d & p2 = Point (el.PNum(k));
+      lochfunc->SetH (Center (p1, p2), 2 * Dist (p1, p2));
+      (*testout) << "set vol h to " << (2 * Dist (p1, p2)) << endl;
+
+      }
+      }
+      }
+    */
+
+    /*
+      const char * meshsizefilename = 
+      globflags.GetStringFlag ("meshsize", NULL);
+      if (meshsizefilename)
+      {
+      ifstream msf(meshsizefilename);
+      if (msf)
+      {
+      int nmsp;
+      msf >> nmsp;
+      for (i = 1; i <= nmsp; i++)
+      {
+      Point3d pi;
+      double hi;
+      msf >> pi.X() >> pi.Y() >> pi.Z();
+      msf >> hi;
+      lochfunc->SetH (pi, hi);
+      }
+      }
+      }
+    */
+    //  lochfunc -> Convexify();
+    //  lochfunc -> PrintMemInfo (cout);
+  }
+
+
+  void Mesh :: CalcLocalHFromPointDistances(void)
+  {
+    PrintMessage (3, "Calculating local h from point distances");
+  
+    if (!lochfunc)
+      {
+	Point3d pmin, pmax;
+	GetBox (pmin, pmax);
+      
+	SetLocalH (pmin, pmax, mparam.grading);
+      }
+
+    PointIndex i,j;
+    double hl;
+
+  
+    for (i = PointIndex::BASE; 
+	 i < GetNP()+PointIndex::BASE; i++)
+      {
+	for(j=i+1; j<GetNP()+PointIndex::BASE; j++)
+	  {
+	    const Point3d & p1 = points[i];
+	    const Point3d & p2 = points[j];
+	    hl = Dist(p1,p2);
+	    RestrictLocalH(p1,hl);
+	    RestrictLocalH(p2,hl);
+	    //cout << "restricted h at " << p1 << " and " << p2 << " to " << hl << endl;
+	  }
+      }
+  
+
+  }
+
+
+  void Mesh :: CalcLocalHFromSurfaceCurvature (double elperr) 
+  {
+    PrintMessage (3, "Calculating local h from surface curvature");
+
+    if (!lochfunc)
+      {
+	Point3d pmin, pmax;
+	GetBox (pmin, pmax);
+      
+	SetLocalH (pmin, pmax, mparam.grading);
+      }
+
+  
+    INDEX_2_HASHTABLE<int> edges(3 * GetNP() + 2);
+    INDEX_2_HASHTABLE<int> bedges(GetNSeg() + 2);
+    int i, j;
+
+    for (i = 1; i <= GetNSeg(); i++)
+      {
+	const Segment & seg = LineSegment(i);
+	INDEX_2 i2(seg.p1, seg.p2);
+	i2.Sort();
+	bedges.Set (i2, 1);
+      }
+    for (i = 1; i <= GetNSE(); i++)
+      {
+	const Element2d & sel = SurfaceElement(i);
+	if (!sel.PNum(1))
+	  continue;
+	for (j = 1; j <= 3; j++)
+	  {
+	    INDEX_2 i2(sel.PNumMod(j), sel.PNumMod(j+1));
+	    i2.Sort();
+	    if (bedges.Used(i2)) continue;
+
+	    if (edges.Used(i2))
+	      {
+		int other = edges.Get(i2);
+
+		const Element2d & elother = SurfaceElement(other);
+
+		int pi3 = 1;
+		while ( (sel.PNum(pi3) == i2.I1()) || 
+			(sel.PNum(pi3) == i2.I2()))
+		  pi3++;
+		pi3 = sel.PNum(pi3);
+
+		int pi4 = 1;
+		while ( (elother.PNum(pi4) == i2.I1()) || 
+			(elother.PNum(pi4) == i2.I2()))
+		  pi4++;
+		pi4 = elother.PNum(pi4);
+
+		double rad = ComputeCylinderRadius (Point (i2.I1()),
+						    Point (i2.I2()),
+						    Point (pi3), 
+						    Point (pi4));
+	      
+		RestrictLocalHLine (Point(i2.I1()), Point(i2.I2()), rad/elperr);
+
+
+		/*	      
+		  (*testout) << "pi1,2, 3, 4 = " << i2.I1() << ", " << i2.I2() << ", " << pi3 << ", " << pi4
+		  << " p1 = " << Point(i2.I1()) 
+		  << ", p2 = " << Point(i2.I2()) 
+		  //			 << ", p3 = " << Point(pi3) 
+		  //			 << ", p4 = " << Point(pi4) 
+		  << ", rad = " << rad << endl;
+		*/
+	      }
+	    else
+	      edges.Set (i2, i);
+	  }
+      }
+
+
+    // Restrict h due to line segments
+
+    for (i = 1; i <= GetNSeg(); i++)
+      {
+	const Segment & seg = LineSegment(i);
+	const Point3d & p1 = Point(seg.p1);
+	const Point3d & p2 = Point(seg.p2);
+	RestrictLocalH (Center (p1, p2),  Dist (p1, p2));
+      }
+
+
+
+    /*
+
+
+    int i, j;
+    int np = GetNP();
+    int nseg = GetNSeg();
+    int nse = GetNSE();
+  
+    ARRAY<Vec3d> normals(np);
+    BitArray linepoint(np);
+
+    linepoint.Clear();
+    for (i = 1; i <= nseg; i++)
+    {
+    linepoint.Set (LineSegment(i).p1);
+    linepoint.Set (LineSegment(i).p2);
+    }
+
+    for (i = 1; i <= np; i++)
+    normals.Elem(i) = Vec3d(0,0,0);
+
+    for (i = 1; i <= nse; i++)
+    {
+    Element2d & el = SurfaceElement(i);
+    Vec3d nf = Cross (Vec3d (Point (el.PNum(1)), Point(el.PNum(2))),
+    Vec3d (Point (el.PNum(1)), Point(el.PNum(3))));
+    for (j = 1; j <= 3; j++)
+    normals.Elem(el.PNum(j)) += nf;
+    }
+
+    for (i = 1; i <= np; i++)
+    normals.Elem(i) /= (1e-12 + normals.Elem(i).Length());
+
+    for (i = 1; i <= nse; i++)
+    {
+    Element2d & el = SurfaceElement(i);
+    Vec3d nf = Cross (Vec3d (Point (el.PNum(1)), Point(el.PNum(2))),
+    Vec3d (Point (el.PNum(1)), Point(el.PNum(3))));
+    nf /= nf.Length();
+    Point3d c = Center (Point(el.PNum(1)),
+    Point(el.PNum(2)),
+    Point(el.PNum(3)));
+			  
+    for (j = 1; j <= 3; j++)
+    {
+    if (!linepoint.Test (el.PNum(j)))
+    {
+    double dist = Dist (c, Point(el.PNum(j)));
+    double dn = (nf - normals.Get(el.PNum(j))).Length();
+	  
+    RestrictLocalH (Point(el.PNum(j)), dist / (dn+1e-12) /elperr);
+    }
+    }
+    }
+    */
+  }
+
+
+  void Mesh :: RestrictLocalH (resthtype rht, int nr, double loch)
+  {
+    int i;
+    switch (rht)
+      {
+      case RESTRICTH_FACE:
+	{
+	  for (i = 1; i <= GetNSE(); i++)
+	    {
+	      const Element2d & sel = SurfaceElement(i);
+	      if (sel.GetIndex() == nr)
+		RestrictLocalH (RESTRICTH_SURFACEELEMENT, i, loch);
+	    }
+	  break;
+	}
+      case RESTRICTH_EDGE:
+	{
+	  for (i = 1; i <= GetNSeg(); i++)
+	    {
+	      const Segment & seg = LineSegment(i);
+	      if (seg.edgenr == nr)
+		RestrictLocalH (RESTRICTH_SEGMENT, i, loch);
+	    }
+	  break;
+	}
+      case RESTRICTH_POINT:
+	{
+	  RestrictLocalH (Point (nr), loch);
+	  break;
+	}
+
+      case RESTRICTH_SURFACEELEMENT:
+	{
+	  const Element2d & sel = SurfaceElement(nr);
+	  Point3d p = Center (Point(sel.PNum(1)),
+			      Point(sel.PNum(2)),
+			      Point(sel.PNum(3)));
+	  RestrictLocalH (p, loch);
+	  break;
+	}
+      case RESTRICTH_SEGMENT:
+	{
+	  const Segment & seg = LineSegment(nr);
+	  RestrictLocalHLine (Point (seg.p1), Point(seg.p2), loch);
+	  break;
+	}
+      }
+  }
+
+
+  void Mesh :: LoadLocalMeshSize (const char * meshsizefilename)
+  {
+    if (!meshsizefilename) return;
+
+    ifstream msf(meshsizefilename);
+
+    if (!msf) return;
+
+    PrintMessage (3, "Load local mesh-size");
+    int nmsp, nmsl;
+    msf >> nmsp;
+    for (int i = 0; i < nmsp; i++)
+      {
+	Point3d pi;
+	double hi;
+	msf >> pi.X() >> pi.Y() >> pi.Z();
+	msf >> hi;
+	if (!msf.good())
+	  throw NgException ("problem in mesh-size file\n");
+	RestrictLocalH (pi, hi);
+      }
+    msf >> nmsl;
+    for (int i = 0; i < nmsl; i++)
+      {
+	Point3d p1, p2;
+	double hi;
+	msf >> p1.X() >> p1.Y() >> p1.Z();
+	msf >> p2.X() >> p2.Y() >> p2.Z();
+	msf >> hi;
+	if (!msf.good())
+	  throw NgException ("problem in mesh-size file\n");
+	RestrictLocalHLine (p1, p2, hi);
+      }  
+  }
+
+
+
+  void Mesh :: GetBox (Point3d & pmin, Point3d & pmax, int dom) const
+  {
+    if (points.Size() == 0)
+      {
+	pmin = pmax = Point3d(0,0,0);
+	return;
+      }
+
+    if (dom <= 0)
+      {
+	pmin = Point3d (1e10, 1e10, 1e10);
+	pmax = Point3d (-1e10, -1e10, -1e10); 
+
+	for (PointIndex pi = PointIndex::BASE; 
+	     pi < GetNP()+PointIndex::BASE; pi++)
+	  {
+	    pmin.SetToMin ( (*this) [pi] );
+	    pmax.SetToMax ( (*this) [pi] );
+	  }
+      }
+    else
+      {
+	int j, nse = GetNSE();
+	SurfaceElementIndex sei;
+
+	pmin = Point3d (1e10, 1e10, 1e10);
+	pmax = Point3d (-1e10, -1e10, -1e10); 
+	for (sei = 0; sei < nse; sei++)
+	  {
+	    const Element2d & el = (*this)[sei];
+	    if (el.IsDeleted() ) continue;
+
+	    if (dom == -1 || el.GetIndex() == dom)
+	      {
+		for (j = 0; j < 3; j++)
+		  {
+		    pmin.SetToMin ( (*this) [el[j]] );
+		    pmax.SetToMax ( (*this) [el[j]] );
+		  }
+	      }
+	  }
+      }
+
+    if (pmin.X() > 0.5e10)
+      {
+	pmin = pmax = Point3d(0,0,0);
+      }
+  }
+
+
+
+
+  void Mesh :: GetBox (Point3d & pmin, Point3d & pmax, POINTTYPE ptyp) const
+  {
+    if (points.Size() == 0)
+      {
+	pmin = pmax = Point3d(0,0,0);
+	return;
+      }
+
+    pmin = Point3d (1e10, 1e10, 1e10);
+    pmax = Point3d (-1e10, -1e10, -1e10); 
+  
+    for (PointIndex pi = PointIndex::BASE; 
+	 pi < GetNP()+PointIndex::BASE; pi++)
+      if (points[pi].Type() <= ptyp)
+	{
+	  pmin.SetToMin ( (*this) [pi] );
+	  pmax.SetToMax ( (*this) [pi] );
+	}
+  }
+
+
+
+
+  double Mesh :: ElementError (int eli) const
+  {
+    const Element & el = volelements.Get(eli);
+    return CalcTetBadness (points.Get(el[0]), points.Get(el[1]),
+			   points.Get(el[2]), points.Get(el[3]), -1);
+  }
+
+  void Mesh :: AddLockedPoint (PointIndex pi)
+  { 
+    lockedpoints.Append (pi); 
+  }
+
+  void Mesh :: ClearLockedPoints ()
+  { 
+    lockedpoints.SetSize (0); 
+  }
+
+
+
+  void Mesh :: Compress ()
+  {
+    int i, j;
+    ARRAY<int,PointIndex::BASE> op2np(GetNP());
+    ARRAY<MeshPoint> hpoints;
+    BitArrayChar<PointIndex::BASE> pused(GetNP());
+
+    /*
+      (*testout) << "volels: " << endl;
+      for (i = 1; i <= volelements.Size(); i++)
+      {
+      for (j = 1; j <= volelements.Get(i).GetNP(); j++)
+      (*testout) << volelements.Get(i).PNum(j) << " ";
+      (*testout) << endl;
+      }
+      (*testout) << "np: " << GetNP() << endl;
+    */
+
+    for (i = 0; i < volelements.Size(); i++)
+      if (volelements[i][0] <= PointIndex::BASE-1 ||
+	  volelements[i].IsDeleted())
+	{
+	  volelements.Delete(i);
+	  i--;
+	}
+
+
+    for (i = 0; i < surfelements.Size(); i++)
+      if (surfelements[i].IsDeleted())
+	{
+	  surfelements.Delete(i);
+	  i--;
+	}
+
+    for (i = 0; i < segments.Size(); i++)
+      if (segments[i].p1 <= PointIndex::BASE-1)
+	{
+	  segments.Delete(i);
+	  i--;
+	}
+
+    pused.Clear();
+    for (i = 0; i < volelements.Size(); i++)
+      {
+	const Element & el = volelements[i];
+	for (j = 0; j < el.GetNP(); j++)
+	  pused.Set (el[j]);
+      }
+
+    for (i = 0; i < surfelements.Size(); i++)
+      {
+	const Element2d & el = surfelements[i];
+	for (j = 0; j < el.GetNP(); j++)
+	  pused.Set (el[j]);
+      }
+
+    for (i = 0; i < segments.Size(); i++)
+      {
+	const Segment & seg = segments[i];
+	pused.Set (seg.p1);
+	pused.Set (seg.p2);
+      }
+
+    for (i = 0; i < openelements.Size(); i++)
+      {
+	const Element2d & el = openelements[i];
+	for (j = 0; j < el.GetNP(); j++)
+	  pused.Set(el[j]);
+      }
+
+    for (i = 0; i < lockedpoints.Size(); i++)
+      pused.Set (lockedpoints[i]);
+
+
+    /*
+    // compress points doesnt work for identified points !
+    if (identifiedpoints)
+    {
+    for (i = 1; i <= identifiedpoints->GetNBags(); i++)
+    if (identifiedpoints->GetBagSize(i))
+    {
+    pused.Set ();
+    break;
+    }
+    }
+    */
+    //  pused.Set();
+
+
+    int npi = PointIndex::BASE-1;
+
+    for (i = PointIndex::BASE; 
+	 i < points.Size()+PointIndex::BASE; i++)
+      if (pused.Test(i))
+	{
+	  npi++;
+	  op2np[i] = npi;
+	  hpoints.Append (points[i]);
+	}
+      else
+	op2np[i] = -1;
+
+
+
+    points.SetSize(0);
+    for (i = 0; i < hpoints.Size(); i++)
+      points.Append (hpoints[i]);
+
+
+    for (i = 1; i <= volelements.Size(); i++)
+      {
+	Element & el = VolumeElement(i);
+	for (j = 0; j < el.GetNP(); j++)
+	  el[j] = op2np[el[j]];
+      }
+
+    for (i = 1; i <= surfelements.Size(); i++)
+      {
+	Element2d & el = SurfaceElement(i);
+	for (j = 0; j < el.GetNP(); j++)
+	  el[j] = op2np[el[j]];
+      }
+  
+    for (i = 0; i < segments.Size(); i++)
+      {
+	Segment & seg = segments[i];
+	seg.p1 = op2np[seg.p1];
+	seg.p2 = op2np[seg.p2];
+      }
+
+    for (i = 1; i <= openelements.Size(); i++)
+      {
+	Element2d & el = openelements.Elem(i);
+	for (j = 0; j < el.GetNP(); j++)
+	  el[j] = op2np[el[j]];
+      }  
+
+
+    for (i = 0; i < lockedpoints.Size(); i++)
+      lockedpoints[i] = op2np[lockedpoints[i]];
+
+    for (int i = 0; i < facedecoding.Size(); i++)
+      facedecoding[i].firstelement = -1;
+    for (int i = surfelements.Size()-1; i >= 0; i--)
+      {
+        int ind = surfelements[i].GetIndex();
+        surfelements[i].next = facedecoding[ind-1].firstelement;
+        facedecoding[ind-1].firstelement = i;
+      }
+    
+
+    CalcSurfacesOfNode();
+
+
+    //  FindOpenElements();
+    timestamp = NextTimeStamp();
+
+    /*
+      (*testout) << "compress, done" << endl
+      << "np = " << points.Size()
+      << "ne = " << volelements.Size() << ", type.size = " << eltyps.Size()
+      <<  "volelements = " << volelements << endl;
+    */
+  }
+
+
+  int Mesh :: CheckConsistentBoundary () const
+  {
+    int nf = GetNOpenElements();
+    INDEX_2_HASHTABLE<int> edges(nf+2);
+    INDEX_2 i2, i2s, edge;
+    int err = 0;
+
+    for (int i = 1; i <= nf; i++)
+      {
+	const Element2d & sel = OpenElement(i);
+        
+	for (int j = 1; j <= sel.GetNP(); j++)
+	  {
+	    i2.I1() = sel.PNumMod(j);
+	    i2.I2() = sel.PNumMod(j+1);
+
+	    int sign = (i2.I2() > i2.I1()) ? 1 : -1;
+	    i2.Sort();
+	    if (!edges.Used (i2))
+	      edges.Set (i2, 0);
+	    edges.Set (i2, edges.Get(i2) + sign);
+	  }
+      }
+
+    for (int i = 1; i <= edges.GetNBags(); i++)
+      for (int j = 1; j <= edges.GetBagSize(i); j++)
+	{
+	  int cnt = 0;
+	  edges.GetData (i, j, i2, cnt);
+	  if (cnt)
+	    {
+	      PrintError ("Edge ", i2.I1() , " - ", i2.I2(), " multiple times in surface mesh");
+
+	      (*testout) << "Edge " << i2 << " multiple times in surface mesh" << endl;
+	      i2s = i2;
+	      i2s.Sort();
+	      for (int k = 1; k <= nf; k++)
+		{
+		  const Element2d & sel = OpenElement(k);
+		  for (int l = 1; l <= sel.GetNP(); l++)
+		    {
+		      edge.I1() = sel.PNumMod(l);
+		      edge.I2() = sel.PNumMod(l+1);
+		      edge.Sort();
+
+		      if (edge == i2s) 
+			(*testout) << "edge of element " << sel << endl;
+		    }
+		}
+
+
+	      err = 2;
+	    }
+	}
+
+    return err;
+  }
+
+
+
+  int Mesh :: CheckOverlappingBoundary () 
+  {
+    int i, j, k;
+
+    Point3d pmin, pmax;
+    GetBox (pmin, pmax);
+    Box3dTree setree(pmin, pmax);
+    ARRAY<int> inters;
+  
+    bool overlap = 0;
+    bool incons_layers = 0;
+
+
+    for (i = 1; i <= GetNSE(); i++)
+      SurfaceElement(i).badel = 0;
+
+
+    for (i = 1; i <= GetNSE(); i++)
+      {
+	const Element2d & tri = SurfaceElement(i);
+      
+	Point3d tpmin (Point(tri[0]));
+	Point3d tpmax (tpmin);
+
+	for (k = 1; k < tri.GetNP(); k++)
+	  {
+	    tpmin.SetToMin (Point (tri[k]));
+	    tpmax.SetToMax (Point (tri[k]));
+	  }
+	Vec3d diag(tpmin, tpmax);
+
+	tpmax = tpmax + 0.1 * diag;
+	tpmin = tpmin - 0.1 * diag;
+
+	setree.Insert (tpmin, tpmax, i);
+      }
+
+    for (i = 1; i <= GetNSE(); i++)
+      {
+	const Element2d & tri = SurfaceElement(i);
+      
+	Point3d tpmin (Point(tri[0]));
+	Point3d tpmax (tpmin);
+
+	for (k = 1; k < tri.GetNP(); k++)
+	  {
+	    tpmin.SetToMin (Point (tri[k]));
+	    tpmax.SetToMax (Point (tri[k]));
+	  }
+
+	setree.GetIntersecting (tpmin, tpmax, inters);
+
+	for (j = 1; j <= inters.Size(); j++)
+	  {
+	    const Element2d & tri2 = SurfaceElement(inters.Get(j));	  
+
+	    if ( (*this)[tri[0]].GetLayer() != (*this)[tri2[0]].GetLayer())
+	      continue;
+
+	    if ( (*this)[tri[0]].GetLayer() != (*this)[tri[1]].GetLayer() ||
+		 (*this)[tri[0]].GetLayer() != (*this)[tri[2]].GetLayer())
+	      {
+		incons_layers = 1;
+		cout << "inconsistent layers in triangle" << endl;
+	      }
+
+
+	    const netgen::Point<3> *trip1[3], *trip2[3];	  
+	    for (k = 1; k <= 3; k++)
+	      {
+		trip1[k-1] = &Point (tri.PNum(k));
+		trip2[k-1] = &Point (tri2.PNum(k));
+	      }
+
+	    if (IntersectTriangleTriangle (&trip1[0], &trip2[0]))
+	      {
+		overlap = 1;
+		PrintWarning ("Intersecting elements " 
+			      ,i, " and ", inters.Get(j));
+
+		(*testout) << "Intersecting: " << endl;
+		(*testout) << "openelement " << i << " with open element " << inters.Get(j) << endl;
+
+		cout << "el1 = " << tri << endl;
+		cout << "el2 = " << tri2 << endl;
+		cout << "layer1 = " <<  (*this)[tri[0]].GetLayer() << endl;
+		cout << "layer2 = " <<  (*this)[tri2[0]].GetLayer() << endl;
+
+
+		for (k = 1; k <= 3; k++)
+		  (*testout) << tri.PNum(k) << "  ";
+		(*testout) << endl;
+		for (k = 1; k <= 3; k++)
+		  (*testout) << tri2.PNum(k) << "  ";
+		(*testout) << endl;
+
+		for (k = 0; k <= 2; k++)
+		  (*testout) << *trip1[k] << "   ";
+		(*testout) << endl;
+		for (k = 0; k <= 2; k++)
+		  (*testout) << *trip2[k] << "   ";
+		(*testout) << endl;
+		
+		(*testout) << "Face1 = " << GetFaceDescriptor(tri.GetIndex()) << endl;
+		(*testout) << "Face1 = " << GetFaceDescriptor(tri2.GetIndex()) << endl;
+
+		/*
+		  INDEX_3 i3(tri.PNum(1), tri.PNum(2), tri.PNum(3));
+		  i3.Sort();
+		  for (k = 1; k <= GetNSE(); k++)
+		  {
+		  const Element2d & el2 = SurfaceElement(k);
+		  INDEX_3 i3b(el2.PNum(1), el2.PNum(2), el2.PNum(3));
+		  i3b.Sort();
+		  if (i3 == i3b)
+		  {
+		  SurfaceElement(k).badel = 1;
+		  }
+		  }
+		*/
+		SurfaceElement(i).badel = 1;
+		SurfaceElement(inters.Get(j)).badel = 1;
+	      }
+	  }
+      }
+
+    // bug 'fix'
+    if (incons_layers) overlap = 0;
+
+    return overlap;
+  }
+
+
+  int Mesh :: CheckVolumeMesh () const
+  {
+    PrintMessage (3, "Checking volume mesh");
+  
+    int ne = GetNE();
+    DenseMatrix dtrans(3,3);
+    int i, j;
+
+    PrintMessage (5, "elements: ", ne);
+    for (i = 1; i <= ne; i++)
+      {
+	Element & el = (Element&) VolumeElement(i);
+	el.flags.badel = 0;
+	int nip = el.GetNIP();
+	for (j = 1; j <= nip; j++)
+	  {
+	    el.GetTransformation (j, Points(), dtrans);
+	    double det = dtrans.Det();
+	    if (det > 0)
+	      {
+		PrintError ("Element ", i , " has wrong orientation");
+		el.flags.badel = 1;
+	      }
+	  }
+      }
+
+    return 0;
+  }
+
+
+  bool Mesh :: LegalTrig (const Element2d & el) const
+  {
+    return 1;
+    if ( /* hp */ 1)  // needed for old, simple hp-refinement
+      { 
+	// trigs with 2 or more segments are illegal
+	int i;
+	int nseg = 0;
+
+	if (!segmentht)
+	  {
+	    cerr << "no segmentht allocated" << endl;
+	    return 0;
+	  }
+
+	//      Point3d cp(0.5, 0.5, 0.5);
+	for (i = 1; i <= 3; i++)
+	  {
+	    INDEX_2 i2(el.PNumMod (i), el.PNumMod (i+1));
+	    i2.Sort();
+	    if (segmentht -> Used (i2))
+	      nseg++;
+	  }
+	if (nseg >= 2) 
+	  return 0;
+      }
+    return 1;
+  }
+
+
+
+
+  ///
+  bool Mesh :: LegalTet2 (Element & el) const
+  {
+    // static int timer1 = NgProfiler::CreateTimer ("Legaltet2");
+
+
+    // Test, whether 4 points have a common surface plus
+    // at least 4 edges at the boundary
+
+    if(!boundaryedges)
+      const_cast<Mesh *>(this)->BuildBoundaryEdges();
+
+  
+    // non-tets are always legal
+    if (el.GetType() != TET)
+      {
+	el.SetLegal (1);
+	return 1;
+      }
+
+    POINTTYPE pointtype[4];
+    for(int i = 0; i < 4; i++)
+      pointtype[i] = (*this)[el[i]].Type();
+
+    
+
+    // element has at least 2 inner points ---> legal
+    int cnti = 0;
+    for (int j = 0; j < 4; j++)
+      if ( pointtype[j] == INNERPOINT)
+	{
+	  cnti++;
+	  if (cnti >= 2)
+	    {
+	      el.SetLegal (1);
+	      return 1;
+	    }
+	}
+
+
+
+    // which faces are boundary faces ?
+    int bface[4];
+    for (int i = 0; i < 4; i++)
+      {
+	bface[i] = surfelementht->Used (INDEX_3::Sort(el[gftetfacesa[i][0]],
+                                                      el[gftetfacesa[i][1]],
+                                                      el[gftetfacesa[i][2]]));
+      }
+
+    int bedge[4][4];
+    int segedge[4][4];
+    static const int pi3map[4][4] = { { -1,  2,  1,  1 },
+                                      {  2, -1,  0,  0 },
+                                      {  1,  0, -1,  0 },
+                                      {  1,  0,  0, -1 } };
+
+    static const int pi4map[4][4] = { { -1,  3,  3,  2 },
+                                      {  3, -1,  3,  2 },
+                                      {  3,  3, -1,  1 },
+                                      {  2,  2,  1, -1 } };
+
+    
+    for (int i = 0; i < 4; i++)
+      for (int j = 0; j < i; j++)
+	{
+	  bool sege = false, be = false;
+
+          int pos = boundaryedges -> Position(INDEX_2::Sort(el[i], el[j]));
+	  if (pos)
+	    {
+	      be = true;
+	      if (boundaryedges -> GetData(pos) == 2)
+		sege = true;
+	    }
+
+	  segedge[j][i] = segedge[i][j] = sege;
+	  bedge[j][i] = bedge[i][j] = be;
+	}
+
+    // two boundary faces and no edge is illegal
+    for (int i = 0; i < 3; i++)
+      for (int j = i+1; j < 4; j++)
+	{
+	  if (bface[i] && bface[j])
+            if (!segedge[pi3map[i][j]][pi4map[i][j]])
+              {
+                // 2 boundary faces withoud edge in between
+                el.SetLegal (0);
+                return 0;
+              }
+	}
+
+    // three boundary edges meeting in a Surface point
+    for (int i = 0; i < 4; i++)
+      {
+	bool alledges = 1;
+	if ( pointtype[i] == SURFACEPOINT)
+	  {
+            bool alledges = 1;
+	    for (int j = 0; j < 4; j++)
+	      if (j != i && !bedge[i][j])
+                {
+                  alledges = 0;
+                  break;
+                }
+	    if (alledges)
+	      {
+		// cout << "tet illegal due to unmarked node" << endl;
+		el.SetLegal (0);
+		return 0;
+	      }
+	  }
+      }
+
+
+
+    for (int fnr = 0; fnr < 4; fnr++)
+      if (!bface[fnr])
+        for (int i = 0; i < 4; i++)
+          if (i != fnr)
+            {
+              int pi1 = pi3map[i][fnr];
+              int pi2 = pi4map[i][fnr];
+
+              if ( pointtype[i] == SURFACEPOINT)
+                {
+                  // two connected edges on surface, but no face
+                  if (bedge[i][pi1] && bedge[i][pi2])
+                    {
+                      el.SetLegal (0);
+                      return 0;
+                    }
+                }
+
+              if ( pointtype[i] == EDGEPOINT)
+                {
+                  // connected surface edge and edge edge, but no face
+                  if (bedge[i][pi1] && segedge[i][pi2] ||
+                      bedge[i][pi2] && segedge[i][pi1])
+                    {
+                      el.SetLegal (0);
+                      return 0;
+                    }
+                }
+
+            }
+
+
+    el.SetLegal (1);
+    return 1;
+  
+  }
+
+
+
+  int Mesh :: GetNDomains() const
+  {
+    int ndom = 0;
+
+    for (int k = 0; k < facedecoding.Size(); k++)
+      {
+	if (facedecoding[k].DomainIn() > ndom)
+	  ndom = facedecoding[k].DomainIn();
+	if (facedecoding[k].DomainOut() > ndom)
+	  ndom = facedecoding[k].DomainOut();
+      }
+
+    return ndom;
+  }
+
+
+
+  void Mesh :: SurfaceMeshOrientation ()
+  {
+    int i, j;
+    int nse = GetNSE();
+  
+    BitArray used(nse);
+    used.Clear();
+    INDEX_2_HASHTABLE<int> edges(nse+1);
+
+    bool haschanged = 0;
+
+
+    const Element2d & tri = SurfaceElement(1);
+    for (j = 1; j <= 3; j++)
+      {
+	INDEX_2 i2(tri.PNumMod(j), tri.PNumMod(j+1));
+	edges.Set (i2, 1);
+      }
+    used.Set(1);
+
+    bool unused;
+    do
+      {
+	bool changed;
+	do
+	  {
+	    changed = 0;
+	    for (i = 1; i <= nse; i++)
+	      if (!used.Test(i))
+		{
+		  Element2d & el = surfelements.Elem(i);
+		  int found = 0, foundrev = 0;
+		  for (j = 1; j <= 3; j++)
+		    {
+		      INDEX_2 i2(el.PNumMod(j), el.PNumMod(j+1));
+		      if (edges.Used(i2))
+			foundrev = 1;
+		      swap (i2.I1(), i2.I2());
+		      if (edges.Used(i2))
+			found = 1;
+		    }
+		
+		  if (found || foundrev)
+		    {
+		      if (foundrev)
+			swap (el.PNum(2), el.PNum(3));
+		    
+		      changed = 1;
+		      for (j = 1; j <= 3; j++)
+			{
+			  INDEX_2 i2(el.PNumMod(j), el.PNumMod(j+1));
+			  edges.Set (i2, 1);
+			}
+		      used.Set (i);
+		    }
+		}
+	    if (changed)
+	      haschanged = 1;
+	  }
+	while (changed);
+      
+
+	unused = 0;
+	for (i = 1; i <= nse; i++)
+	  if (!used.Test(i))
+	    {
+	      unused = 1;
+	      const Element2d & tri = SurfaceElement(i);
+	      for (j = 1; j <= 3; j++)
+		{
+		  INDEX_2 i2(tri.PNumMod(j), tri.PNumMod(j+1));
+		  edges.Set (i2, 1);
+		}
+	      used.Set(i);
+	      break;
+	    }
+      }
+    while (unused);
+
+    if (haschanged)
+      timestamp = NextTimeStamp();
+  }
+  
+
+  void Mesh :: Split2Tets()
+  {
+    PrintMessage (1, "Split To Tets");
+    bool has_prisms = 0;
+
+    int oldne = GetNE(); 
+    for (int i = 1; i <= oldne; i++)
+      {
+	Element el = VolumeElement(i);
+
+	if (el.GetType() == PRISM)
+	  {
+	    // prism, to 3 tets
+
+	    // make minimal node to node 1
+	    int minpi=0;
+	    PointIndex minpnum;
+	    minpnum = GetNP() + 1;
+
+	    for (int j = 1; j <= 6; j++)
+	      {
+		if (el.PNum(j) < minpnum)
+		  {
+		    minpnum = el.PNum(j);
+		    minpi = j;
+		  }
+	      }
+
+	    if (minpi >= 4)
+	      {
+		for (int j = 1; j <= 3; j++)
+		  swap (el.PNum(j), el.PNum(j+3));
+		minpi -= 3;
+	      }
+
+	    while (minpi > 1)
+	      {
+		int hi = 0;
+		for (int j = 0; j <= 3; j+= 3)
+		  {
+		    hi = el.PNum(1+j);
+		    el.PNum(1+j) = el.PNum(2+j);
+		    el.PNum(2+j) = el.PNum(3+j);
+		    el.PNum(3+j) = hi;
+		  }
+		minpi--;
+	      }
+
+	    /*
+	      version 1: edge from pi2 to pi6,
+	      version 2: edge from pi3 to pi5,
+	    */
+
+	    static const int ntets[2][12] =
+	      { { 1, 4, 5, 6, 1, 2, 3, 6, 1, 2, 5, 6 },
+		{ 1, 4, 5, 6, 1, 2, 3, 5, 3, 1, 5, 6 } };
+
+	    const int * min2pi;
+
+	    if (min2 (el.PNum(2), el.PNum(6)) <
+		min2 (el.PNum(3), el.PNum(5)))
+	      {
+		min2pi = &ntets[0][0];
+		// (*testout) << "version 1 ";
+	      }
+	    else
+	      {
+		min2pi = &ntets[1][0];
+		// (*testout) << "version 2 ";
+	      }
+
+	  
+	    int firsttet = 1;
+	    for (int j = 1; j <= 3; j++)
+	      {
+		Element nel(TET);
+		for (int k = 1; k <= 4; k++)
+		  nel.PNum(k) = el.PNum(min2pi[4 * j + k - 5]);
+		nel.SetIndex (el.GetIndex());
+
+		int legal = 1;
+		for (int k = 1; k <= 3; k++)
+		  for (int l = k+1; l <= 4; l++)
+		    if (nel.PNum(k) == nel.PNum(l))
+		      legal = 0;
+
+		// (*testout) << nel << " ";
+		if (legal)
+		  {
+		    if (firsttet)
+		      {
+			VolumeElement(i) = nel;
+			firsttet = 0;
+		      }
+		    else
+		      {
+			AddVolumeElement(nel);
+		      }
+		  }
+	      }
+	    if (firsttet) cout << "no legal";
+	    (*testout) << endl;
+	  }
+      
+
+
+	else if (el.GetType() == HEX)
+	  {
+	    // hex to A) 2 prisms or B) to 5 tets
+
+	    // make minimal node to node 1
+	    int minpi=0;
+	    PointIndex minpnum;
+	    minpnum = GetNP() + 1;
+
+	    for (int j = 1; j <= 8; j++)
+	      {
+		if (el.PNum(j) < minpnum)
+		  {
+		    minpnum = el.PNum(j);
+		    minpi = j;
+		  }
+	      }
+
+	    if (minpi >= 5)
+	      {
+		for (int j = 1; j <= 4; j++)
+		  swap (el.PNum(j), el.PNum(j+4));
+		minpi -= 4;
+	      }
+
+	    while (minpi > 1)
+	      {
+		int hi = 0;
+		for (int j = 0; j <= 4; j+= 4)
+		  {
+		    hi = el.PNum(1+j);
+		    el.PNum(1+j) = el.PNum(2+j);
+		    el.PNum(2+j) = el.PNum(3+j);
+		    el.PNum(3+j) = el.PNum(4+j);
+		    el.PNum(4+j) = hi;
+		  }
+		minpi--;
+	      }
+
+
+
+	    static const int to_prisms[3][12] =
+	      { { 0, 1, 2, 4, 5, 6, 0, 2, 3, 4, 6, 7 },
+		{ 0, 1, 5, 3, 2, 6, 0, 5, 4, 3, 6, 7 },
+		{ 0, 7, 4, 1, 6, 5, 0, 3, 7, 1, 2, 6 },
+	      };
+
+	    const int * min2pi = 0;
+	    if (min2 (el[4], el[6]) < min2 (el[5], el[7]))
+	      min2pi = &to_prisms[0][0];
+	    else if (min2 (el[3], el[6]) < min2 (el[2], el[7]))
+	      min2pi = &to_prisms[1][0];
+	    else if (min2 (el[1], el[6]) < min2 (el[2], el[5]))
+	      min2pi = &to_prisms[2][0];
+
+	    if (min2pi)
+	      {
+		has_prisms = 1;
+		for (int j = 0; j < 2; j++)
+		  {
+		    Element nel(PRISM);
+		    for (int k = 0; k < 6; k++)
+		      nel[k] = el[min2pi[6*j + k]];
+		    nel.SetIndex (el.GetIndex());
+		  
+		    if (j == 0)
+		      VolumeElement(i) = nel;
+		    else
+		      AddVolumeElement(nel);
+		  }
+	      }
+	    else
+	      {
+		// split to 5 tets
+	      
+		static const int to_tets[20] =
+		  {
+		    1, 2, 0, 5,
+		    3, 0, 2, 7,
+		    4, 5, 7, 0,
+		    6, 7, 5, 2,
+		    0, 2, 7, 5
+		  };
+
+		for (int j = 0; j < 5; j++)
+		  {
+		    Element nel(TET);
+		    for (int k = 0; k < 4; k++)
+		      nel[k] = el[to_tets[4*j + k]];
+		    nel.SetIndex (el.GetIndex());
+		  
+		    if (j == 0)
+		      VolumeElement(i) = nel;
+		    else
+		      AddVolumeElement(nel);
+		  }
+	      
+	      }
+	  }
+      
+
+
+
+      
+	else if (el.GetType() == PYRAMID)
+	  {
+	    // pyramid, to 2 tets
+	  
+	    // cout << "pyramid: " << el << endl;
+	    
+	    static const int ntets[2][8] =
+	      { { 1, 2, 3, 5, 1, 3, 4, 5 },
+		{ 1, 2, 4, 5, 4, 2, 3, 5 }};
+
+	    const int * min2pi;
+
+	    if (min2 (el[0], el[2]) < min2 (el[1], el[3]))
+	      min2pi = &ntets[0][0];
+	    else
+	      min2pi = &ntets[1][0];
+
+	    bool firsttet = 1;
+	    for (int j = 0; j < 2; j++)
+	      {
+		Element nel(TET);
+		for (int k = 0; k < 4; k++)
+		  nel[k] = el[min2pi[4*j + k]-1];
+		nel.SetIndex (el.GetIndex());
+
+		// cout << "pyramid-tet: " << nel << endl;
+
+		bool legal = 1;
+		for (int k = 0; k < 3; k++)
+		  for (int l = k+1; l < 4; l++)
+		    if (nel[k] == nel[l])
+		      legal = 0;
+
+		if (legal)
+		  {
+		    (*testout) << nel << " ";
+		    if (firsttet)
+		      VolumeElement(i) = nel;
+		    else
+		      AddVolumeElement(nel);
+
+		    firsttet = 0;
+		  }
+	      }
+	    if (firsttet) cout << "no legal";
+	    (*testout) << endl;
+	  }
+      }
+
+  
+    int oldnse = GetNSE(); 
+    for (int i = 1; i <= oldnse; i++)
+      {
+	Element2d el = SurfaceElement(i);
+	if (el.GetNP() == 4)
+	  {
+	    (*testout) << "split el: " << el << " to ";
+	  
+	    static const int ntris[2][6] =
+	      { { 1, 2, 3, 1, 3, 4 },
+		{ 1, 2, 4, 4, 2, 3 }};
+
+	    const int * min2pi;
+
+	    if (min2 (el.PNum(1), el.PNum(3)) <
+		min2 (el.PNum(2), el.PNum(4)))
+	      min2pi = &ntris[0][0];
+	    else
+	      min2pi = &ntris[1][0];
+
+	    for (int j = 0; j <6; j++)
+	      (*testout) << min2pi[j] << " ";
+
+
+	    int firsttri = 1;
+	    for (int j = 1; j <= 2; j++)
+	      {
+		Element2d nel(3);
+		for (int k = 1; k <= 3; k++)
+		  nel.PNum(k) = el.PNum(min2pi[3 * j + k - 4]);
+		nel.SetIndex (el.GetIndex());
+
+		int legal = 1;
+		for (int k = 1; k <= 2; k++)
+		  for (int l = k+1; l <= 3; l++)
+		    if (nel.PNum(k) == nel.PNum(l))
+		      legal = 0;
+
+		if (legal)
+		  {
+		    (*testout) << nel << " ";
+		    if (firsttri)
+		      {
+			SurfaceElement(i) = nel;
+			firsttri = 0;
+		      }
+		    else
+		      {
+			AddSurfaceElement(nel);
+		      }
+		  }
+	      }
+	    (*testout) << endl;
+
+	  }
+      }
+
+
+    if (has_prisms)
+
+      Split2Tets();
+  
+    else
+      {
+	for (int i = 1; i <= GetNE(); i++)
+	  {
+	    Element & el = VolumeElement(i);
+	    const Point3d & p1 = Point (el.PNum(1));
+	    const Point3d & p2 = Point (el.PNum(2));
+	    const Point3d & p3 = Point (el.PNum(3));
+	    const Point3d & p4 = Point (el.PNum(4));
+	  
+	    double vol = (Vec3d (p1, p2) * 
+			  Cross (Vec3d (p1, p3), Vec3d(p1, p4)));
+	    if (vol > 0)
+	      swap (el.PNum(3), el.PNum(4));
+	  }
+
+
+
+	UpdateTopology();
+	timestamp = NextTimeStamp();
+      }
+  }
+
+  void Mesh :: BuildElementSearchTree ()
+  {
+    if (elementsearchtreets == GetTimeStamp())
+      return;
+
+    NgLock lock(mutex);
+    lock.Lock();
+
+    PrintMessage (4, "Rebuild element searchtree");
+
+    if (elementsearchtree)
+      delete elementsearchtree;
+    elementsearchtree = NULL;
+
+    Box3d box;
+    int i, j;
+    int ne = GetNE();
+    if (!ne) 
+      {
+	lock.UnLock();
+	return;
+      }
+
+    box.SetPoint (Point (VolumeElement(1).PNum(1)));
+    for (i = 1; i <= ne; i++)
+      {
+	const Element & el = VolumeElement(i);
+	for (j = 1; j <= el.GetNP(); j++)
+	  box.AddPoint (Point (el.PNum(j)));
+      }
+  
+    box.Increase (1.01 * box.CalcDiam());
+    elementsearchtree = new Box3dTree (box.PMin(), box.PMax());
+  
+
+
+    for (i = 1; i <= ne; i++)
+      {
+	const Element & el = VolumeElement(i);
+	box.SetPoint (Point (el.PNum(1)));
+	for (j = 1; j <= el.GetNP(); j++)
+	  box.AddPoint (Point (el.PNum(j)));
+
+	elementsearchtree -> Insert (box.PMin(), box.PMax(), i);
+      }
+
+    elementsearchtreets = GetTimeStamp();
+
+    lock.UnLock();
+  }
+
+
+  
+  bool Mesh :: PointContainedIn2DElement(const Point3d & p,
+					 double lami[3],
+					 const int element,
+					 bool consider3D) const
+  {
+    static Vec3d col1, col2, col3;
+    static Vec3d rhs, sol;
+    const double eps = 1e-6;
+
+    static ARRAY<Element2d> loctrigs;
+
+
+    //SZ 
+    if(SurfaceElement(element).GetType()==QUAD)
+      {
+	const Element2d & el = SurfaceElement(element); 
+	      
+	const Point3d & p1 = Point(el.PNum(1)); 
+	const Point3d & p2 = Point(el.PNum(2));
+	const Point3d & p3 = Point(el.PNum(3));
+	const Point3d & p4 = Point(el.PNum(4)); 
+
+	// Coefficients of Bilinear Mapping from Ref-Elem to global Elem
+	// X = a + b x + c y + d x y 
+	Vec3d a = p1; 
+	Vec3d b = p2 - a; 
+	Vec3d c = p4 - a; 
+	Vec3d d = p3 - a - b - c; 
+	   
+	double dxb = d.X()*b.Y()-d.Y()*b.X();
+	double dxc = d.X()*c.Y()-d.Y()*c.X(); 
+	double dxa = d.X()*a.Y()-d.Y()*a.X(); 
+	double dxp = d.X()*p.Y()-d.Y()*p.X(); 
+	      	      
+	double c0,c1,c2,rt; 
+	lami[2]=0.; 
+	double eps = 1.E-12; 
+
+	if(fabs(d.X()) <= eps && fabs(d.Y())<= eps)
+	  {
+	    //Solve Linear System
+	    lami[0]=(c.Y()*(p.X()-a.X())-c.X()*(p.Y()-a.Y()))/
+	      (b.X()*c.Y() -b.Y()*c.X()); 
+	    lami[1]=(-b.Y()*(p.X()-a.X())+b.X()*(p.Y()-a.Y()))/
+	      (b.X()*c.Y() -b.Y()*c.X()); 
+	  } 
+	else
+	  if(fabs(dxb) <= eps) 
+	    {
+	      lami[1] = (dxp-dxa)/dxc;
+	      if(fabs(b.X()-d.X()*lami[1])>=eps)
+		lami[0] = (p.X()-a.X() - c.X()*lami[1])/(b.X()+d.X()*lami[1]); 
+	      else
+		lami[0] = (p.Y()-a.Y() - c.Y()*lami[1])/(b.Y()+d.Y()*lami[1]); 
+	    }
+	  else
+	    if(fabs(dxc) <= eps)
+	      {
+		lami[0] = (dxp-dxa)/dxb;
+		if(fabs(c.X()-d.X()*lami[0])>=eps)
+		  lami[1] = (p.X()-a.X() - b.X()*lami[0])/(c.X()+d.X()*lami[0]); 
+		else
+		  lami[1] = (p.Y()-a.Y() - b.Y()*lami[0])/(c.Y()+d.Y()*lami[0]); 
+	      }
+	    else //Solve quadratic equation
+	      {
+		if(fabs(d.X()) >= eps)
+		  {
+		    c2 = d.X()*dxc;
+		    c1 = d.X()*dxc - c.X()*dxb - d.X()*(dxp-dxa);
+		    c0 = -b.X()*(dxp -dxa) - (a.X()-p.X())*dxb;
+		  }
+		else 
+		  {
+		    c2 = d.Y()*dxc;
+		    c1 = d.Y()*dxc - c.Y()*dxb - d.Y()*(dxp-dxa);
+		    c0 = -b.Y()*(dxp -dxa) - (a.Y()-p.Y())*dxb;
+		  }
+
+		double rt =  c1*c1 - 4*c2*c0;
+		if (rt < 0.) return false; 
+		lami[1] = (-c1 + sqrt(rt))/2/c2;
+		if(lami[1]<=1. && lami[1]>=0.)
+		  {
+		    lami[0] = (dxp - dxa -dxc*lami[1])/dxb;
+		    if(lami[0]<=1. && lami[0]>=0.)
+		      return true;
+		  }
+		      
+		lami[1] = (-c1 - sqrt(rt))/2/c2;
+		lami[0] = (dxp - dxa -dxc*lami[1])/dxb;
+	      }
+
+	if( lami[0] <= 1.+eps  && lami[0] >= -eps && lami[1]<=1.+eps && lami[1]>=-eps)
+	  {
+	    if(consider3D)
+	      {
+		Vec3d n = Cross(b,c);
+		lami[2] = 0;
+		for(int i=1; i<=3; i++)
+		  lami[2] +=(p.X(i)-a.X(i)-lami[0]*b.X(i)-lami[1]*c.X(i)) * n.X(i);
+		if(lami[2] >= -eps && lami[2] <= eps)
+		  return true;
+	      }
+	    else
+	      return true;
+	  }
+		      
+	return false;
+	      
+      }
+    else
+      {
+	//	  SurfaceElement(element).GetTets (loctets);
+	loctrigs.SetSize(1);
+	loctrigs.Elem(1) = SurfaceElement(element);
+	      
+	      
+	      
+	for (int j = 1; j <= loctrigs.Size(); j++)
+	  {
+	    const Element2d & el = loctrigs.Get(j);
+		  
+		  
+	    const Point3d & p1 = Point(el.PNum(1));
+	    const Point3d & p2 = Point(el.PNum(2));
+	    const Point3d & p3 = Point(el.PNum(3));
+	    /*
+	      Box3d box;
+	      box.SetPoint (p1);
+	      box.AddPoint (p2);
+	      box.AddPoint (p3);
+	      box.AddPoint (p4);
+	      if (!box.IsIn (p))
+	      continue;
+	    */
+	    col1 = p2-p1;
+	    col2 = p3-p1;
+	    col3 = Cross(col1,col2);
+	    //col3 = Vec3d(0, 0, 1);
+	    rhs = p - p1;
+		  
+	    int retval = SolveLinearSystem (col1, col2, col3, rhs, sol);
+
+	    //(*testout) << "retval " << retval << endl;
+		  
+	    //(*testout) << "col1 " << col1 << " col2 " << col2 << " col3 " << col3 << " rhs " << rhs << endl;
+	    //(*testout) << "sol " << sol << endl;
+
+	    if (sol.X() >= -eps && sol.Y() >= -eps && 
+		sol.X() + sol.Y() <= 1+eps)
+	      {
+		if(!consider3D || (sol.Z() >= -eps && sol.Z() <= eps))
+		  {
+		    lami[0] = sol.X();
+		    lami[1] = sol.Y();
+		    lami[2] = sol.Z();
+		    
+		    return true;
+		  }
+	      }
+	  }
+      }
+
+    return false;
+
+  }
+
+
+
+
+  bool Mesh :: PointContainedIn3DElement(const Point3d & p,
+					 double lami[3],
+					 const int element) const
+  {
+    //bool oldresult = PointContainedIn3DElementOld(p,lami,element);
+    //(*testout) << "old result: " << oldresult
+    //       << " lam " << lami[0] << " " << lami[1] << " " << lami[2] << endl;
+
+    //if(!curvedelems->IsElementCurved(element-1))
+    //  return PointContainedIn3DElementOld(p,lami,element);
+
+
+    const double eps = 1.e-4;
+    const Element & el = VolumeElement(element);
+
+    netgen::Point<3> lam;
+
+    if (el.GetType() == TET)
+      {
+	lam = 0.25;
+      }
+    else if (el.GetType() == PRISM)
+      {
+	lam(0) = 0.33; lam(1) = 0.33; lam(2) = 0.5;
+      }
+    else if (el.GetType() == PYRAMID)
+      {
+	lam(0) = 0.4; lam(1) = 0.4; lam(2) = 0.2;
+      }
+    else if (el.GetType() == HEX)
+      {
+	lam = 0.5;
+      }
+    
+
+    Vec<3> deltalam,rhs;
+    netgen::Point<3> x;
+    Mat<3,3> Jac,Jact;
+
+    double delta=1;
+
+    bool retval;
+    
+    int i = 0;
+
+    const int maxits = 30;
+
+    while(delta > 1e-16 && i<maxits)
+      {
+	curvedelems->CalcElementTransformation(lam,element-1,x,Jac);
+
+	rhs = p-x;
+	Jac.Solve(rhs,deltalam);
+
+	lam += deltalam;
+
+	delta = deltalam.Length2();
+
+	i++;
+	//(*testout) << "pcie i " << i << " delta " << delta << " p " << p << " x " << x << " lam " << lam << endl;
+	//<< "Jac " << Jac << endl;
+      }
+
+    if(i==maxits)
+      return false;
+
+
+    for(i=0; i<3; i++)
+      lami[i] = lam(i);
+
+
+
+    if (el.GetType() == TET)
+      {
+	retval = (lam(0) > -eps && 
+		  lam(1) > -eps && 
+		  lam(2) > -eps && 
+		  lam(0) + lam(1) + lam(2) < 1+eps);
+      }
+    else if (el.GetType() == PRISM)
+      {
+	retval = (lam(0) > -eps &&
+		  lam(1) > -eps &&
+		  lam(2) > -eps &&
+		  lam(2) < 1+eps &&
+		  lam(0) + lam(1) < 1+eps);
+      }
+    else if (el.GetType() == PYRAMID)
+      {
+	retval = (lam(0) > -eps &&
+		  lam(1) > -eps &&
+		  lam(2) > -eps &&
+		  lam(0) + lam(2) < 1+eps &&
+		  lam(1) + lam(2) < 1+eps);
+      }
+    else if (el.GetType() == HEX)
+      {
+	retval = (lam(0) > -eps && lam(0) < 1+eps &&
+		  lam(1) > -eps && lam(1) < 1+eps &&
+		  lam(2) > -eps && lam(2) < 1+eps);
+      }
+    else
+      throw NgException("Da haun i wos vagessn");
+
+    return retval;
+  }
+  
+
+  
+  bool Mesh :: PointContainedIn3DElementOld(const Point3d & p,
+					    double lami[3],
+					    const int element) const
+  {
+
+    static Vec3d col1, col2, col3;
+    static Vec3d rhs, sol;
+    const double eps = 1.e-4;
+    
+    static ARRAY<Element> loctets;
+
+    VolumeElement(element).GetTets (loctets);
+    
+    for (int j = 1; j <= loctets.Size(); j++)
+      {
+	const Element & el = loctets.Get(j);
+	
+	const Point3d & p1 = Point(el.PNum(1));
+	const Point3d & p2 = Point(el.PNum(2));
+	const Point3d & p3 = Point(el.PNum(3));
+	const Point3d & p4 = Point(el.PNum(4));
+	
+	Box3d box;
+	box.SetPoint (p1);
+	box.AddPoint (p2);
+	box.AddPoint (p3);
+	box.AddPoint (p4);
+	if (!box.IsIn (p))
+	  continue;
+	
+	col1 = p2-p1;
+	col2 = p3-p1;
+	col3 = p4-p1;
+	rhs = p - p1;
+	
+	SolveLinearSystem (col1, col2, col3, rhs, sol);
+	
+	if (sol.X() >= -eps && sol.Y() >= -eps && sol.Z() >= -eps &&
+	    sol.X() + sol.Y() + sol.Z() <= 1+eps)
+	  {
+	    ARRAY<Element> loctetsloc;
+	    ARRAY<netgen::Point<3> > pointsloc;
+	    
+	    VolumeElement(element).GetTetsLocal (loctetsloc);
+	    VolumeElement(element).GetNodesLocalNew (pointsloc);
+	    
+	    const Element & le = loctetsloc.Get(j);
+	   
+
+	    Point3d pp = 
+	      pointsloc.Get(le.PNum(1)) 
+	      + sol.X() * Vec3d (pointsloc.Get(le.PNum(1)), pointsloc.Get(le.PNum(2))) 
+	      + sol.Y() * Vec3d (pointsloc.Get(le.PNum(1)), pointsloc.Get(le.PNum(3))) 
+	      + sol.Z() * Vec3d (pointsloc.Get(le.PNum(1)), pointsloc.Get(le.PNum(4))) ;
+	    
+	    lami[0] = pp.X();
+	    lami[1] = pp.Y();
+	    lami[2] = pp.Z();
+	    return true;
+	  }
+      }
+    return false;
+  }
+ 
+
+  int Mesh :: GetElementOfPoint (const Point3d & p,
+				 double lami[3],
+				 bool build_searchtree,
+				 const int index,
+				 const bool allowindex) const
+  {
+    if(index != -1) 
+      {
+	ARRAY<int> dummy(1);
+	dummy[0] = index;
+	return GetElementOfPoint(p,lami,&dummy,build_searchtree,allowindex);
+      }
+    else
+      return GetElementOfPoint(p,lami,NULL,build_searchtree,allowindex);
+  }
+
+
+
+
+  int Mesh :: GetElementOfPoint (const Point3d & p,
+				 double lami[3],
+				 const ARRAY<int> * const indices,
+				 bool build_searchtree,
+				 const bool allowindex) const
+  {
+    if (dimension == 2)
+      {
+	int i, j;
+	int ne;
+      
+	
+	if(ps_startelement != 0 && ps_startelement <= GetNSE() && PointContainedIn2DElement(p,lami,ps_startelement))
+	  return ps_startelement;
+
+	ARRAY<int> locels;
+	if (0)
+	  {
+	    elementsearchtree->GetIntersecting (p, p, locels);
+	    ne = locels.Size();
+	  }
+	else
+	  ne = GetNSE();
+
+	for (i = 1; i <= ne; i++)
+	  {
+	    int ii;
+
+	    if (0)
+	      ii = locels.Get(i);
+	    else
+	      ii = i;
+	      
+	    if(ii == ps_startelement) continue;
+
+	    if(indices != NULL && indices->Size() > 0)
+	      {
+		bool contained = indices->Contains(SurfaceElement(ii).GetIndex());
+		if((allowindex && !contained) || (!allowindex && contained)) continue;
+	      }
+
+	    if(PointContainedIn2DElement(p,lami,ii)) return ii;
+
+	  }
+	return 0;
+      }
+    else
+      
+      {
+	int i, j;
+	int ne;
+      
+	if(ps_startelement != 0 && PointContainedIn3DElement(p,lami,ps_startelement))
+	  return ps_startelement;
+
+	ARRAY<int> locels;
+	if (elementsearchtree || build_searchtree)
+	  {
+	    // update if necessary:
+	    const_cast<Mesh&>(*this).BuildElementSearchTree (); 
+	    elementsearchtree->GetIntersecting (p, p, locels);
+	    ne = locels.Size();
+	  }
+	else
+	  ne = GetNE();
+      
+	for (i = 1; i <= ne; i++)
+	  {
+	    int ii;
+
+	    if (elementsearchtree)
+	      ii = locels.Get(i);
+	    else
+	      ii = i;
+	      
+	    if(ii == ps_startelement) continue;
+	    
+	    if(indices != NULL && indices->Size() > 0)
+	      {
+		bool contained = indices->Contains(VolumeElement(ii).GetIndex());
+		if((allowindex && !contained) || (!allowindex && contained)) continue;
+	      }
+	    
+	  
+	    if(PointContainedIn3DElement(p,lami,ii)) 
+	      {
+		ps_startelement = ii;
+		return ii;
+	      }
+	  }
+
+	// Not found, try uncurved variant:
+	for (i = 1; i <= ne; i++)
+	  {
+	    int ii;
+
+	    if (elementsearchtree)
+	      ii = locels.Get(i);
+	    else
+	      ii = i;
+	    
+	    if(indices != NULL && indices->Size() > 0)
+	      {
+		bool contained = indices->Contains(VolumeElement(ii).GetIndex());
+		if((allowindex && !contained) || (!allowindex && contained)) continue;
+	      }
+	    
+	  
+	    if(PointContainedIn3DElementOld(p,lami,ii)) 
+	      {
+		ps_startelement = ii;
+		(*testout) << "WARNING: found element of point " << p <<" only for uncurved mesh" << endl;
+		return ii;
+	      }
+	  }
+
+      
+	return 0;
+      }
+  }
+
+
+
+  int Mesh :: GetSurfaceElementOfPoint (const Point3d & p,
+					double lami[3],
+					bool build_searchtree,
+					const int index,
+					const bool allowindex) const
+  {
+    if(index != -1) 
+      {
+	ARRAY<int> dummy(1);
+	dummy[0] = index;
+	return GetSurfaceElementOfPoint(p,lami,&dummy,build_searchtree,allowindex);
+      }
+    else
+      return GetSurfaceElementOfPoint(p,lami,NULL,build_searchtree,allowindex);
+  }
+
+
+
+
+  int Mesh :: GetSurfaceElementOfPoint (const Point3d & p,
+					double lami[3],
+					const ARRAY<int> * const indices,
+					bool build_searchtree,
+					const bool allowindex) const
+  {
+    if (dimension == 2)
+      {
+	throw NgException("GetSurfaceElementOfPoint not yet implemented for 2D meshes");
+      }
+    else
+      {
+	double vlam[3];
+	int velement = GetElementOfPoint(p,vlam,NULL,build_searchtree,allowindex);
+
+	//(*testout) << "p " << p << endl;
+	//(*testout) << "velement " << velement << endl;
+
+	ARRAY<int> faces;
+	topology->GetElementFaces(velement,faces);
+
+	//(*testout) << "faces " << faces << endl;
+
+	for(int i=0; i<faces.Size(); i++)
+	  faces[i] = topology->GetFace2SurfaceElement(faces[i]);
+
+	//(*testout) << "surfel " << faces << endl;
+
+	for(int i=0; i<faces.Size(); i++)
+	  {
+	    if(faces[i] == 0)
+	      continue;
+
+	    if(indices && indices->Size() != 0)
+	      {
+		if(indices->Contains(SurfaceElement(faces[i]).GetIndex()) &&
+		   PointContainedIn2DElement(p,lami,faces[i],true))
+		  return faces[i];
+	      }
+	    else
+	      {
+		if(PointContainedIn2DElement(p,lami,faces[i],true))
+		  {
+		    //(*testout) << "found point " << p << " in sel " << faces[i]
+		    //	       << ", lam " << lami[0] << ", " << lami[1] << ", " << lami[2] << endl;
+		    return faces[i];
+		  }
+	      }
+	  }
+	     
+      }
+
+    return 0;
+  }
+
+
+  void Mesh::GetIntersectingVolEls(const Point3d& p1, const Point3d& p2, 
+				   ARRAY<int> & locels) const
+  {
+    elementsearchtree->GetIntersecting (p1, p2, locels);
+  }
+
+  void Mesh :: SplitIntoParts()
+  {
+    int i, j, dom;
+    int ne = GetNE();
+    int np = GetNP();
+    int nse = GetNSE();
+
+    BitArray surfused(nse);
+    BitArray pused (np);
+
+    surfused.Clear();
+
+    dom = 0;
+  
+    while (1)
+      {
+	int cntd = 1;
+
+	dom++;
+      
+	pused.Clear();
+
+	int found = 0;
+	for (i = 1; i <= nse; i++)
+	  if (!surfused.Test(i))
+	    {
+	      SurfaceElement(i).SetIndex (dom);
+	      for (j = 1; j <= 3; j++)
+		pused.Set (SurfaceElement(i).PNum(j));
+	      found = 1;
+	      cntd = 1;
+	      surfused.Set(i);
+	      break;
+	    }
+
+	if (!found)
+	  break;
+
+	int change;
+	do
+	  {
+	    change = 0;
+	    for (i = 1; i <= nse; i++)
+	      {
+		int is = 0, isnot = 0;
+		for (j = 1; j <= 3; j++)
+		  if (pused.Test(SurfaceElement(i).PNum(j)))
+		    is = 1;
+		  else
+		    isnot = 1;
+	      
+		if (is && isnot)
+		  {
+		    change = 1;
+		    for (j = 1; j <= 3; j++)
+		      pused.Set (SurfaceElement(i).PNum(j));
+		  }
+
+		if (is) 
+		  {
+		    if (!surfused.Test(i))
+		      {
+			surfused.Set(i);
+			SurfaceElement(i).SetIndex (dom);
+			cntd++;
+		      }
+		  }
+	      }
+
+
+	    for (i = 1; i <= ne; i++)
+	      {
+		int is = 0, isnot = 0;
+		for (j = 1; j <= 4; j++)
+		  if (pused.Test(VolumeElement(i).PNum(j)))
+		    is = 1;
+		  else
+		    isnot = 1;
+	      
+		if (is && isnot)
+		  {
+		    change = 1;
+		    for (j = 1; j <= 4; j++)
+		      pused.Set (VolumeElement(i).PNum(j));
+		  }
+
+		if (is)
+		  {
+		    VolumeElement(i).SetIndex (dom);
+		  }
+	      }
+	  }
+	while (change);
+
+	PrintMessage (3, "domain ", dom, " has ", cntd, " surfaceelements");
+      }
+
+    /*
+      facedecoding.SetSize (dom);
+      for (i = 1; i <= dom; i++)
+      {
+      facedecoding.Elem(i).surfnr = 0;
+      facedecoding.Elem(i).domin = i;
+      facedecoding.Elem(i).domout = 0;
+      }
+    */
+    ClearFaceDescriptors();
+    for (i = 1; i <= dom; i++)
+      AddFaceDescriptor (FaceDescriptor (0, i, 0, 0));
+    CalcSurfacesOfNode();
+    timestamp = NextTimeStamp();
+  }
+
+  void Mesh :: SplitSeparatedFaces ()
+  {
+    PrintMessage (3, "SplitSeparateFaces");
+    int fdi;
+    int np = GetNP();
+
+    BitArray usedp(np);
+    ARRAY<SurfaceElementIndex> els_of_face;
+
+    fdi = 1;
+    while (fdi <= GetNFD())
+      {
+	GetSurfaceElementsOfFace (fdi, els_of_face);
+
+	if (els_of_face.Size() == 0) continue;
+
+	SurfaceElementIndex firstel = els_of_face[0];
+
+	usedp.Clear();
+	for (int j = 1; j <= SurfaceElement(firstel).GetNP(); j++)
+	  usedp.Set (SurfaceElement(firstel).PNum(j));
+
+	bool changed;
+	do
+	  {
+	    changed = false;
+
+	    for (int i = 0; i < els_of_face.Size(); i++)
+	      {
+		const Element2d & el = SurfaceElement(els_of_face[i]);
+
+		bool has = 0;
+		bool hasno = 0;
+		for (int j = 0; j < el.GetNP(); j++)
+		  {
+		    if (usedp.Test(el[j]))
+		      has = true;
+		    else
+		      hasno = true;
+		  }
+
+		if (has && hasno)
+		  changed = true;
+
+		if (has)
+		  for (int j = 0; j < el.GetNP(); j++)
+		    usedp.Set (el[j]);
+	      }
+	  }
+	while (changed);
+
+	int nface = 0;
+	for (int i = 0; i < els_of_face.Size(); i++)
+	  {
+	    Element2d & el = SurfaceElement(els_of_face[i]);
+
+	    int hasno = 0;
+	    for (int j = 1; j <= el.GetNP(); j++)
+	      if (!usedp.Test(el.PNum(j)))
+		  hasno = 1;
+	  
+	    if (hasno)
+	      {
+		if (!nface)
+		  {
+		    FaceDescriptor nfd = GetFaceDescriptor(fdi);
+		    nface = AddFaceDescriptor (nfd);
+		  }
+
+		el.SetIndex (nface);
+	      }
+	  }
+
+        // reconnect list
+        if (nface)
+          {
+            facedecoding[nface-1].firstelement = -1;
+            facedecoding[fdi-1].firstelement = -1;
+
+            for (int i = 0; i < els_of_face.Size(); i++)
+              {
+                int ind = SurfaceElement(els_of_face[i]).GetIndex();
+                SurfaceElement(els_of_face[i]).next = facedecoding[ind-1].firstelement;
+                facedecoding[ind-1].firstelement = els_of_face[i];
+              }
+          }
+
+	fdi++;
+      }
+
+
+    /*
+    fdi = 1;
+    while (fdi <= GetNFD())
+      {
+	int firstel = 0;
+	for (int i = 1; i <= GetNSE(); i++)
+	  if (SurfaceElement(i).GetIndex() == fdi)
+	    {
+	      firstel = i;
+	      break;
+	    }
+	if (!firstel) continue;
+
+	usedp.Clear();
+	for (int j = 1; j <= SurfaceElement(firstel).GetNP(); j++)
+	  usedp.Set (SurfaceElement(firstel).PNum(j));
+
+	int changed;
+	do
+	  {
+	    changed = 0;
+	    for (int i = 1; i <= GetNSE(); i++)
+	      {
+		const Element2d & el = SurfaceElement(i);
+		if (el.GetIndex() != fdi)
+		  continue;
+
+		int has = 0;
+		int hasno = 0;
+		for (int j = 1; j <= el.GetNP(); j++)
+		  {
+		    if (usedp.Test(el.PNum(j)))
+		      has = 1;
+		    else
+		      hasno = 1;
+		  }
+		if (has && hasno)
+		  changed = 1;
+
+		if (has)
+		  for (int j = 1; j <= el.GetNP(); j++)
+		    usedp.Set (el.PNum(j));
+	      }
+	  }
+	while (changed);
+
+	int nface = 0;
+	for (int i = 1; i <= GetNSE(); i++)
+	  {
+	    Element2d & el = SurfaceElement(i);
+	    if (el.GetIndex() != fdi)
+	      continue;	  
+
+	    int hasno = 0;
+	    for (int j = 1; j <= el.GetNP(); j++)
+	      {
+		if (!usedp.Test(el.PNum(j)))
+		  hasno = 1;
+	      }
+	  
+	    if (hasno)
+	      {
+		if (!nface)
+		  {
+		    FaceDescriptor nfd = GetFaceDescriptor(fdi);
+		    nface = AddFaceDescriptor (nfd);
+		  }
+
+		el.SetIndex (nface);
+	      }
+	  }
+	fdi++;
+      }
+    */
+  }
+
+
+  void Mesh :: GetSurfaceElementsOfFace (int facenr, ARRAY<SurfaceElementIndex> & sei) const
+  {
+    static int timer = NgProfiler::CreateTimer ("GetSurfaceElementsOfFace");
+    NgProfiler::RegionTimer reg (timer);
+
+    /*
+    sei.SetSize (0);
+    for (SurfaceElementIndex i = 0; i < GetNSE(); i++)
+      if ( (*this)[i].GetIndex () == facenr && (*this)[i][0] >= PointIndex::BASE &&
+	   !(*this)[i].IsDeleted() )
+	sei.Append (i);
+
+    int size1 = sei.Size();
+    */
+
+    sei.SetSize(0);
+
+    SurfaceElementIndex si = facedecoding[facenr-1].firstelement;
+    while (si != -1)
+      {
+        if ( (*this)[si].GetIndex () == facenr && (*this)[si][0] >= PointIndex::BASE &&
+             !(*this)[si].IsDeleted() )
+          {
+            sei.Append (si);
+          }
+
+        si = (*this)[si].next;
+      }
+
+    /*
+     // *testout << "with list = " << endl << sei << endl;
+
+    if (size1 != sei.Size()) 
+      {
+        cout << "size mismatch" << endl;
+        exit(1);
+      }
+    */
+  }
+
+
+
+
+  void Mesh :: CalcMinMaxAngle (double badellimit, double * retvalues) 
+  {
+    int i, j;
+    int lpi1, lpi2, lpi3, lpi4;
+    double phimax = 0, phimin = 10;
+    double facephimax = 0, facephimin = 10;
+    int illegaltets = 0, negativetets = 0, badtets = 0;
+
+    for (i = 1; i <= GetNE(); i++)
+      {
+	int badel = 0;
+
+	Element & el = VolumeElement(i);
+
+	if (el.GetType() != TET)
+	  {
+	    VolumeElement(i).flags.badel = 0;
+	    continue;
+	  }
+
+	if (el.Volume(Points()) < 0)
+	  {
+	    badel = 1;
+	    negativetets++;
+	  }
+      
+
+	if (!LegalTet (el)) 
+	  {
+	    badel = 1;
+	    illegaltets++;
+	    (*testout) << "illegal tet: " << i << " ";
+	    for (j = 1; j <= el.GetNP(); j++)
+	      (*testout) << el.PNum(j) << " ";
+	    (*testout) << endl;
+	  }
+      
+	
+	// angles between faces
+	for (lpi1 = 1; lpi1 <= 3; lpi1++)
+	  for (lpi2 = lpi1+1; lpi2 <= 4; lpi2++)
+	    {
+	      lpi3 = 1;
+	      while (lpi3 == lpi1 || lpi3 == lpi2)
+		lpi3++;
+	      lpi4 = 10 - lpi1 - lpi2 - lpi3;
+
+	      const Point3d & p1 = Point (el.PNum(lpi1));
+	      const Point3d & p2 = Point (el.PNum(lpi2));
+	      const Point3d & p3 = Point (el.PNum(lpi3));
+	      const Point3d & p4 = Point (el.PNum(lpi4));
+
+	      Vec3d n(p1, p2);
+	      n /= n.Length();
+	      Vec3d v1(p1, p3);
+	      Vec3d v2(p1, p4);
+
+	      v1 -= (n * v1) * n;
+	      v2 -= (n * v2) * n;
+
+	      double cosphi = (v1 * v2) / (v1.Length() * v2.Length());
+	      double phi = acos (cosphi);
+	      if (phi > phimax) phimax = phi;
+	      if (phi < phimin) phimin = phi;
+
+	      if ((180/M_PI) * phi > badellimit)
+		badel = 1;
+	    }
+
+
+	// angles in faces
+	for (j = 1; j <= 4; j++)
+	  {
+	    Element2d face;
+	    el.GetFace (j, face);
+	    for (lpi1 = 1; lpi1 <= 3; lpi1++)
+	      {
+		lpi2 = lpi1 % 3 + 1;
+		lpi3 = lpi2 % 3 + 1;
+
+		const Point3d & p1 = Point (el.PNum(lpi1));
+		const Point3d & p2 = Point (el.PNum(lpi2));
+		const Point3d & p3 = Point (el.PNum(lpi3));
+
+		Vec3d v1(p1, p2);
+		Vec3d v2(p1, p3);
+		double cosphi = (v1 * v2) / (v1.Length() * v2.Length());
+		double phi = acos (cosphi);
+		if (phi > facephimax) facephimax = phi;
+		if (phi < facephimin) facephimin = phi;
+
+		if ((180/M_PI) * phi > badellimit)
+		  badel = 1;
+
+	      }
+	  }
+
+       
+	VolumeElement(i).flags.badel = badel;
+	if (badel) badtets++;
+      }
+
+    if (!GetNE())
+      {
+	phimin = phimax = facephimin = facephimax = 0;
+      }
+
+    if (!retvalues)
+      {
+	PrintMessage (1, "");
+	PrintMessage (1, "between planes:  phimin = ", (180/M_PI) * phimin,
+		      " phimax = ", (180/M_PI) *phimax);
+	PrintMessage (1, "inside planes:   phimin = ", (180/M_PI) * facephimin,
+		      " phimax = ", (180/M_PI) * facephimax);
+	PrintMessage (1, "");      
+      }
+    else
+      {
+	retvalues[0] = (180/M_PI) * facephimin;
+	retvalues[1] = (180/M_PI) * facephimax;
+	retvalues[2] = (180/M_PI) * phimin;
+	retvalues[3] = (180/M_PI) * phimax;
+      }
+    PrintMessage (3, "negative tets: ", negativetets);
+    PrintMessage (3, "illegal tets:  ", illegaltets);
+    PrintMessage (3, "bad tets:      ", badtets);
+  }
+
+
+  int Mesh :: MarkIllegalElements ()
+  {
+    int cnt = 0;
+    int i;
+
+    for (i = 1; i <= GetNE(); i++)
+      {
+	LegalTet (VolumeElement(i));
+
+	/*
+	  Element & el = VolumeElement(i);
+	  int leg1 = LegalTet (el);
+	  el.flags.illegal_valid = 0;
+	  int leg2 = LegalTet (el);
+
+	  if (leg1 != leg2) 
+	  {
+	  cerr << "legal differs!!" << endl;
+	  (*testout) << "legal differs" << endl;
+	  (*testout) << "elnr = " << i << ", el = " << el
+	  << " leg1 = " << leg1 << ", leg2 = " << leg2 << endl;
+	  }
+      
+	  //      el.flags.illegal = !LegalTet (el);
+	  */
+	cnt += VolumeElement(i).Illegal();
+      }
+    return cnt;
+  }
+
+// #ifdef NONE
+//   void Mesh :: AddIdentification (int pi1, int pi2, int identnr)
+//   {
+//     INDEX_2 pair(pi1, pi2);
+//     //  pair.Sort();
+//     identifiedpoints->Set (pair, identnr);
+//     if (identnr > maxidentnr)
+//       maxidentnr = identnr;
+//     timestamp = NextTimeStamp();
+//   }
+
+//   int Mesh :: GetIdentification (int pi1, int pi2) const
+//   {
+//     INDEX_2 pair(pi1, pi2);
+//     if (identifiedpoints->Used (pair))
+//       return identifiedpoints->Get(pair);
+//     else
+//       return 0;
+//   }
+
+//   int Mesh :: GetIdentificationSym (int pi1, int pi2) const
+//   {
+//     INDEX_2 pair(pi1, pi2);
+//     if (identifiedpoints->Used (pair))
+//       return identifiedpoints->Get(pair);
+
+//     pair = INDEX_2 (pi2, pi1);
+//     if (identifiedpoints->Used (pair))
+//       return identifiedpoints->Get(pair);
+
+//     return 0;
+//   }
+
+
+//   void Mesh :: GetIdentificationMap (int identnr, ARRAY<int> & identmap) const
+//   {
+//     int i, j;
+
+//     identmap.SetSize (GetNP());
+//     for (i = 1; i <= identmap.Size(); i++)
+//       identmap.Elem(i) = 0;
+
+//     for (i = 1; i <= identifiedpoints->GetNBags(); i++)
+//       for (j = 1; j <= identifiedpoints->GetBagSize(i); j++)
+// 	{
+// 	  INDEX_2 i2;
+// 	  int nr;
+// 	  identifiedpoints->GetData (i, j, i2, nr);
+	
+// 	  if (nr == identnr)
+// 	    {
+// 	      identmap.Elem(i2.I1()) = i2.I2();
+// 	    }
+// 	}
+//   }
+
+
+//   void Mesh :: GetIdentificationPairs (int identnr, ARRAY<INDEX_2> & identpairs) const
+//   {
+//     int i, j;
+
+//     identpairs.SetSize(0);
+
+//     for (i = 1; i <= identifiedpoints->GetNBags(); i++)
+//       for (j = 1; j <= identifiedpoints->GetBagSize(i); j++)
+// 	{
+// 	  INDEX_2 i2;
+// 	  int nr;
+// 	  identifiedpoints->GetData (i, j, i2, nr);
+	
+// 	  if (identnr == 0 || nr == identnr)
+// 	    identpairs.Append (i2);
+// 	}
+//   }
+// #endif
+
+  
+
+  void Mesh :: InitPointCurve(double red, double green, double blue) const
+  {
+    pointcurves_startpoint.Append(pointcurves.Size());
+    pointcurves_red.Append(red);
+    pointcurves_green.Append(green);
+    pointcurves_blue.Append(blue);
+  }
+  void Mesh :: AddPointCurvePoint(const Point3d & pt) const
+  {
+    pointcurves.Append(pt);
+  }
+  int Mesh :: GetNumPointCurves(void) const
+  {
+    return pointcurves_startpoint.Size();
+  }
+  int Mesh :: GetNumPointsOfPointCurve(int curve) const
+  {
+    if(curve == pointcurves_startpoint.Size()-1)
+      return (pointcurves.Size() - pointcurves_startpoint.Last());
+    else
+      return (pointcurves_startpoint[curve+1]-pointcurves_startpoint[curve]);
+  }
+
+  Point3d & Mesh :: GetPointCurvePoint(int curve, int n) const
+  {
+    return pointcurves[pointcurves_startpoint[curve]+n];
+  }
+
+  void Mesh :: GetPointCurveColor(int curve, double & red, double & green, double & blue) const
+  {
+    red = pointcurves_red[curve];
+    green = pointcurves_green[curve];
+    blue = pointcurves_blue[curve];
+  }
+  
+
+  void Mesh :: ComputeNVertices ()
+  {
+    int i, j, nv;
+    int ne = GetNE();
+    int nse = GetNSE();
+
+    numvertices = 0;
+    for (i = 1; i <= ne; i++)
+      {
+	const Element & el = VolumeElement(i);
+	nv = el.GetNV();
+	for (j = 0; j < nv; j++)
+	  if (el[j] > numvertices)
+	    numvertices = el[j];
+      }
+    for (i = 1; i <= nse; i++)
+      {
+	const Element2d & el = SurfaceElement(i);
+	nv = el.GetNV();
+	for (j = 1; j <= nv; j++)
+	  if (el.PNum(j) > numvertices)
+	    numvertices = el.PNum(j);
+      } 
+
+    numvertices += 1- PointIndex::BASE;
+  }
+
+  int Mesh :: GetNV () const
+  {
+    if (numvertices < 0)
+      return GetNP();
+    else
+      return numvertices;
+  }
+
+  void Mesh :: SetNP (int np)
+  {
+    points.SetSize(np);
+    //  ptyps.SetSize(np);
+
+    int mlold = mlbetweennodes.Size();
+    mlbetweennodes.SetSize(np);
+    if (np > mlold)
+      for (int i = mlold+PointIndex::BASE; 
+	   i < np+PointIndex::BASE; i++)
+	{
+	  mlbetweennodes[i].I1() = PointIndex::BASE-1;
+	  mlbetweennodes[i].I2() = PointIndex::BASE-1;
+	}
+
+    GetIdentifications().SetMaxPointNr (np + PointIndex::BASE-1);
+  }
+
+
+  /*
+    void Mesh :: BuildConnectedNodes ()
+    {
+    if (PureTetMesh())
+    {
+    connectedtonode.SetSize(0);
+    return;
+    }
+
+
+    int i, j, k;
+    int np = GetNP();
+    int ne = GetNE();
+    TABLE<int> conto(np);
+    for (i = 1; i <= ne; i++)
+    {
+    const Element & el = VolumeElement(i);
+
+    if (el.GetType() == PRISM)
+    {
+    for (j = 1; j <= 6; j++)
+    {
+    int n1 = el.PNum (j);
+    int n2 = el.PNum ((j+2)%6+1);
+    //	    if (n1 != n2)
+    {
+    int found = 0;
+    for (k = 1; k <= conto.EntrySize(n1); k++)
+    if (conto.Get(n1, k) == n2)
+    {
+    found = 1;
+    break;
+    }
+    if (!found)
+    conto.Add (n1, n2);
+    }
+    }
+    }
+    else if (el.GetType() == PYRAMID)
+    {
+    for (j = 1; j <= 4; j++)
+    {
+    int n1, n2;
+    switch (j)
+    {
+    case 1: n1 = 1; n2 = 4; break;
+    case 2: n1 = 4; n2 = 1; break;
+    case 3: n1 = 2; n2 = 3; break;
+    case 4: n1 = 3; n2 = 2; break;
+    }
+
+    int found = 0;
+    for (k = 1; k <= conto.EntrySize(n1); k++)
+    if (conto.Get(n1, k) == n2)
+    {
+    found = 1;
+    break;
+    }
+    if (!found)
+    conto.Add (n1, n2);
+    }
+    }
+    }
+  
+    connectedtonode.SetSize(np);
+    for (i = 1; i <= np; i++)
+    connectedtonode.Elem(i) = 0;
+  
+    for (i = 1; i <= np; i++)
+    if (connectedtonode.Elem(i) == 0)
+    {
+    connectedtonode.Elem(i) = i;
+    ConnectToNodeRec (i, i, conto);
+    }
+  
+
+
+    }
+
+    void Mesh :: ConnectToNodeRec (int node, int tonode, 
+    const TABLE<int> & conto)
+    {
+    int i, n2;
+    //  (*testout) << "connect " << node << " to " << tonode << endl;
+    for (i = 1; i <= conto.EntrySize(node); i++)
+    {
+    n2 = conto.Get(node, i);
+    if (!connectedtonode.Get(n2))
+    {
+    connectedtonode.Elem(n2) = tonode;
+    ConnectToNodeRec (n2, tonode, conto);
+    }
+    }
+    }
+  */
+
+
+  bool Mesh :: PureTrigMesh (int faceindex) const
+  {
+    if (!faceindex)
+      return !mparam.quad;
+
+    int i;
+    for (i = 1; i <= GetNSE(); i++)
+      if (SurfaceElement(i).GetIndex() == faceindex &&
+	  SurfaceElement(i).GetNP() != 3)
+	return 0;
+    return 1;
+  }
+
+  bool Mesh :: PureTetMesh () const
+  {
+    for (ElementIndex ei = 0; ei < GetNE(); ei++)
+      if (VolumeElement(ei).GetNP() != 4)
+	return 0;
+    return 1;
+  }
+
+  void Mesh :: UpdateTopology()
+  {
+    topology->Update();
+    clusters->Update();
+  }
+
+
+  void Mesh :: SetMaterial (int domnr, const char * mat)
+  {
+    if (domnr > materials.Size())
+      {
+	int olds = materials.Size();
+	materials.SetSize (domnr);
+	for (int i = olds; i < domnr; i++)
+	  materials[i] = 0;
+      }
+    materials.Elem(domnr) = new char[strlen(mat)+1];
+    strcpy (materials.Elem(domnr), mat);
+  }
+
+  const char * Mesh :: GetMaterial (int domnr) const
+  {
+    if (domnr <= materials.Size())
+      return materials.Get(domnr);
+    return 0;
+  }
+
+  void Mesh ::SetNBCNames ( int nbcn )
+  {
+    if ( bcnames.Size() )
+      for ( int i = 0; i < bcnames.Size(); i++)
+	if ( bcnames[i] ) delete bcnames[i];
+    bcnames.SetSize(nbcn);
+    bcnames = 0;
+  }
+
+  void Mesh ::SetBCName ( int bcnr, const string & abcname )
+  {
+    if ( bcnames[bcnr] ) delete bcnames[bcnr];
+    if ( abcname != "default" )
+      bcnames[bcnr] = new string ( abcname );
+    else
+      bcnames[bcnr] = 0;
+  }
+
+  string Mesh ::GetBCName ( int bcnr ) const
+  {
+    if ( !bcnames.Size() )
+      return "default";
+    if ( bcnames[bcnr] )
+      return *bcnames[bcnr];
+    else
+      return "default";
+  }
+
+  void Mesh :: SetUserData(const char * id, ARRAY<int> & data)
+  {
+    if(userdata_int.Used(id))
+      delete userdata_int.Get(id);
+
+    ARRAY<int> * newdata = new ARRAY<int>(data);
+
+    userdata_int.Set(id,newdata);      
+  }
+  bool Mesh :: GetUserData(const char * id, ARRAY<int> & data, int shift) const
+  {
+    if(userdata_int.Used(id))
+      {
+	if(data.Size() < (*userdata_int.Get(id)).Size()+shift)
+	  data.SetSize((*userdata_int.Get(id)).Size()+shift);
+	for(int i=0; i<(*userdata_int.Get(id)).Size(); i++)
+	  data[i+shift] = (*userdata_int.Get(id))[i];
+	return true;
+      }
+    else
+      {
+	data.SetSize(0);
+	return false;
+      }
+  }
+  void Mesh :: SetUserData(const char * id, ARRAY<double> & data)
+  {
+    if(userdata_double.Used(id))
+      delete userdata_double.Get(id);
+
+    ARRAY<double> * newdata = new ARRAY<double>(data);
+
+    userdata_double.Set(id,newdata);      
+  }
+  bool Mesh :: GetUserData(const char * id, ARRAY<double> & data, int shift) const
+  {
+    if(userdata_double.Used(id))
+      {
+	if(data.Size() < (*userdata_double.Get(id)).Size()+shift)
+	  data.SetSize((*userdata_double.Get(id)).Size()+shift);
+	for(int i=0; i<(*userdata_double.Get(id)).Size(); i++)
+	  data[i+shift] = (*userdata_double.Get(id))[i];
+	return true;
+      }
+    else
+      {
+	data.SetSize(0);
+	return false;
+      }
+  }
+  
+
+
+  void Mesh :: PrintMemInfo (ostream & ost) const
+  {
+    ost << "Mesh Mem:" << endl;
+
+    ost << GetNP() << " Points, of size " 
+	<< sizeof (Point3d) << " + " << sizeof(POINTTYPE) << " = "
+	<< GetNP() * (sizeof (Point3d) + sizeof(POINTTYPE)) << endl;
+
+    ost << GetNSE() << " Surface elements, of size " 
+	<< sizeof (Element2d) << " = " 
+	<< GetNSE() * sizeof(Element2d) << endl;
+
+    ost << GetNE() << " Volume elements, of size " 
+	<< sizeof (Element) << " = " 
+	<< GetNE() * sizeof(Element) << endl;
+
+    ost << "surfs on node:";
+    surfacesonnode.PrintMemInfo (cout);
+  
+    ost << "boundaryedges: ";
+    if (boundaryedges)
+      boundaryedges->PrintMemInfo (cout);
+
+    ost << "surfelementht: ";
+    if (surfelementht)
+      surfelementht->PrintMemInfo (cout);
+  }
+}
diff --git a/contrib/Netgen/libsrc/meshing/meshclass.hpp b/contrib/Netgen/libsrc/meshing/meshclass.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..4dab869d3427a49f8470ef101a85c1583f39ae89
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/meshclass.hpp
@@ -0,0 +1,777 @@
+#ifndef MESHCLASS
+#define MESHCLASS
+
+/**************************************************************************/
+/* File:   meshclass.hpp                                                  */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   20. Nov. 99                                                    */
+/**************************************************************************/
+
+/*
+  The mesh class
+*/
+
+
+
+enum resthtype { RESTRICTH_FACE, RESTRICTH_EDGE, 
+		 RESTRICTH_SURFACEELEMENT, RESTRICTH_POINT, RESTRICTH_SEGMENT };
+
+class HPRefElement;
+
+
+/// 2d/3d mesh
+class Mesh
+{
+public:
+  typedef MoveableArray<MeshPoint,PointIndex::BASE> T_POINTS;
+  typedef MoveableArray<Element> T_VOLELEMENTS;
+  typedef MoveableArray<Element2d> T_SURFELEMENTS;
+
+  // typedef ARRAY<MeshPoint,PointIndex::BASE> T_POINTS;
+  // typedef ARRAY<Element> T_VOLELEMENTS;
+  // typedef ARRAY<Element2d> T_SURFELEMENTS;
+
+
+private:
+  /// point coordinates
+  T_POINTS points;
+
+  /// type of element, set in calcsurfacesofnode
+  // ARRAY<ELEMENTTYPE> eltyps;
+
+  /// line-segments at edges
+  ARRAY<Segment> segments;
+  /// surface elements, 2d-inner elements
+  T_SURFELEMENTS surfelements;
+  /// volume elements
+  T_VOLELEMENTS volelements;
+  /// points will be fixed forever
+  ARRAY<PointIndex> lockedpoints;
+
+
+  /// surface indices at boundary nodes
+  TABLE<int,PointIndex::BASE> surfacesonnode;
+  /// boundary edges  (1..normal bedge, 2..segment)
+  INDEX_2_CLOSED_HASHTABLE<int> * boundaryedges;
+  ///
+  INDEX_2_CLOSED_HASHTABLE<int> * segmentht;
+  ///
+  INDEX_3_CLOSED_HASHTABLE<int> * surfelementht;
+
+  /// faces of rest-solid
+  ARRAY<Element2d> openelements;
+  /// open segmenets for surface meshing  
+  ARRAY<Segment> opensegments;
+
+
+
+  /**
+     Representation of local mesh-size h
+  */
+  LocalH * lochfunc;
+  ///
+  double hglob;
+  ///
+  double hmin;
+  ///
+  ARRAY<double> maxhdomain;
+  
+  /**
+     the face-index of the surface element maps into
+     this table.
+  */
+  ARRAY<FaceDescriptor> facedecoding;
+
+  /// sub-domain materials 
+  ARRAY<char*> materials;
+
+  ARRAY<string*, 0> bcnames;
+
+  /// Periodic surface, close surface, etc. identifications
+  Identifications * ident;
+
+
+  /// number of vertices (if < 0, use np)
+  int numvertices;
+
+  /// geometric search tree for interval intersection search
+  Box3dTree * elementsearchtree;
+  /// time stamp for tree
+  int elementsearchtreets;
+
+  /// element -> face, element -> edge etc ...
+  class MeshTopology * topology;
+  /// methods for high order elements
+  class CurvedElements * curvedelems;
+
+  /// nodes identified by close points 
+  class AnisotropicClusters * clusters;
+
+  /// space dimension (2 or 3)
+  int dimension;
+  
+  /// changed by every minor modification (addpoint, ...)
+  int timestamp;
+  /// changed after finishing global algorithm (improve, ...)
+  int majortimestamp;
+
+  /// mesh access semaphors.
+  NgMutex mutex;
+  /// mesh access semaphors.
+  NgMutex majormutex;
+
+  SYMBOLTABLE< ARRAY<int>* > userdata_int;
+  SYMBOLTABLE< ARRAY<double>* > userdata_double; 
+
+
+  mutable ARRAY< Point3d > pointcurves;
+  mutable ARRAY<int> pointcurves_startpoint;
+  mutable ARRAY<double> pointcurves_red,pointcurves_green,pointcurves_blue;
+
+
+  /// start element for point search (GetElementOfPoint)
+  mutable int ps_startelement;
+
+
+#ifdef PARALLEL
+  /// connection to parallel meshes
+  class ParallelMeshTopology * paralleltop;
+
+#endif
+
+
+private:
+  void BuildBoundaryEdges(void);
+
+public:
+  bool PointContainedIn2DElement(const Point3d & p,
+				 double lami[3],
+				 const int element,
+				 bool consider3D = false) const;
+  bool PointContainedIn3DElement(const Point3d & p,
+				 double lami[3],
+				 const int element) const;
+  bool PointContainedIn3DElementOld(const Point3d & p,
+				    double lami[3],
+				    const int element) const;
+
+public:
+
+  // store coarse mesh before hp-refinement
+  ARRAY<HPRefElement> * hpelements;
+  Mesh * coarsemesh;
+  
+  
+  /// number of refinement levels
+  int mglevels;
+  /// refinement hierarchy
+  ARRAY<INDEX_2,PointIndex::BASE> mlbetweennodes;
+  /// parent element of volume element
+  ARRAY<int> mlparentelement;
+  /// parent element of surface element
+  ARRAY<int> mlparentsurfaceelement;
+
+
+
+  ///
+  Mesh();
+  ///
+  ~Mesh();
+
+  Mesh & operator= (const Mesh & mesh2);
+  
+  ///
+  void DeleteMesh();
+  
+  ///
+  void ClearSurfaceElements()
+  { 
+    surfelements.SetSize(0); 
+    timestamp = NextTimeStamp();
+  }
+
+  ///
+  void ClearVolumeElements()
+  {
+    volelements.SetSize(0); 
+    // eltyps.SetSize(0);
+    timestamp = NextTimeStamp();
+  }
+
+  ///
+  void ClearSegments()
+  { 
+    segments.SetSize(0); 
+    timestamp = NextTimeStamp();
+  }
+  
+  ///
+  bool TestOk () const;
+
+  void SetAllocSize(int nnodes, int nsegs, int nsel, int nel);
+
+
+  PointIndex AddPoint (const Point3d & p, int layer = 1);
+  PointIndex AddPoint (const Point3d & p, int layer, POINTTYPE type);
+#ifdef PARALLEL
+  PointIndex AddPoint (const Point3d & p, bool aisghost, int layer = 1);
+  PointIndex AddPoint (const Point3d & p, bool aisghost, int layer, POINTTYPE type);
+#endif
+  int GetNP () const { return points.Size(); }
+
+  MeshPoint & Point(int i) { return points.Elem(i); }
+  MeshPoint & Point(PointIndex pi) { return points[pi]; }
+  const MeshPoint & Point(int i) const { return points.Get(i); }
+  const MeshPoint & Point(PointIndex pi) const { return points[pi]; }
+
+  const MeshPoint & operator[] (PointIndex pi) const { return points[pi]; }
+  MeshPoint & operator[] (PointIndex pi) { return points[pi]; }
+
+  const T_POINTS & Points() const { return points; }
+  T_POINTS & Points() { return points; }
+
+
+  SegmentIndex AddSegment (const Segment & s);
+  void DeleteSegment (int segnr)
+  {
+    segments.Elem(segnr).p1 = PointIndex::BASE-1;
+    segments.Elem(segnr).p2 = PointIndex::BASE-1;
+  }
+  void FullDeleteSegment (int segnr)
+  {
+    segments.Delete(segnr-PointIndex::BASE);
+  }
+
+  int GetNSeg () const { return segments.Size(); }
+  Segment & LineSegment(int i) { return segments.Elem(i); }
+  const Segment & LineSegment(int i) const { return segments.Get(i); }
+
+  Segment & LineSegment(SegmentIndex si) { return segments[si]; }
+  const Segment & LineSegment(SegmentIndex si) const { return segments[si]; }
+  const Segment & operator[] (SegmentIndex si) const { return segments[si]; }
+  Segment & operator[] (SegmentIndex si) { return segments[si]; }
+
+
+
+
+  SurfaceElementIndex AddSurfaceElement (const Element2d & el);
+  void DeleteSurfaceElement (int eli)
+  { 
+    surfelements.Elem(eli).Delete();
+    surfelements.Elem(eli).PNum(1) = -1; 
+    surfelements.Elem(eli).PNum(2) = -1; 
+    surfelements.Elem(eli).PNum(3) = -1; 
+    timestamp = NextTimeStamp();
+  }
+
+  void DeleteSurfaceElement (SurfaceElementIndex eli)
+  {
+    DeleteSurfaceElement (int(eli)+1);
+  }
+
+  int GetNSE () const { return surfelements.Size(); }
+  Element2d & SurfaceElement(int i) { return surfelements.Elem(i); }
+  const Element2d & SurfaceElement(int i) const { return surfelements.Get(i); }
+
+  Element2d & SurfaceElement(SurfaceElementIndex i)
+  { return surfelements[i]; }
+  const Element2d & SurfaceElement(SurfaceElementIndex i) const
+  { return surfelements[i]; }
+
+  const Element2d & operator[] (SurfaceElementIndex ei) const
+  { return surfelements[ei]; }
+  Element2d & operator[] (SurfaceElementIndex ei)
+  { return surfelements[ei]; }
+
+  
+  void GetSurfaceElementsOfFace (int facenr, ARRAY<SurfaceElementIndex> & sei) const;
+
+  ElementIndex AddVolumeElement (const Element & el);
+
+  int GetNE () const { return volelements.Size(); }
+
+  Element & VolumeElement(int i) { return volelements.Elem(i); }
+  const Element & VolumeElement(int i) const { return volelements.Get(i); }
+  Element & VolumeElement(ElementIndex i) { return volelements[i]; }
+  const Element & VolumeElement(ElementIndex i) const { return volelements[i]; }
+
+  const Element & operator[] (ElementIndex ei) const 
+  { return volelements[ei]; }
+  Element & operator[] (ElementIndex ei)
+  { return volelements[ei]; }
+
+
+
+
+  // ELEMENTTYPE ElementType (int i) const { return eltyps.Get(i); }
+
+
+  // ELEMENTTYPE ElementType (int i) const 
+  // { return (volelements.Get(i).fixed) ? FIXEDELEMENT : FREEELEMENT; }
+
+  ELEMENTTYPE ElementType (ElementIndex i) const 
+  { return (volelements[i].flags.fixed) ? FIXEDELEMENT : FREEELEMENT; }
+
+  /*
+  ELEMENTTYPE ElementType (int i) const { return eltyps.Get(i); }
+  ELEMENTTYPE ElementType (ElementIndex i) const { return eltyps[i]; }
+  */
+
+  const T_VOLELEMENTS & VolumeElements() const { return volelements; }
+  T_VOLELEMENTS & VolumeElements() { return volelements; }
+
+
+  ///
+  double ElementError (int eli) const;
+
+  /// 
+  void AddLockedPoint (PointIndex pi);
+  ///
+  void ClearLockedPoints ();
+
+  const ARRAY<PointIndex> & LockedPoints() const
+  { return lockedpoints; }
+
+  /// Returns number of domains
+  int GetNDomains() const;
+
+
+  ///
+  int GetDimension() const 
+  { return dimension; }
+  void SetDimension(int dim)
+  { dimension = dim; }
+
+  /// sets internal tables
+  void CalcSurfacesOfNode ();
+
+  /// additional (temporarily) fix points 
+  void FixPoints (const BitArray & fixpoints);
+
+  /**
+     finds elements without neighbour and
+     boundary elements without inner element.
+     Results are stored in openelements.
+     if dom == 0, all sub-domains, else subdomain dom */
+  void FindOpenElements (int dom = 0);
+
+  
+  /**
+     finds segments without surface element,
+     and surface elements without neighbours.
+     store in opensegmentsy
+  */
+  void FindOpenSegments (int surfnr = 0);
+  /**
+     remove one layer of surface elements
+  */
+  void RemoveOneLayerSurfaceElements ();
+
+
+  int GetNOpenSegments () { return opensegments.Size(); }
+  const Segment & GetOpenSegment (int nr) { return opensegments.Get(nr); }
+  
+  /**
+     Checks overlap of boundary
+     return == 1, iff overlap
+  */
+  int CheckOverlappingBoundary ();
+  /**
+     Checks consistent boundary
+     return == 0, everything ok
+  */
+  int CheckConsistentBoundary () const;
+
+  /*
+    checks element orientation
+  */
+  int CheckVolumeMesh () const;
+
+
+  /**
+     finds average h of surface surfnr if surfnr > 0,
+     else of all surfaces.
+  */
+  double AverageH (int surfnr = 0) const;
+  /// Calculates localh 
+  void CalcLocalH ();
+  ///
+  void SetLocalH (const Point3d & pmin, const Point3d & pmax, double grading);
+  ///
+  void RestrictLocalH (const Point3d & p, double hloc);
+  ///
+  void RestrictLocalHLine (const Point3d & p1, const Point3d & p2, 
+			   double hloc);
+  /// number of elements per radius
+  void CalcLocalHFromSurfaceCurvature(double elperr);
+  ///
+  void CalcLocalHFromPointDistances(void);
+  ///
+  void RestrictLocalH (resthtype rht, int nr, double loch);
+  ///
+  void LoadLocalMeshSize (const char * meshsizefilename);
+  ///
+  void SetGlobalH (double h);
+  ///
+  void SetMinimalH (double h);
+  ///
+  double MaxHDomain (int dom) const;
+  ///
+  void SetMaxHDomain (const ARRAY<double> & mhd);
+  ///
+  double GetH (const Point3d & p) const;
+  ///
+  double GetMinH (const Point3d & pmin, const Point3d & pmax);
+  ///
+  LocalH & LocalHFunction () { return * lochfunc; }
+  ///
+  bool LocalHFunctionGenerated(void) const { return (lochfunc != NULL); }
+
+  /// Find bounding box
+  void GetBox (Point3d & pmin, Point3d & pmax, int dom = -1) const;
+
+  /// Find bounding box of points of typ ptyp or less
+  void GetBox (Point3d & pmin, Point3d & pmax, POINTTYPE ptyp ) const;
+
+  ///
+  int GetNOpenElements() const
+  { return openelements.Size(); }
+  ///
+  const Element2d & OpenElement(int i) const
+  { return openelements.Get(i); }
+
+
+  /// are also quads open elements
+  bool HasOpenQuads () const;
+
+  /// split into connected pieces
+  void SplitIntoParts ();
+
+  /// 
+  void SplitSeparatedFaces ();
+
+  /// Refines mesh and projects points to true surface
+  // void Refine (int levels, const CSGeometry * geom);
+  
+
+  bool BoundaryEdge (PointIndex pi1, PointIndex pi2) const
+  {
+    if(!boundaryedges)
+      const_cast<Mesh *>(this)->BuildBoundaryEdges();
+
+    INDEX_2 i2 (pi1, pi2);
+    i2.Sort();
+    return boundaryedges->Used (i2);
+  }
+
+  bool IsSegment (PointIndex pi1, PointIndex pi2) const
+  {
+    INDEX_2 i2 (pi1, pi2);
+    i2.Sort();
+    return segmentht->Used (i2);
+  }
+
+  SegmentIndex SegmentNr (PointIndex pi1, PointIndex pi2) const
+  {
+    INDEX_2 i2 (pi1, pi2);
+    i2.Sort();
+    return segmentht->Get (i2);
+  }
+
+
+  /**
+     Remove unused points. etc.
+  */
+  void Compress ();
+
+  ///
+  void Save (ostream & outfile) const;
+  ///
+  void Load (istream & infile);
+  ///
+  void Merge (istream & infile, const int surfindex_offset = 0);
+  ///
+  void Save (const string & filename) const;
+  ///
+  void Load (const string & filename);
+  ///
+  void Merge (const string & filename, const int surfindex_offset = 0);
+
+
+  ///
+  void ImproveMesh (OPTIMIZEGOAL goal = OPT_QUALITY);
+
+  ///
+  void ImproveMeshJacobian (OPTIMIZEGOAL goal = OPT_QUALITY, const BitArray * usepoint = NULL);
+  ///
+  void ImproveMeshJacobianOnSurface (const BitArray & usepoint, 
+				     const ARRAY< Vec<3>* > & nv,
+				     OPTIMIZEGOAL goal = OPT_QUALITY,
+				     const ARRAY< ARRAY<int,PointIndex::BASE>* > * idmaps = NULL);
+  /*
+#ifdef SOLIDGEOM
+  /// old
+  void ImproveMesh (const CSGeometry & surfaces, 
+		    OPTIMIZEGOAL goal = OPT_QUALITY);
+#endif  
+  */
+
+  /**
+     free nodes in environment of openelements 
+     for optimiztion
+  */
+  void FreeOpenElementsEnvironment (int layers);
+
+  ///
+  bool LegalTet (Element & el) const
+  {
+    if (el.IllegalValid())
+      return !el.Illegal();
+    return LegalTet2 (el);
+  }
+  ///
+  bool LegalTet2 (Element & el) const;
+
+
+  ///
+  bool LegalTrig (const Element2d & el) const;
+  /**
+     if values non-null, return values in 4-double array:
+     triangle angles min/max, tetangles min/max
+     if null, output results on cout
+  */
+  void CalcMinMaxAngle (double badellimit, double * retvalues = NULL);
+
+  /*
+    Marks elements which are dangerous to refine
+    return: number of illegal elements
+  */
+  int MarkIllegalElements ();
+
+  /// orient surface mesh, for one sub-domain only
+  void SurfaceMeshOrientation ();
+
+  /// convert mixed element mesh to tet-mesh
+  void Split2Tets();
+
+
+  /// build box-search tree
+  void BuildElementSearchTree ();
+
+  void SetPointSearchStartElement(const int el) const {ps_startelement = el;}
+
+  /// gives element of point, barycentric coordinates
+  int GetElementOfPoint (const Point3d & p,
+			 double * lami,
+			 bool build_searchtree = 0,
+			 const int index = -1,
+			 const bool allowindex = true) const;
+  int GetElementOfPoint (const Point3d & p,
+			 double * lami,
+			 const ARRAY<int> * const indices,
+			 bool build_searchtree = 0,
+			 const bool allowindex = true) const;
+  int GetSurfaceElementOfPoint (const Point3d & p,
+				double * lami,
+				bool build_searchtree = 0,
+				const int index = -1,
+				const bool allowindex = true) const;
+  int GetSurfaceElementOfPoint (const Point3d & p,
+				double * lami,
+				const ARRAY<int> * const indices,
+				bool build_searchtree = 0,
+				const bool allowindex = true) const;
+
+  /// give list of vol elements which are int the box(p1,p2)
+  void GetIntersectingVolEls(const Point3d& p1, const Point3d& p2, 
+			     ARRAY<int> & locels) const;
+
+  ///
+  int AddFaceDescriptor(const FaceDescriptor& fd)
+  { return facedecoding.Append(fd); }
+
+
+  ///
+  void SetMaterial (int domnr, const char * mat);
+  ///
+  const char * GetMaterial (int domnr) const;
+    
+  void SetNBCNames ( int nbcn );
+
+  void SetBCName ( int bcnr, const string & abcname );
+
+  string GetBCName ( int bcnr ) const;
+
+  string * GetBCNamePtr ( int bcnr )
+  { return bcnames[bcnr]; }
+
+  ///
+  void ClearFaceDescriptors()
+  { facedecoding.SetSize(0); }
+
+  ///
+  int GetNFD () const
+  { return facedecoding.Size(); }
+
+  const FaceDescriptor & GetFaceDescriptor (int i) const
+  { return facedecoding.Get(i); }
+
+  ///
+  FaceDescriptor & GetFaceDescriptor (int i) 
+  { return facedecoding.Elem(i); }
+
+// #ifdef NONE
+//   /*
+//     Identify points pi1 and pi2, due to
+//     identification nr identnr
+//   */
+//   void AddIdentification (int pi1, int pi2, int identnr);
+
+//   int GetIdentification (int pi1, int pi2) const;
+//   int GetIdentificationSym (int pi1, int pi2) const;
+//   ///
+//   INDEX_2_HASHTABLE<int> & GetIdentifiedPoints () 
+//   { 
+//     return *identifiedpoints; 
+//   }
+
+//   ///
+//   void GetIdentificationMap (int identnr, ARRAY<int> & identmap) const;
+//   ///
+//   void GetIdentificationPairs (int identnr, ARRAY<INDEX_2> & identpairs) const;
+//   ///
+//   int GetMaxIdentificationNr () const
+//   { 
+//     return maxidentnr; 
+//   }
+// #endif
+
+  /// return periodic, close surface etc. identifications
+  Identifications & GetIdentifications () { return *ident; }
+  /// return periodic, close surface etc. identifications
+  const Identifications & GetIdentifications () const { return *ident; }
+
+
+  void InitPointCurve(double red = 1, double green = 0, double blue = 0) const;
+  void AddPointCurvePoint(const Point3d & pt) const;
+  int GetNumPointCurves(void) const;
+  int GetNumPointsOfPointCurve(int curve) const;
+  Point3d & GetPointCurvePoint(int curve, int n) const;
+  void GetPointCurveColor(int curve, double & red, double & green, double & blue) const;
+
+
+
+
+  /// find number of vertices
+  void ComputeNVertices ();
+  /// number of vertices (no edge-midpoints)
+  int GetNV () const;
+  /// remove edge points
+  void SetNP (int np);
+
+  
+
+
+  /*
+ /// build connected nodes along prism stack
+ void BuildConnectedNodes ();
+ void ConnectToNodeRec (int node, int tonode, 
+ const TABLE<int> & conto);
+  */
+
+  bool PureTrigMesh (int faceindex = 0) const;
+  bool PureTetMesh () const;
+
+
+  const class MeshTopology & GetTopology () const
+  { return *topology; }
+
+  void UpdateTopology();
+  
+  class CurvedElements & GetCurvedElements () const
+  { return *curvedelems; }
+
+  const class AnisotropicClusters & GetClusters () const
+  { return *clusters; }
+
+  int GetTimeStamp() const { return timestamp; }
+  void SetNextTimeStamp() 
+  { timestamp = NextTimeStamp(); }
+
+  int GetMajorTimeStamp() const { return majortimestamp; }
+  void SetNextMajorTimeStamp() 
+  { majortimestamp = timestamp = NextTimeStamp(); }
+
+
+  /// return mutex
+  NgMutex & Mutex ()   { return mutex; }
+  NgMutex & MajorMutex ()   { return majormutex; }
+
+
+  ///
+  void SetUserData(const char * id, ARRAY<int> & data);
+  ///
+  bool GetUserData(const char * id, ARRAY<int> & data, int shift = 0) const;
+  ///
+  void SetUserData(const char * id, ARRAY<double> & data);
+  ///
+  bool GetUserData(const char * id, ARRAY<double> & data, int shift = 0) const;
+
+  ///
+  friend void OptimizeRestart (Mesh & mesh3d);
+  ///
+  void PrintMemInfo (ostream & ost) const;
+  /// 
+  friend class Meshing3;
+
+
+  enum GEOM_TYPE { NO_GEOM = 0, GEOM_2D = 1, GEOM_CSG = 10, GEOM_STL = 11, GEOM_OCC = 12, GEOM_ACIS = 13 };
+  GEOM_TYPE geomtype;
+  
+
+
+#ifdef PARALLEL
+  /// returns parallel topology
+  class ParallelMeshTopology & GetParallelTopology () const
+  { return *paralleltop; }
+
+
+  /// distributes the master-mesh to local meshes
+  void Distribute ();
+
+  /// loads a mesh sent from master processor
+  void ReceiveParallelMesh ();
+
+  /// find connection to parallel meshes
+//   void FindExchangePoints () ;
+
+//   void FindExchangeEdges ();
+//   void FindExchangeFaces ();
+
+  /// use metis to decompose master mesh 
+  void ParallelMetis (); //  ARRAY<int> & neloc );
+  void PartHybridMesh (); //  ARRAY<int> & neloc );
+  void PartDualHybridMesh (); //  ARRAY<int> & neloc );
+  void PartDualHybridMesh2D ();  // ( ARRAY<int> & neloc );
+
+  /// send mesh to parallel machine, keep global mesh at master 
+  void SendMesh ( ) const;   // Mesh * mastermesh, ARRAY<int> & neloc) const;
+
+  void UpdateOverlap ();
+ 
+#endif
+
+
+};
+
+inline ostream& operator<<(ostream& ost, const Mesh& mesh)
+{
+  ost << "mesh: " << endl;
+  mesh.Save(ost);
+  return ost;
+}
+
+
+#endif
+
+
diff --git a/contrib/Netgen/libsrc/meshing/meshfunc.cpp b/contrib/Netgen/libsrc/meshing/meshfunc.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..06fb451dd4c999e1447e2ee1fcd02a0b59aed086
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/meshfunc.cpp
@@ -0,0 +1,725 @@
+#include <mystdlib.h>
+#include "meshing.hpp"
+
+namespace netgen
+{
+  extern const char * tetrules[];
+  // extern const char * tetrules2[];
+  extern const char * prismrules2[];
+  extern const char * pyramidrules[];
+  extern const char * pyramidrules2[];
+
+
+  extern double teterrpow; 
+  MESHING3_RESULT MeshVolume (MeshingParameters & mp, Mesh& mesh3d)
+  {
+    int i, oldne;
+    PointIndex pi;
+
+    int meshed;
+    int cntsteps; 
+
+
+    ARRAY<INDEX_2> connectednodes;
+
+    mesh3d.Compress();
+
+    //  mesh3d.PrintMemInfo (cout);
+
+    if (mp.checkoverlappingboundary)
+      if (mesh3d.CheckOverlappingBoundary())
+	throw NgException ("Stop meshing since boundary mesh is overlapping");
+
+    int nonconsist = 0;
+    for (int k = 1; k <= mesh3d.GetNDomains(); k++)
+      {
+	PrintMessage (3, "Check subdomain ", k, " / ", mesh3d.GetNDomains());
+
+	mesh3d.FindOpenElements(k);
+
+	/*
+	bool res = mesh3d.CheckOverlappingBoundary();
+	if (res)
+	  {
+	    PrintError ("Surface is overlapping !!");
+	    nonconsist = 1;
+	  }
+	*/
+
+	bool res = (mesh3d.CheckConsistentBoundary() != 0);
+	if (res)
+	  {
+	    PrintError ("Surface mesh not consistent");
+	    nonconsist = 1;
+	  }
+      }
+
+    if (nonconsist)
+      {
+	PrintError ("Stop meshing since surface mesh not consistent");
+	throw NgException ("Stop meshing since surface mesh not consistent");
+      }
+
+    double globmaxh = mp.maxh;
+
+    for (int k = 1; k <= mesh3d.GetNDomains(); k++)
+      {
+	if (multithread.terminate)
+	  break;
+
+	PrintMessage (2, "");
+	PrintMessage (1, "Meshing subdomain ", k, " of ", mesh3d.GetNDomains());
+	(*testout) << "Meshing subdomain " << k << endl;
+ 
+	mp.maxh = min2 (globmaxh, mesh3d.MaxHDomain(k));
+
+	mesh3d.CalcSurfacesOfNode();
+	mesh3d.FindOpenElements(k);
+
+	if (!mesh3d.GetNOpenElements())
+	  continue;
+
+
+	
+	Box<3> domain_bbox( Box<3>::EMPTY_BOX ); 
+        /*
+        Point<3> (1e10, 1e10, 1e10),
+        Point<3> (-1e10, -1e10, -1e10));
+        */
+
+	for (SurfaceElementIndex sei = 0; sei < mesh3d.GetNSE(); sei++)
+	  {
+	    const Element2d & el = mesh3d[sei];
+	    if (el.IsDeleted() ) continue;
+	    
+	    if (mesh3d.GetFaceDescriptor(el.GetIndex()).DomainIn() == k ||
+		mesh3d.GetFaceDescriptor(el.GetIndex()).DomainOut() == k)
+
+	      for (int j = 0; j < el.GetNP(); j++)
+		domain_bbox.Add (mesh3d[el[j]]);
+	  }
+	domain_bbox.Increase (0.01 * domain_bbox.Diam());
+
+
+	for (int qstep = 1; qstep <= 3; qstep++)
+	  {
+	    if (mesh3d.HasOpenQuads())
+	      {
+		string rulefile = ngdir;
+
+		const char ** rulep = NULL;
+		switch (qstep)
+		  {
+		  case 1:
+		    rulefile += "/rules/prisms2.rls";
+		    rulep = prismrules2;
+		    break;
+		  case 2: // connect pyramid to triangle
+		    rulefile += "/rules/pyramids2.rls";
+		    rulep = pyramidrules2;
+		    break;
+		  case 3: // connect to vis-a-vis point
+		    rulefile += "/rules/pyramids.rls";
+		    rulep = pyramidrules;
+		    break;
+		  }
+	      
+		//		Meshing3 meshing(rulefile);
+		Meshing3 meshing(rulep); 
+	      
+		MeshingParameters mpquad = mp;
+	      
+		mpquad.giveuptol = 15;
+		mpquad.baseelnp = 4;
+		mpquad.starshapeclass = 1000;
+		mpquad.check_impossible = qstep == 1;   // for prisms only (air domain in trafo)
+
+
+		for (pi = PointIndex::BASE; 
+		     pi < mesh3d.GetNP()+PointIndex::BASE; pi++)
+		  meshing.AddPoint (mesh3d[pi], pi);
+
+		mesh3d.GetIdentifications().GetPairs (0, connectednodes);
+		for (i = 1; i <= connectednodes.Size(); i++)
+		  meshing.AddConnectedPair (connectednodes.Get(i));
+	      
+		for (i = 1; i <= mesh3d.GetNOpenElements(); i++)
+		  {
+		    Element2d hel = mesh3d.OpenElement(i);
+		    meshing.AddBoundaryElement (hel);
+		  }
+	      
+		oldne = mesh3d.GetNE();
+	      
+		meshing.GenerateMesh (mesh3d, mpquad);
+	      
+		for (i = oldne + 1; i <= mesh3d.GetNE(); i++)
+		  mesh3d.VolumeElement(i).SetIndex (k);
+	      
+		(*testout) 
+		  << "mesh has " << mesh3d.GetNE() << " prism/pyramid�elements" << endl;
+	      
+		mesh3d.FindOpenElements(k);
+	      }
+	  }
+
+
+	if (mesh3d.HasOpenQuads())
+	  {
+	    PrintSysError ("mesh has still open quads");
+	    throw NgException ("Stop meshing since too many attempts");
+	    // return MESHING3_GIVEUP;
+	  }
+
+
+	if (mp.delaunay && mesh3d.GetNOpenElements())
+	  {
+	    Meshing3 meshing((const char**)NULL);
+	 
+	    mesh3d.FindOpenElements(k);
+	  
+
+	    for (pi = PointIndex::BASE; 
+		 pi < mesh3d.GetNP()+PointIndex::BASE; pi++)
+	      meshing.AddPoint (mesh3d[pi], pi);
+	  
+
+	    for (i = 1; i <= mesh3d.GetNOpenElements(); i++)
+	      meshing.AddBoundaryElement (mesh3d.OpenElement(i));
+	  
+	    oldne = mesh3d.GetNE();
+
+	    meshing.Delaunay (mesh3d, k, mp);
+
+	    for (i = oldne + 1; i <= mesh3d.GetNE(); i++)
+	      mesh3d.VolumeElement(i).SetIndex (k);
+
+	    PrintMessage (3, mesh3d.GetNP(), " points, ",
+			  mesh3d.GetNE(), " elements");
+	  }
+
+
+	cntsteps = 0;
+	if (mesh3d.GetNOpenElements())
+	do
+	  {
+	    if (multithread.terminate)
+	      break;
+
+	    mesh3d.FindOpenElements(k);
+	    PrintMessage (5, mesh3d.GetNOpenElements(), " open faces");
+	    cntsteps++;
+
+	    if (cntsteps > mp.maxoutersteps) 
+	      throw NgException ("Stop meshing since too many attempts");
+
+	    string rulefile = ngdir + "/tetra.rls";
+	    PrintMessage (1, "start tetmeshing");
+
+	    //	  Meshing3 meshing(rulefile);
+	    Meshing3 meshing(tetrules);
+      
+	    ARRAY<int, PointIndex::BASE> glob2loc(mesh3d.GetNP());
+	    glob2loc = -1;
+            
+	    for (pi = PointIndex::BASE; 
+		 pi < mesh3d.GetNP()+PointIndex::BASE; pi++)
+	      
+	      if (domain_bbox.IsIn (mesh3d[pi]))
+		glob2loc[pi] = 
+		  meshing.AddPoint (mesh3d[pi], pi);
+
+	    for (i = 1; i <= mesh3d.GetNOpenElements(); i++)
+	      {
+		Element2d hel = mesh3d.OpenElement(i);
+		for (int j = 0; j < hel.GetNP(); j++)
+		  hel[j] = glob2loc[hel[j]];
+		meshing.AddBoundaryElement (hel);
+	    // meshing.AddBoundaryElement (mesh3d.OpenElement(i));
+	      }
+
+	    oldne = mesh3d.GetNE();
+
+	    mp.giveuptol = 15 + 10 * cntsteps; 
+	    mp.sloppy = 5;
+	    meshing.GenerateMesh (mesh3d, mp);
+
+	    for (ElementIndex ei = oldne; ei < mesh3d.GetNE(); ei++)
+	      mesh3d[ei].SetIndex (k);
+	  
+	  
+	    mesh3d.CalcSurfacesOfNode();
+	    mesh3d.FindOpenElements(k);
+	  
+	    teterrpow = 2;
+	    if (mesh3d.GetNOpenElements() != 0)
+	      {
+		meshed = 0;
+		PrintMessage (5, mesh3d.GetNOpenElements(), " open faces found");
+
+		//	      mesh3d.Save ("tmp.vol");
+
+
+		MeshOptimize3d optmesh;
+
+		const char * optstr = "mcmstmcmstmcmstmcm";
+		size_t j;
+		for (j = 1; j <= strlen(optstr); j++)
+		  {
+		    mesh3d.CalcSurfacesOfNode();
+		    mesh3d.FreeOpenElementsEnvironment(2);
+		    mesh3d.CalcSurfacesOfNode();
+
+		    switch (optstr[j-1])
+		      {
+		      case 'c': optmesh.CombineImprove(mesh3d, OPT_REST); break;
+		      case 'd': optmesh.SplitImprove(mesh3d, OPT_REST); break;
+		      case 's': optmesh.SwapImprove(mesh3d, OPT_REST); break;
+		      case 't': optmesh.SwapImprove2(mesh3d, OPT_REST); break;
+		      case 'm': mesh3d.ImproveMesh(OPT_REST); break;
+		      }	  
+
+		  }
+
+		mesh3d.FindOpenElements(k);	      
+		PrintMessage (3, "Call remove problem");
+		RemoveProblem (mesh3d, k);
+		mesh3d.FindOpenElements(k);
+	      }
+	    else
+	      {
+		meshed = 1;
+		PrintMessage (1, "Success !");
+	      }
+	  }
+	while (!meshed);
+
+	PrintMessage (1, mesh3d.GetNP(), " points, ",
+		      mesh3d.GetNE(), " elements");
+      }
+
+    mp.maxh = globmaxh;
+
+    MeshQuality3d (mesh3d);
+
+    return MESHING3_OK;
+  }  
+
+
+
+
+  /*
+
+
+  MESHING3_RESULT MeshVolumeOld (MeshingParameters & mp, Mesh& mesh3d)
+  {
+  int i, k, oldne;
+
+
+  int meshed;
+  int cntsteps; 
+
+
+  PlotStatistics3d * pstat;
+  if (globflags.GetNumFlag("silentflag", 1) <= 2)
+  pstat = new XPlotStatistics3d;
+  else
+  pstat = new TerminalPlotStatistics3d;
+
+  cntsteps = 0;
+  do
+  {
+  cntsteps++;
+  if (cntsteps > mp.maxoutersteps) 
+  {
+  return MESHING3_OUTERSTEPSEXCEEDED;
+  }
+
+
+  int noldp = mesh3d.GetNP();
+      
+      
+  if ( (cntsteps == 1) && globflags.GetDefineFlag ("delaunay"))
+  {
+  cntsteps ++;
+
+  mesh3d.CalcSurfacesOfNode();
+
+
+  for (k = 1; k <= mesh3d.GetNDomains(); k++)
+  {
+  Meshing3 meshing(NULL, pstat);
+
+  mesh3d.FindOpenElements(k);
+	      
+  for (i = 1; i <= noldp; i++)
+  meshing.AddPoint (mesh3d.Point(i), i);
+	      
+  for (i = 1; i <= mesh3d.GetNOpenElements(); i++)
+  {
+  if (mesh3d.OpenElement(i).GetIndex() == k)
+  meshing.AddBoundaryElement (mesh3d.OpenElement(i));
+  }
+	      
+  oldne = mesh3d.GetNE();
+  if (globflags.GetDefineFlag ("blockfill"))
+  {
+  if (!globflags.GetDefineFlag ("localh"))
+  meshing.BlockFill 
+  (mesh3d, mp.h * globflags.GetNumFlag ("relblockfillh", 1));
+  else
+  meshing.BlockFillLocalH (mesh3d);
+  }
+	      
+  MeshingParameters mpd;
+  meshing.Delaunay (mesh3d, mpd);
+
+  for (i = oldne + 1; i <= mesh3d.GetNE(); i++)
+  mesh3d.VolumeElement(i).SetIndex (k);
+  }
+  }
+
+  noldp = mesh3d.GetNP();
+
+  mesh3d.CalcSurfacesOfNode();
+  mesh3d.FindOpenElements();
+  for (k = 1; k <= mesh3d.GetNDomains(); k++)
+  {
+  Meshing3 meshing(globflags.GetStringFlag ("rules3d", NULL), pstat);
+      
+  Point3d pmin, pmax;
+  mesh3d.GetBox (pmin, pmax, k);
+	  
+  rot.SetCenter (Center (pmin, pmax));
+
+  for (i = 1; i <= noldp; i++)
+  meshing.AddPoint (mesh3d.Point(i), i);
+
+  for (i = 1; i <= mesh3d.GetNOpenElements(); i++)
+  {
+  if (mesh3d.OpenElement(i).GetIndex() == k)
+  meshing.AddBoundaryElement (mesh3d.OpenElement(i));
+  }
+
+  oldne = mesh3d.GetNE();
+
+
+  if ( (cntsteps == 1) && globflags.GetDefineFlag ("blockfill"))
+  {
+  if (!globflags.GetDefineFlag ("localh"))
+  {
+  meshing.BlockFill 
+  (mesh3d, 
+  mp.h * globflags.GetNumFlag ("relblockfillh", 1));
+  }
+  else
+  {
+  meshing.BlockFillLocalH (mesh3d);
+  }
+  }
+
+
+  mp.giveuptol = int(globflags.GetNumFlag ("giveuptol", 15));
+
+  meshing.GenerateMesh (mesh3d, mp);
+
+  for (i = oldne + 1; i <= mesh3d.GetNE(); i++)
+  mesh3d.VolumeElement(i).SetIndex (k);
+  }
+
+
+
+  mesh3d.CalcSurfacesOfNode();
+  mesh3d.FindOpenElements();
+      
+  teterrpow = 2;
+  if (mesh3d.GetNOpenElements() != 0)
+  {
+  meshed = 0;
+  (*mycout) << "Open elements found, old" << endl;
+  const char * optstr = "mcmcmcmcm";
+  int j;
+  for (j = 1; j <= strlen(optstr); j++)
+  switch (optstr[j-1])
+  {
+  case 'c': mesh3d.CombineImprove(); break;
+  case 'd': mesh3d.SplitImprove(); break;
+  case 's': mesh3d.SwapImprove(); break;
+  case 'm': mesh3d.ImproveMesh(2); break;
+  }	  
+	  
+  (*mycout) << "Call remove" << endl;
+  RemoveProblem (mesh3d);
+  (*mycout) << "Problem removed" << endl;
+  }
+  else
+  meshed = 1;
+  }
+  while (!meshed);
+
+  MeshQuality3d (mesh3d);
+
+  return MESHING3_OK;
+  }  
+
+  */
+
+
+
+
+  /*
+  MESHING3_RESULT MeshMixedVolume(MeshingParameters & mp, Mesh& mesh3d)
+  {
+    int i, j;
+    MESHING3_RESULT res;
+    Point3d pmin, pmax;
+
+    mp.giveuptol = 10;
+    mp.baseelnp = 4;
+    mp.starshapeclass = 100;
+
+    //  TerminalPlotStatistics3d pstat;
+  
+    Meshing3 meshing1("pyramids.rls");
+    for (i = 1; i <= mesh3d.GetNP(); i++)
+      meshing1.AddPoint (mesh3d.Point(i), i);
+
+    mesh3d.FindOpenElements();
+    for (i = 1; i <= mesh3d.GetNOpenElements(); i++)
+      if (mesh3d.OpenElement(i).GetIndex() == 1)
+	meshing1.AddBoundaryElement (mesh3d.OpenElement(i));
+
+    res = meshing1.GenerateMesh (mesh3d, mp);
+
+    mesh3d.GetBox (pmin, pmax);
+    PrintMessage (1, "Mesh pyramids, res = ", res);
+    if (res)
+      exit (1);
+
+
+    for (i = 1; i <= mesh3d.GetNE(); i++)
+      mesh3d.VolumeElement(i).SetIndex (1);
+
+    // do delaunay
+  
+    mp.baseelnp = 0;
+    mp.starshapeclass = 5;
+
+    Meshing3 meshing2(NULL);
+    for (i = 1; i <= mesh3d.GetNP(); i++)
+      meshing2.AddPoint (mesh3d.Point(i), i);
+    
+    mesh3d.FindOpenElements();
+    for (i = 1; i <= mesh3d.GetNOpenElements(); i++)
+      if (mesh3d.OpenElement(i).GetIndex() == 1)
+	meshing2.AddBoundaryElement (mesh3d.OpenElement(i));
+
+    MeshingParameters mpd;
+    meshing2.Delaunay (mesh3d, mpd);
+
+    for (i = 1; i <= mesh3d.GetNE(); i++)
+      mesh3d.VolumeElement(i).SetIndex (1);
+
+
+    mp.baseelnp = 0;
+    mp.giveuptol = 10;
+
+    for (int trials = 1; trials <= 50; trials++)
+      {
+	if (multithread.terminate)
+	  return MESHING3_TERMINATE;
+
+	Meshing3 meshing3("tetra.rls");
+	for (i = 1; i <= mesh3d.GetNP(); i++)
+	  meshing3.AddPoint (mesh3d.Point(i), i);
+      
+	mesh3d.FindOpenElements();
+	for (i = 1; i <= mesh3d.GetNOpenElements(); i++)
+	  if (mesh3d.OpenElement(i).GetIndex() == 1)
+	    meshing3.AddBoundaryElement (mesh3d.OpenElement(i));
+      
+	if (trials > 1)
+	  CheckSurfaceMesh2 (mesh3d);
+	res = meshing3.GenerateMesh (mesh3d, mp);
+      
+	for (i = 1; i <= mesh3d.GetNE(); i++)
+	  mesh3d.VolumeElement(i).SetIndex (1);
+
+	if (res == 0) break;
+
+
+
+	for (i = 1; i <= mesh3d.GetNE(); i++)
+	  {
+	    const Element & el = mesh3d.VolumeElement(i);
+	    if (el.GetNP() != 4)
+	      {
+		for (j = 1; j <= el.GetNP(); j++)
+		  mesh3d.AddLockedPoint (el.PNum(j));
+	      }
+	  }
+
+	mesh3d.CalcSurfacesOfNode();
+	mesh3d.FindOpenElements();
+
+	MeshOptimize3d optmesh;
+
+	teterrpow = 2;
+	const char * optstr = "mcmcmcmcm";
+	for (j = 1; j <= strlen(optstr); j++)
+	  switch (optstr[j-1])
+	    {
+	    case 'c': optmesh.CombineImprove(mesh3d, OPT_REST); break;
+	    case 'd': optmesh.SplitImprove(mesh3d); break;
+	    case 's': optmesh.SwapImprove(mesh3d); break;
+	    case 'm': mesh3d.ImproveMesh(); break;
+	    }	  
+	        
+	RemoveProblem (mesh3d);
+      }
+
+
+    PrintMessage (1, "Meshing tets, res = ", res);
+    if (res)
+      {
+	mesh3d.FindOpenElements();
+	PrintSysError (1, "Open elemetns: ", mesh3d.GetNOpenElements());
+	exit (1);
+      }
+
+
+  
+    for (i = 1; i <= mesh3d.GetNE(); i++)
+      {
+	const Element & el = mesh3d.VolumeElement(i);
+	if (el.GetNP() != 4)
+	  {
+	    for (j = 1; j <= el.GetNP(); j++)
+	      mesh3d.AddLockedPoint (el.PNum(j));
+	  }
+      }
+  
+    mesh3d.CalcSurfacesOfNode();
+    mesh3d.FindOpenElements();
+  
+    MeshOptimize3d optmesh;
+
+    teterrpow = 2;
+    const char * optstr = "mcmcmcmcm";
+    for (j = 1; j <= strlen(optstr); j++)
+      switch (optstr[j-1])
+	{
+	case 'c': optmesh.CombineImprove(mesh3d, OPT_REST); break;
+	case 'd': optmesh.SplitImprove(mesh3d); break;
+	case 's': optmesh.SwapImprove(mesh3d); break;
+	case 'm': mesh3d.ImproveMesh(); break;
+	}	  
+
+
+    return MESHING3_OK;
+  }
+*/
+
+
+
+
+
+
+  MESHING3_RESULT OptimizeVolume (MeshingParameters & mp, 
+				  Mesh & mesh3d)
+    //				  const CSGeometry * geometry)
+  {
+    int i;
+
+    PrintMessage (1, "Volume Optimization");
+
+    /*
+      if (!mesh3d.PureTetMesh())
+      return MESHING3_OK;
+    */
+
+    // (*mycout) << "optstring = " << mp.optimize3d << endl;
+    /*
+      const char * optstr = globflags.GetStringFlag ("optimize3d", "cmh");
+      int optsteps = int (globflags.GetNumFlag ("optsteps3d", 2));
+    */
+
+    mesh3d.CalcSurfacesOfNode();
+    for (i = 1; i <= mp.optsteps3d; i++)
+      {
+	if (multithread.terminate)
+	  break;
+
+	MeshOptimize3d optmesh;
+
+	teterrpow = mp.opterrpow;
+	for (size_t j = 1; j <= strlen(mp.optimize3d); j++)
+	  {
+	    if (multithread.terminate)
+	      break;
+
+	    switch (mp.optimize3d[j-1])
+	      {
+	      case 'c': optmesh.CombineImprove(mesh3d, OPT_REST); break;
+	      case 'd': optmesh.SplitImprove(mesh3d); break;
+	      case 's': optmesh.SwapImprove(mesh3d); break;
+                // case 'u': optmesh.SwapImproveSurface(mesh3d); break;
+	      case 't': optmesh.SwapImprove2(mesh3d); break;
+#ifdef SOLIDGEOM
+	      case 'm': mesh3d.ImproveMesh(*geometry); break;
+	      case 'M': mesh3d.ImproveMesh(*geometry); break;
+#else
+	      case 'm': mesh3d.ImproveMesh(); break;
+	      case 'M': mesh3d.ImproveMesh(); break;
+#endif
+	      case 'j': mesh3d.ImproveMeshJacobian(); break;
+	      }
+	  }
+	mesh3d.mglevels = 1;
+	MeshQuality3d (mesh3d);
+      }
+  
+    return MESHING3_OK;
+  }
+
+
+
+
+  void RemoveIllegalElements (Mesh & mesh3d)
+  {
+    int it = 10;
+    int nillegal, oldn;
+
+    PrintMessage (1, "Remove Illegal Elements");
+    // return, if non-pure tet-mesh
+    /*
+      if (!mesh3d.PureTetMesh())
+      return;
+    */
+    mesh3d.CalcSurfacesOfNode();
+
+    nillegal = mesh3d.MarkIllegalElements();
+
+    MeshOptimize3d optmesh;
+    while (nillegal && (it--) > 0)
+      {
+	if (multithread.terminate)
+	  break;
+
+	PrintMessage (5, nillegal, " illegal tets");
+	optmesh.SplitImprove (mesh3d, OPT_LEGAL);
+
+	mesh3d.MarkIllegalElements();  // test
+	optmesh.SwapImprove (mesh3d, OPT_LEGAL);
+	mesh3d.MarkIllegalElements();  // test
+	optmesh.SwapImprove2 (mesh3d, OPT_LEGAL);
+
+	oldn = nillegal;
+	nillegal = mesh3d.MarkIllegalElements();
+
+	if (oldn != nillegal)
+	  it = 10;
+      }
+    PrintMessage (5, nillegal, " illegal tets");
+  }
+}
diff --git a/contrib/Netgen/libsrc/meshing/meshfunc.hpp b/contrib/Netgen/libsrc/meshing/meshfunc.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..ab2d661050842ae9abb673d9c39091ca4e1aa78e
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/meshfunc.hpp
@@ -0,0 +1,41 @@
+#ifndef FILE_MESHFUNC
+#define FILE_MESHFUNC
+
+/**************************************************************************/
+/* File:   meshfunc.hh                                                    */
+/* Author: Johannes Gerstmayr                                             */
+/* Date:   26. Jan. 98                                                    */
+/**************************************************************************/
+
+
+/*
+  Functions for mesh-generations strategies
+ */
+
+class Mesh;
+// class CSGeometry;
+
+/// Build tet-mesh
+MESHING3_RESULT MeshVolume(MeshingParameters & mp, Mesh& mesh3d);
+
+/// Build mixed-element mesh
+MESHING3_RESULT MeshMixedVolume(MeshingParameters & mp, Mesh& mesh3d);
+
+/// Optimize tet-mesh
+MESHING3_RESULT OptimizeVolume(MeshingParameters & mp, Mesh& mesh3d);
+//			       const CSGeometry * geometry = NULL);
+
+void RemoveIllegalElements (Mesh & mesh3d);
+
+
+enum MESHING_STEP { 
+  MESHCONST_ANALYSE = 1,
+  MESHCONST_MESHEDGES = 2,
+  MESHCONST_MESHSURFACE = 3,
+  MESHCONST_OPTSURFACE = 4,
+  MESHCONST_MESHVOLUME = 5,
+  MESHCONST_OPTVOLUME = 6
+};
+
+
+#endif
diff --git a/contrib/Netgen/libsrc/meshing/meshfunc2d.cpp b/contrib/Netgen/libsrc/meshing/meshfunc2d.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..ac4fbe8e928691ea24301a0e36f306379ca31dc8
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/meshfunc2d.cpp
@@ -0,0 +1,61 @@
+#include <mystdlib.h>
+#include "meshing.hpp"
+
+namespace netgen
+{
+
+  void Optimize2d (Mesh & mesh, MeshingParameters & mp)
+  {
+    int i;
+
+    //double h = mp.maxh;
+  
+    mesh.CalcSurfacesOfNode();
+
+    const char * optstr = mp.optimize2d;
+    int optsteps = mp.optsteps2d;
+
+    //  cout << "optstr = " << optstr << endl;
+
+    for (i = 1; i <= optsteps; i++)
+      for (size_t j = 1; j <= strlen(optstr); j++)
+	{
+	  if (multithread.terminate) break;
+	  switch (optstr[j-1])
+	    {
+	    case 's': 
+	      {  // topological swap
+		MeshOptimize2d meshopt;
+		meshopt.SetMetricWeight (0);
+		meshopt.EdgeSwapping (mesh, 0);
+		break;
+	      }
+	    case 'S': 
+	      {  // metric swap
+		MeshOptimize2d meshopt;
+		meshopt.SetMetricWeight (0);
+		meshopt.EdgeSwapping (mesh, 1);
+		break;
+	      }
+	    case 'm': 
+	      {
+		MeshOptimize2d meshopt;
+		meshopt.SetMetricWeight (1);
+		meshopt.ImproveMesh(mesh);
+		break;
+	      }
+	    
+	    case 'c': 
+	      {
+		MeshOptimize2d meshopt;
+		meshopt.SetMetricWeight (0.2);
+		meshopt.CombineImprove(mesh);
+		break;
+	      }
+	    default:
+	      cerr << "Optimization code " << optstr[j-1] << " not defined" << endl;
+	    }  
+	}
+  }
+
+}
diff --git a/contrib/Netgen/libsrc/meshing/meshing.hpp b/contrib/Netgen/libsrc/meshing/meshing.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..10b77f9e18d7129da0403919eea59d2e9520e7cb
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/meshing.hpp
@@ -0,0 +1,86 @@
+#ifndef FILE_MESHING
+#define FILE_MESHING
+
+
+
+#define CURVEDELEMS_NEW
+
+
+#include "../include/myadt.hpp"
+#include "../include/gprim.hpp"
+#include "../include/linalg.hpp"
+#include "../include/opti.hpp"
+
+
+
+
+namespace netgen
+{
+
+  extern int printmessage_importance;
+
+  class CSGeometry;
+  
+  
+#include "msghandler.hpp"
+
+#include "meshtype.hpp"
+#include "localh.hpp"
+#include "meshclass.hpp"
+#include "global.hpp"
+
+
+#include "meshtool.hpp"
+#include "ruler2.hpp"
+#include "adfront2.hpp"
+#include "meshing2.hpp"
+#include "improve2.hpp"
+
+
+#include "geomsearch.hpp"
+#include "adfront3.hpp"
+#include "ruler3.hpp"
+
+#ifndef SMALLLIB
+#define _INCLUDE_MORE
+#endif
+#ifdef LINUX
+#define _INCLUDE_MORE
+#endif
+
+#ifdef _INCLUDE_MORE
+#include "meshing3.hpp"
+#include "improve3.hpp"
+#endif
+#include "findip.hpp"
+#include "findip2.hpp"
+
+#include "topology.hpp"
+
+#ifdef CURVEDELEMS_NEW
+#include "curvedelems_new.hpp"
+#else
+#include "curvedelems.hpp"
+#endif
+#include "clusters.hpp"
+
+#ifdef _INCLUDE_MORE
+#include "meshfunc.hpp"
+#endif
+#include "bisect.hpp"
+#include "hprefinement.hpp"
+#include "boundarylayer.hpp"
+#include "specials.hpp"
+
+#include "validate.hpp"
+
+#ifdef PARALLEL
+#include "../parallel/paralleltop.hpp"
+// #include "../parallel/parallelmesh.hpp"
+#endif
+
+
+
+}
+
+#endif
diff --git a/contrib/Netgen/libsrc/meshing/meshing2.cpp b/contrib/Netgen/libsrc/meshing/meshing2.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..7793ecbbfa383846485c3d8161a21ef39197909a
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/meshing2.cpp
@@ -0,0 +1,1890 @@
+#include <mystdlib.h>
+#include "meshing.hpp"
+
+namespace netgen
+{
+  static void glrender (int wait);
+
+
+  // global variable for visualization
+
+  static ARRAY<Point3d> locpoints;
+  static ARRAY<int> legalpoints;
+  static ARRAY<Point2d> plainpoints;
+  static ARRAY<int> plainzones;
+  static ARRAY<INDEX_2> loclines;
+  static int geomtrig;
+  //static const char * rname;
+  static int cntelem, trials, nfaces;
+  static int oldnl;
+  static int qualclass;
+ 
+
+  Meshing2 :: Meshing2 (const Box<3> & aboundingbox)
+  {
+    boundingbox = aboundingbox;
+
+    LoadRules (NULL);
+    // LoadRules ("rules/quad.rls");
+    // LoadRules ("rules/triangle.rls");
+
+    adfront = new AdFront2(boundingbox);
+    starttime = GetTime();
+
+    maxarea = -1;
+  }
+
+
+  Meshing2 :: ~Meshing2 ()
+  {
+    delete adfront;
+    for (int i = 0; i < rules.Size(); i++)
+      delete rules[i];
+  }
+
+  void Meshing2 :: AddPoint (const Point3d & p, PointIndex globind, 
+			     MultiPointGeomInfo * mgi,
+			     bool pointonsurface)
+  {
+    //(*testout) << "add point " << globind << endl;
+    adfront ->AddPoint (p, globind, mgi, pointonsurface);
+  }
+
+  void Meshing2 :: AddBoundaryElement (int i1, int i2,
+				       const PointGeomInfo & gi1, const PointGeomInfo & gi2)
+  {
+    //    (*testout) << "add line " << i1 << " - " << i2 << endl;
+    if (!gi1.trignum || !gi2.trignum)
+      {
+	PrintSysError ("addboundaryelement: illegal geominfo");
+      }
+    adfront -> AddLine (i1-1, i2-1, gi1, gi2);
+  }
+
+
+
+  void Meshing2 :: StartMesh ()
+  {
+    foundmap.SetSize (rules.Size());
+    canuse.SetSize (rules.Size());
+    ruleused.SetSize (rules.Size());
+
+    foundmap = 0;
+    canuse = 0;
+    ruleused = 0;
+
+    cntelem = 0;
+    trials = 0;
+  }
+
+  void Meshing2 :: EndMesh ()
+  {
+    for (int i = 0; i < ruleused.Size(); i++)
+      (*testout) << setw(4) << ruleused[i]
+		 << " times used rule " << rules[i] -> Name() << endl;
+  }
+
+  void Meshing2 :: SetStartTime (double astarttime)
+  {
+    starttime = astarttime;
+  }
+
+  
+  void Meshing2 :: SetMaxArea (double amaxarea)
+  {
+    maxarea = amaxarea;
+  }
+
+
+  double Meshing2 :: CalcLocalH (const Point3d & /* p */, double gh) const
+  {
+    return gh;
+  }
+
+  // should be class variables !!(?)
+  static Vec3d ex, ey;
+  static Point3d globp1;
+
+  void Meshing2 :: DefineTransformation (const Point3d & p1, const Point3d & p2,
+					 const PointGeomInfo * geominfo1,
+					 const PointGeomInfo * geominfo2)
+  {
+    globp1 = p1;
+    ex = p2 - p1;
+    ex /= ex.Length();
+    ey.X() = -ex.Y();
+    ey.Y() =  ex.X();
+    ey.Z() = 0;
+  }
+
+  void Meshing2 :: TransformToPlain (const Point3d & locpoint, 
+				     const MultiPointGeomInfo & geominf,
+				     Point2d & plainpoint, double h, int & zone)
+  {
+    Vec3d p1p (globp1, locpoint);
+
+    //    p1p = locpoint - globp1;
+    p1p /= h;
+    plainpoint.X() = p1p * ex;
+    plainpoint.Y() = p1p * ey;
+    zone = 0;
+  }
+
+  int Meshing2 :: TransformFromPlain (Point2d & plainpoint,
+				      Point3d & locpoint, 
+				      PointGeomInfo & gi, 
+				      double h)
+  {
+    Vec3d p1p;
+    gi.trignum = 1;
+
+    p1p = plainpoint.X() * ex + plainpoint.Y() * ey;
+    p1p *= h;
+    locpoint = globp1 + p1p;
+    return 0;
+  }
+
+
+  int Meshing2 :: BelongsToActiveChart (const Point3d & p, 
+					const PointGeomInfo & gi)
+  {
+    return 1;
+  }
+
+
+  int Meshing2 :: ComputePointGeomInfo (const Point3d & p, PointGeomInfo & gi)
+  {
+    gi.trignum = 1;
+    return 0;
+  }
+
+
+  int Meshing2 :: ChooseChartPointGeomInfo (const MultiPointGeomInfo & mpgi, 
+					    PointGeomInfo & pgi)
+  {
+    pgi = mpgi.GetPGI(1);
+    return 0;
+  }
+
+
+
+  int Meshing2 :: 
+  IsLineVertexOnChart (const Point3d & p1, const Point3d & p2,
+		       int endpoint, const PointGeomInfo & geominfo)
+  {
+    return 1;
+  }
+
+  void Meshing2 ::
+  GetChartBoundary (ARRAY<Point2d> & points, 
+		    ARRAY<Point3d> & points3d, 
+		    ARRAY<INDEX_2> & lines, double h) const
+  {
+    points.SetSize (0);
+    points3d.SetSize (0);
+    lines.SetSize (0);
+  }
+
+  double Meshing2 :: Area () const
+  {
+    return -1;
+  }
+
+
+
+
+
+  MESHING2_RESULT Meshing2 :: GenerateMesh (Mesh & mesh, double gh, int facenr)
+  {
+    ARRAY<int> pindex, lindex;
+    ARRAY<int> delpoints, dellines;
+
+    ARRAY<PointGeomInfo> upgeominfo;  // unique info
+    ARRAY<MultiPointGeomInfo> mpgeominfo;  // multiple info
+
+    ARRAY<Element2d> locelements;
+
+    int z1, z2, oldnp(-1);
+    SurfaceElementIndex sei;
+    bool found;
+    int rulenr(-1);
+    int globind;
+    Point<3> p1, p2;
+
+    const PointGeomInfo * blgeominfo1;
+    const PointGeomInfo * blgeominfo2;
+
+    bool morerisc;
+    bool debugflag;
+
+    double h, his, hshould;
+
+
+    // test for 3d overlaps
+    Box3dTree surfeltree (boundingbox.PMin(),
+			  boundingbox.PMax());
+
+    ARRAY<int> intersecttrias;
+    ARRAY<Point3d> critpoints;
+
+    // test for doubled edges
+    //INDEX_2_HASHTABLE<int> doubleedge(300000);
+
+
+    testmode = 0;
+
+    StartMesh();
+
+    ARRAY<Point2d> chartboundpoints;
+    ARRAY<Point3d> chartboundpoints3d;
+    ARRAY<INDEX_2> chartboundlines;
+
+    // illegal points: points with more then 50 elements per node
+    int maxlegalpoint(-1), maxlegalline(-1);
+    ARRAY<int,PointIndex::BASE> trigsonnode;
+    ARRAY<int,PointIndex::BASE> illegalpoint;
+
+    trigsonnode.SetSize (mesh.GetNP());
+    illegalpoint.SetSize (mesh.GetNP());
+
+    trigsonnode = 0;
+    illegalpoint = 0;
+  
+
+    double totalarea = Area ();
+    double meshedarea = 0;
+
+    // search tree for surface elements:
+    for (sei = 0; sei < mesh.GetNSE(); sei++)
+      {
+	const Element2d & sel = mesh[sei];
+
+	if (sel.IsDeleted()) continue;
+
+	if (sel.GetIndex() == facenr)
+	  {
+	    Box<3> box;
+	    box.Set ( mesh[sel[0]] );
+	    box.Add ( mesh[sel[1]] );
+	    box.Add ( mesh[sel[2]] );
+	    surfeltree.Insert (box, sei);
+	  }
+      
+	double trigarea = Cross ( mesh[sel[1]]-mesh[sel[0]],
+				  mesh[sel[2]]-mesh[sel[0]] ).Length() / 2;
+
+
+	if (sel.GetNP() == 4)
+	  trigarea += Cross (Vec3d (mesh.Point (sel.PNum(1)),
+				    mesh.Point (sel.PNum(3))),
+			     Vec3d (mesh.Point (sel.PNum(1)),
+				    mesh.Point (sel.PNum(4)))).Length() / 2;;
+	meshedarea += trigarea;
+      }
+
+
+    const char * savetask = multithread.task;
+    multithread.task = "Surface meshing";
+
+    adfront ->SetStartFront ();
+
+
+    int plotnexttrial = 999;
+
+    double meshedarea_before = meshedarea;
+
+    while (!adfront ->Empty() && !multithread.terminate)
+      {
+	if (multithread.terminate)
+	  throw NgException ("Meshing stopped");
+
+	// known for STL meshing
+	if (totalarea > 0)
+	  multithread.percent = 100 * meshedarea / totalarea;
+	/*
+	  else
+	  multithread.percent = 0;
+	*/
+
+	locpoints.SetSize(0);
+	loclines.SetSize(0);
+	pindex.SetSize(0);
+	lindex.SetSize(0);
+	delpoints.SetSize(0);
+	dellines.SetSize(0);
+	locelements.SetSize(0);
+
+
+
+	// plot statistics
+	if (trials > plotnexttrial)
+	  {
+	    PrintMessage (5, 
+			  "faces = ", nfaces,
+			  " trials = ", trials,
+			  " elements = ", mesh.GetNSE(),
+			  " els/sec = ",
+			  (mesh.GetNSE() / (GetTime() - starttime + 0.0001)));
+	    plotnexttrial += 1000;
+	  }
+
+
+	// unique-pgi, multi-pgi
+	upgeominfo.SetSize(0);
+	mpgeominfo.SetSize(0);
+
+
+	nfaces = adfront->GetNFL();
+	trials ++;
+    
+
+	if (trials % 1000 == 0)
+	  {
+	    (*testout) << "\n";
+	    for (int i = 1; i <= canuse.Size(); i++)
+	      {
+		(*testout) << foundmap.Get(i) << "/" 
+			   << canuse.Get(i) << "/"
+			   << ruleused.Get(i) << " map/can/use rule " << rules.Get(i)->Name() << "\n";
+	      }
+	    (*testout) << "\n";
+	  }
+
+
+	int baselineindex = adfront -> SelectBaseLine (p1, p2, blgeominfo1, blgeominfo2, qualclass);
+
+
+	found = 1;
+
+	his = Dist (p1, p2);
+
+	Point3d pmid = Center (p1, p2);
+	hshould = CalcLocalH (pmid, mesh.GetH (pmid));
+	if (gh < hshould) hshould = gh;
+
+	mesh.RestrictLocalH (pmid, hshould);
+
+	h = hshould;
+
+	double hinner = (3 + qualclass) * max2 (his, hshould);
+
+	adfront ->GetLocals (baselineindex, locpoints, mpgeominfo, loclines, 
+			     pindex, lindex, 2*hinner);
+	//(*testout) << "h for locals: " << 2*hinner << endl;
+	
+
+	//(*testout) << "locpoints " << locpoints << endl;
+
+	if (qualclass > mparam.giveuptol2d)
+	  {
+	    PrintMessage (3, "give up with qualclass ", qualclass);
+	    PrintMessage (3, "number of frontlines = ", adfront->GetNFL());
+	    // throw NgException ("Give up 2d meshing");
+	    break;
+	  }
+
+	/*
+	if (found && qualclass > 60)
+	  {
+	    found = 0;
+	  }
+	*/
+	//      morerisc = ((qualclass > 20) && (qualclass % 2 == 1));
+	//      morerisc = 1;
+	morerisc = 0;
+
+
+	PointIndex gpi1 = adfront -> GetGlobalIndex (pindex.Get(loclines[0].I1()));
+	PointIndex gpi2 = adfront -> GetGlobalIndex (pindex.Get(loclines[0].I2()));
+
+
+	debugflag = 
+	  debugparam.haltsegment &&
+	  ( (debugparam.haltsegmentp1 == gpi1) && 
+	    (debugparam.haltsegmentp2 == gpi2) || 
+	    (debugparam.haltsegmentp1 == gpi2) && 
+	    (debugparam.haltsegmentp2 == gpi1)) ||
+	  debugparam.haltnode &&
+	  ( (debugparam.haltsegmentp1 == gpi1) ||
+	    (debugparam.haltsegmentp2 == gpi1));
+
+      
+	if (debugparam.haltface && debugparam.haltfacenr == facenr)
+	  {
+	    debugflag = 1;
+	    cout << "set debugflag" << endl;
+	  }
+	
+	if (debugparam.haltlargequalclass && qualclass > 50)
+	  debugflag = 1;
+
+
+	// problem recognition !
+	if (found && 
+	    (gpi1 < illegalpoint.Size()+PointIndex::BASE) && 
+	    (gpi2 < illegalpoint.Size()+PointIndex::BASE) )
+	  {
+	    if (illegalpoint[gpi1] || illegalpoint[gpi2])
+	      found = 0;
+	  }
+
+
+	Point2d p12d, p22d;
+
+	if (found)
+	  {
+	    oldnp = locpoints.Size();
+	    oldnl = loclines.Size();
+	  
+	    if (debugflag)
+	      (*testout) << "define new transformation" << endl;
+
+	    DefineTransformation (p1, p2, blgeominfo1, blgeominfo2);
+	  
+	    plainpoints.SetSize (locpoints.Size());
+	    plainzones.SetSize (locpoints.Size());
+
+	    // (*testout) << endl;
+
+	    //	    (*testout) << "3d->2d transformation" << endl;
+
+	    for (int i = 1; i <= locpoints.Size(); i++)
+	      {
+		// (*testout) << "pindex(i) = " << pindex[i-1] << endl;
+		TransformToPlain (locpoints.Get(i), 
+				  mpgeominfo.Get(i),
+				  plainpoints.Elem(i), h, plainzones.Elem(i));
+		//		(*testout) << mpgeominfo.Get(i).GetPGI(1).u << " " << mpgeominfo.Get(i).GetPGI(1).v << " ";
+		//		(*testout) << plainpoints.Get(i).X() << " " << plainpoints.Get(i).Y() << endl;
+		//(*testout) << "transform " << locpoints.Get(i) << " to " << plainpoints.Get(i).X() << " " << plainpoints.Get(i).Y() << endl;
+	      }
+	    //	    (*testout) << endl << endl << endl;
+
+
+	    p12d = plainpoints.Get(1);
+	    p22d = plainpoints.Get(2);
+
+	    /*
+	    // last idea on friday
+	    plainzones.Elem(1) = 0;
+	    plainzones.Elem(2) = 0;
+	    */
+
+
+	    /*
+	    // old netgen:
+	    for (i = 2; i <= loclines.Size(); i++)  // don't remove first line
+	    {
+	    z1 = plainzones.Get(loclines.Get(i).I1());
+	    z2 = plainzones.Get(loclines.Get(i).I2());
+	      
+	    if (z1 && z2 && (z1 != z2) || (z1 == -1) || (z2 == -1) )
+	    {
+	    loclines.DeleteElement(i);
+	    lindex.DeleteElement(i);
+	    oldnl--;
+	    i--;
+	    }
+	    }
+
+	    // 	  for (i = 1; i <= plainpoints.Size(); i++)
+	    // 	    if (plainzones.Elem(i) == -1)
+	    // 	      plainpoints.Elem(i) = Point2d (1e4, 1e4);
+	    */
+	  
+
+	  
+	    for (int i = 2; i <= loclines.Size(); i++)  // don't remove first line
+	      {
+		// (*testout) << "loclines(i) = " << loclines.Get(i).I1() << " - " << loclines.Get(i).I2() << endl;
+		z1 = plainzones.Get(loclines.Get(i).I1());
+		z2 = plainzones.Get(loclines.Get(i).I2());
+	      
+	      
+		// one inner point, one outer
+		if ( (z1 >= 0) != (z2 >= 0))
+		  {
+		    int innerp = (z1 >= 0) ? 1 : 2;
+		    if (IsLineVertexOnChart (locpoints.Get(loclines.Get(i).I1()),
+					     locpoints.Get(loclines.Get(i).I2()),
+					     innerp,
+					     adfront->GetLineGeomInfo (lindex.Get(i), innerp)))
+		      // pgeominfo.Get(loclines.Get(i).I(innerp))))
+		      {		
+
+			if (!morerisc)
+			  {
+			    // use one end of line
+			    int pini, pouti;
+			    Vec2d v;
+			  
+			    pini = loclines.Get(i).I(innerp);
+			    pouti = loclines.Get(i).I(3-innerp);
+			  
+			    Point2d pin (plainpoints.Get(pini));
+			    Point2d pout (plainpoints.Get(pouti));
+			    v = pout - pin;
+			    double len = v.Length();
+			    if (len <= 1e-6)
+			      (*testout) << "WARNING(js): inner-outer: short vector" << endl;
+			    else
+			      v /= len;
+			  
+			    /*
+			    // don't elongate line towards base-line !!
+			    if (Vec2d (pin, p12d) * v > 0 && 
+			    Vec2d (pin, p22d) * v > 0)
+			    v *= -1;  
+			    */
+
+			    Point2d newpout = pin + 1000 * v;
+			    newpout = pout;
+
+			  
+			    plainpoints.Append (newpout);
+			    Point3d pout3d = locpoints.Get(pouti);
+			    locpoints.Append (pout3d);
+
+			    plainzones.Append (0);
+			    pindex.Append (-1);
+			    oldnp++;
+			    loclines.Elem(i).I(3-innerp) = oldnp;
+			  }
+			else
+			  plainzones.Elem(loclines.Get(i).I(3-innerp)) = 0;
+			
+
+			//		  (*testout) << "inner - outer correction" << endl;
+		      }
+		    else
+		      {
+			// remove line
+			loclines.DeleteElement(i);
+			lindex.DeleteElement(i);
+			oldnl--;
+			i--;
+		      }			
+		  }
+	      
+		else if (z1 > 0 && z2 > 0 && (z1 != z2) || (z1 < 0) && (z2 < 0) )
+		  {
+		    loclines.DeleteElement(i);
+		    lindex.DeleteElement(i);
+		    oldnl--;
+		    i--;
+		  }
+	      }
+	  
+
+
+
+
+	    legalpoints.SetSize(plainpoints.Size());
+	    for (int i = 1; i <= legalpoints.Size(); i++)
+	      legalpoints.Elem(i) = 1;
+
+	    double avy = 0;
+	    for (int i = 1; i <= plainpoints.Size(); i++)
+	      avy += plainpoints.Elem(i).Y();
+	    avy *= 1./plainpoints.Size();
+		
+
+	    for (int i = 1; i <= plainpoints.Size(); i++)
+	      {
+		if (plainzones.Elem(i) < 0)
+		  {
+		    plainpoints.Elem(i) = Point2d (1e4, 1e4);
+		    legalpoints.Elem(i) = 0;
+		  }
+		if (pindex.Elem(i) == -1)
+		  {
+		    legalpoints.Elem(i) = 0;
+		  }
+		    
+
+		if (plainpoints.Elem(i).Y() < -1e-10*avy) // changed
+		  {
+		    legalpoints.Elem(i) = 0;
+		  }
+	      }
+	    /*
+	      for (i = 3; i <= plainpoints.Size(); i++)
+	      if (sqr (plainpoints.Get(i).X()) + sqr (plainpoints.Get(i).Y())
+	      > sqr (2 + 0.2 * qualclass))
+	      legalpoints.Elem(i) = 0;
+	    */  
+
+	    /*	  
+		 int clp = 0;
+		 for (i = 1; i <= plainpoints.Size(); i++)
+		 if (legalpoints.Get(i))
+		 clp++;
+		 (*testout) << "legalpts: " << clp << "/" << plainpoints.Size() << endl; 
+
+		 // sort legal/illegal lines
+		 int lastleg = 2;
+		 int firstilleg = oldnl;
+
+		 while (lastleg < firstilleg)
+		 {
+		 while (legalpoints.Get(loclines.Get(lastleg).I1()) &&
+		 legalpoints.Get(loclines.Get(lastleg).I2()) &&
+		 lastleg < firstilleg)
+		 lastleg++;
+		 while ( ( !legalpoints.Get(loclines.Get(firstilleg).I1()) ||
+		 !legalpoints.Get(loclines.Get(firstilleg).I2())) &&
+		 lastleg < firstilleg)
+		 firstilleg--;
+	      
+		 if (lastleg < firstilleg)
+		 {
+		 swap (loclines.Elem(lastleg), loclines.Elem(firstilleg));
+		 swap (lindex.Elem(lastleg), lindex.Elem(firstilleg));
+		 }
+		 }
+
+		 (*testout) << "leglines " << lastleg << "/" << oldnl << endl;
+	    */
+	
+
+	    GetChartBoundary (chartboundpoints, 
+			      chartboundpoints3d,
+			      chartboundlines, h);
+
+	    oldnp = plainpoints.Size();
+
+	    maxlegalpoint = locpoints.Size();
+	    maxlegalline = loclines.Size();
+
+
+
+	    if (mparam.checkchartboundary)
+	      {
+		for (int i = 1; i <= chartboundpoints.Size(); i++)
+		  {
+		    plainpoints.Append (chartboundpoints.Get(i));
+		    locpoints.Append (chartboundpoints3d.Get(i));
+		    legalpoints.Append (0);
+		  }
+	      
+
+		for (int i = 1; i <= chartboundlines.Size(); i++)
+		  {
+		    INDEX_2 line (chartboundlines.Get(i).I1()+oldnp,
+				  chartboundlines.Get(i).I2()+oldnp);
+		    loclines.Append (line);
+		    //	      (*testout) << "line: " << line.I1() << "-" << line.I2() << endl;
+		  }
+	      }
+
+	    oldnl = loclines.Size();
+	    oldnp = plainpoints.Size();
+	  }
+
+
+	/*
+	  if (qualclass > 100)
+	  {
+	  multithread.drawing = 1;
+	  glrender(1);
+	  cout << "qualclass 100, nfl = " << adfront->GetNFL() << endl;
+	  }
+	*/
+
+	if (found)
+	  {
+	    rulenr = ApplyRules (plainpoints, legalpoints, maxlegalpoint,
+				 loclines, maxlegalline, locelements,
+				 dellines, qualclass);
+	    //	    (*testout) << "Rule Nr = " << rulenr << endl;
+	    if (!rulenr)
+	      {
+		found = 0;
+		if ( debugflag || debugparam.haltnosuccess )
+		  PrintWarning ("no rule found");
+	      }
+	  }
+      
+	for (int i = 1; i <= locelements.Size() && found; i++)
+	  {
+	    const Element2d & el = locelements.Get(i);
+
+	    for (int j = 1; j <= el.GetNP(); j++)
+	      if (el.PNum(j) <= oldnp && pindex.Get(el.PNum(j)) == -1)
+		{
+		  found = 0;
+		  PrintSysError ("meshing2, index missing");
+		}
+	  }
+
+
+	if (found)
+	  {
+	    locpoints.SetSize (plainpoints.Size());
+	    upgeominfo.SetSize(locpoints.Size());
+
+	    for (int i = oldnp+1; i <= plainpoints.Size(); i++)
+	      {
+		int err =
+		  TransformFromPlain (plainpoints.Elem(i), locpoints.Elem(i), 
+				      upgeominfo.Elem(i), h);
+
+		if (err)
+		  {
+		    found = 0;
+
+		    if ( debugflag || debugparam.haltnosuccess )
+		      PrintSysError ("meshing2, Backtransformation failed");
+
+		    break;
+		  }
+	      }
+	  }
+	  
+
+	//      for (i = 1; i <= oldnl; i++)
+	//        adfront -> ResetClass (lindex[i]);
+
+
+	/*
+	  double violateminh;
+	  if (qualclass <= 10)
+	  violateminh = 3;
+	  else
+	  violateminh = 3 * qualclass;
+
+	  if (uselocalh && found) //  && qualclass <= 10)
+	  {
+	  for (i = 1; i <= locelements.Size(); i++)
+	  {
+	  Point3d pmin = locpoints.Get(locelements.Get(i).PNum(1));
+	  Point3d pmax = pmin;
+	  for (j = 2; j <= 3; j++)
+	  {
+	  const Point3d & hp = 
+	  locpoints.Get(locelements.Get(i).PNum(j));
+	  pmin.SetToMin (hp);
+	  pmax.SetToMax (hp);
+	  }
+	  double minh = mesh.GetMinH (pmin, pmax);
+	  if (h > violateminh * minh)
+	  {
+	  found = 0;
+	  loclines.SetSize (oldnl);
+	  locpoints.SetSize (oldnp);
+	  }
+	  }
+	  }
+	*/
+
+
+	if (found) 
+	  {
+	    double violateminh = 3 + 0.1 * sqr (qualclass);
+	    double minh = 1e8;
+	    double newedgemaxh = 0;
+	    for (int i = oldnl+1; i <= loclines.Size(); i++)
+	      {
+		double eh = Dist (locpoints.Get(loclines.Get(i).I1()),
+				  locpoints.Get(loclines.Get(i).I2()));
+
+		// Markus (brute force method to avoid bad elements on geometries like \_/ )
+		//if(eh > 4.*mesh.GetH(locpoints.Get(loclines.Get(i).I1()))) found = 0;
+		//if(eh > 4.*mesh.GetH(locpoints.Get(loclines.Get(i).I2()))) found = 0;
+		// Markus end
+
+		if (eh > newedgemaxh)
+		  newedgemaxh = eh;
+	      }
+
+	    for (int i = 1; i <= locelements.Size(); i++)
+	      {
+		Point3d pmin = locpoints.Get(locelements.Get(i).PNum(1));
+		Point3d pmax = pmin;
+		for (int j = 2; j <= locelements.Get(i).GetNP(); j++)
+		  {
+		    const Point3d & hp = 
+		      locpoints.Get(locelements.Get(i).PNum(j));
+		    pmin.SetToMin (hp);
+		    pmax.SetToMax (hp);
+		  }
+		double eh = mesh.GetMinH (pmin, pmax);
+		if (eh < minh)
+		  minh = eh;
+	      }
+
+	    for (int i = 1; i <= locelements.Size(); i++)
+	      for (int j = 1; j <= locelements.Get(i).GetNP(); j++)
+		if (Dist2 (locpoints.Get(locelements.Get(i).PNum(j)), pmid) > hinner*hinner)
+		  found = 0;
+
+	    //	  cout << "violate = " << newedgemaxh / minh << endl;
+	    static double maxviolate = 0;
+	    if (newedgemaxh / minh > maxviolate)
+	      {
+		maxviolate = newedgemaxh / minh;
+		//	      cout << "max minhviolate = " << maxviolate << endl;
+	      }
+
+
+	    if (newedgemaxh > violateminh * minh)
+	      {
+		found = 0;
+		loclines.SetSize (oldnl);
+		locpoints.SetSize (oldnp);
+
+		if ( debugflag || debugparam.haltnosuccess )
+		  PrintSysError ("meshing2, maxh too large");
+
+
+	      }
+	  }
+
+
+
+	/*
+	// test good ComputeLineGeoInfo
+	if (found)
+	{
+	// is line on chart ?
+	for (i = oldnl+1; i <= loclines.Size(); i++)
+	{
+	int gisize;
+	void *geominfo;
+
+	if (ComputeLineGeoInfo (locpoints.Get(loclines.Get(i).I1()),
+	locpoints.Get(loclines.Get(i).I2()),
+	gisize, geominfo))
+	found = 0;
+	}
+	}
+	*/
+
+
+	// changed for OCC meshing
+	if (found)
+	  {
+	    // take geominfo from dellines
+	    // upgeominfo.SetSize(locpoints.Size());
+
+	    /*
+	      for (i = 1; i <= dellines.Size(); i++)
+	      for (j = 1; j <= 2; j++)
+	      {
+	      upgeominfo.Elem(loclines.Get(dellines.Get(i)).I(j)) =
+	      adfront -> GetLineGeomInfo (lindex.Get(dellines.Get(i)), j);
+	      }
+	    */
+
+
+	    for (int i = 1; i <= locelements.Size(); i++)
+	      for (int j = 1; j <= locelements.Get(i).GetNP(); j++)
+		{
+		  int pi = locelements.Get(i).PNum(j);
+		  if (pi <= oldnp)
+		    {
+		    
+		      if (ChooseChartPointGeomInfo (mpgeominfo.Get(pi), upgeominfo.Elem(pi)))
+			{
+			  // cannot select, compute new one
+			  PrintWarning ("calc point geominfo instead of using");
+			  if (ComputePointGeomInfo (locpoints.Get(pi), upgeominfo.Elem(pi)))
+			    {
+			      found = 0;
+			      PrintSysError ("meshing2d, geominfo failed");
+			    }
+			}
+		    }
+		}
+
+	    /*
+	    // use upgeominfo from ProjectFromPlane
+	    for (i = oldnp+1; i <= locpoints.Size(); i++)
+	    {
+	    if (ComputePointGeomInfo (locpoints.Get(i), upgeominfo.Elem(i)))
+	    {
+	    found = 0;
+	    if ( debugflag || debugparam.haltnosuccess )
+	    PrintSysError ("meshing2d, compute geominfo failed");
+	    }
+	    }
+	    */
+	  }
+
+
+	if (found && mparam.checkoverlap)
+	  {
+	    // cout << "checkoverlap" << endl;
+	    // test for overlaps
+	  
+	    Point3d hullmin(1e10, 1e10, 1e10);
+	    Point3d hullmax(-1e10, -1e10, -1e10);
+	  
+	    for (int i = 1; i <= locelements.Size(); i++)
+	      for (int j = 1; j <= locelements.Get(i).GetNP(); j++)
+		{
+		  const Point3d & p = locpoints.Get(locelements.Get(i).PNum(j));
+		  hullmin.SetToMin (p);
+		  hullmax.SetToMax (p);
+		}
+	    hullmin += Vec3d (-his, -his, -his);
+	    hullmax += Vec3d ( his,  his,  his);
+
+	    surfeltree.GetIntersecting (hullmin, hullmax, intersecttrias);
+
+	    critpoints.SetSize (0);
+	    for (int i = oldnp+1; i <= locpoints.Size(); i++)
+	      critpoints.Append (locpoints.Get(i));
+
+	    for (int i = 1; i <= locelements.Size(); i++)
+	      {
+		const Element2d & tri = locelements.Get(i);
+		if (tri.GetNP() == 3)
+		  {
+		    const Point3d & tp1 = locpoints.Get(tri.PNum(1));
+		    const Point3d & tp2 = locpoints.Get(tri.PNum(2));
+		    const Point3d & tp3 = locpoints.Get(tri.PNum(3));
+		  
+		    Vec3d tv1 (tp1, tp2);
+		    Vec3d tv2 (tp1, tp3);
+		  
+		    double lam1, lam2;
+		    for (lam1 = 0.2; lam1 <= 0.8; lam1 += 0.2)
+		      for (lam2 = 0.2; lam2 + lam1 <= 0.8; lam2 += 0.2)
+			{
+			  Point3d hp = tp1 + lam1 * tv1 + lam2 * tv2;
+			  critpoints.Append (hp);
+			}
+		  }
+		else if (tri.GetNP() == 4)
+		  {
+		    const Point3d & tp1 = locpoints.Get(tri.PNum(1));
+		    const Point3d & tp2 = locpoints.Get(tri.PNum(2));
+		    const Point3d & tp3 = locpoints.Get(tri.PNum(3));
+		    const Point3d & tp4 = locpoints.Get(tri.PNum(4));
+		  
+		    double l1, l2;
+		    for (l1 = 0.1; l1 <= 0.9; l1 += 0.1)
+		      for (l2 = 0.1; l2 <= 0.9; l2 += 0.1)
+			{
+			  Point3d hp;
+			  hp.X() = 
+			    (1-l1)*(1-l2) * tp1.X() +
+			    l1*(1-l2) * tp2.X() +
+			    l1*l2 * tp3.X() +
+			    (1-l1)*l2 * tp4.X();
+			  hp.Y() = 
+			    (1-l1)*(1-l2) * tp1.Y() +
+			    l1*(1-l2) * tp2.Y() +
+			    l1*l2 * tp3.Y() +
+			    (1-l1)*l2 * tp4.Y();
+			  hp.Z() = 
+			    (1-l1)*(1-l2) * tp1.Z() +
+			    l1*(1-l2) * tp2.Z() +
+			    l1*l2 * tp3.Z() +
+			    (1-l1)*l2 * tp4.Z();
+
+
+			  critpoints.Append (hp);
+			}
+		  }
+	      }
+	    /*
+	      for (i = oldnl+1; i <= loclines.Size(); i++)
+	      {
+	      Point3d hp = locpoints.Get(loclines.Get(i).I1());
+	      Vec3d hv(hp, locpoints.Get(loclines.Get(i).I2()));
+	      int ncp = 2;
+	      for (j = 1; j <= ncp; j++)
+	      critpoints.Append ( hp + (double(j)/(ncp+1)) * hv);
+	      }
+	    */
+
+
+	    /*
+	      for (i = oldnp+1; i <= locpoints.Size(); i++)
+	      {
+	      const Point3d & p = locpoints.Get(i);
+	    */
+
+
+	    for (int i = 1; i <= critpoints.Size(); i++)
+	      {
+		const Point3d & p = critpoints.Get(i);
+		 
+
+		/*
+		  for (j = 1; j <= mesh.GetNSE(); j++)
+		  {
+		*/
+		int jj;
+		for (jj = 1; jj <= intersecttrias.Size(); jj++)
+		  {
+		    int j = intersecttrias.Get(jj);
+		    const Element2d & el = mesh.SurfaceElement(j);
+		  
+		    int ntrig = (el.GetNP() == 3) ? 1 : 2;
+
+		    int jl;
+		    for (jl = 1; jl <= ntrig; jl++)
+		      {
+			Point3d tp1, tp2, tp3;
+
+			if (jl == 1)
+			  {
+			    tp1 = mesh.Point(el.PNum(1));
+			    tp2 = mesh.Point(el.PNum(2));
+			    tp3 = mesh.Point(el.PNum(3));
+			  }
+			else
+			  {
+			    tp1 = mesh.Point(el.PNum(1));
+			    tp2 = mesh.Point(el.PNum(3));
+			    tp3 = mesh.Point(el.PNum(4));
+			  }
+
+			int onchart = 0;
+			for (int k = 1; k <= el.GetNP(); k++)
+			  if (BelongsToActiveChart (mesh.Point(el.PNum(k)),
+						    el.GeomInfoPi(k)))
+			    onchart = 1;
+			if (!onchart)
+			  continue;
+		      
+			Vec3d e1(tp1, tp2);
+			Vec3d e2(tp1, tp3);
+			Vec3d n = Cross (e1, e2);
+			n /= n.Length();
+			double lam1, lam2, lam3;
+			lam3 = n * Vec3d (tp1, p);
+			LocalCoordinates (e1, e2, Vec3d (tp1, p), lam1, lam2);
+		      
+			if (fabs (lam3) < 0.1 * hshould && 
+			    lam1 > 0 && lam2 > 0 && (lam1 + lam2) < 1)
+			  {
+#ifdef DEVELOP
+			    cout << "overlap" << endl;
+			    (*testout) << "overlap:" << endl
+				       << "tri = " << tp1 << "-" << tp2 << "-" << tp3 << endl
+				       << "point = " << p << endl
+				       << "lam1, 2 = " << lam1 << ", " << lam2 << endl
+				       << "lam3 = " << lam3 << endl;
+			  
+			    //		      cout << "overlap !!!" << endl;
+#endif
+			    for (int k = 1; k <= 5; k++)
+			      adfront -> IncrementClass (lindex.Get(1));
+
+			    found = 0;
+			  
+			    if ( debugflag || debugparam.haltnosuccess )
+			      PrintWarning ("overlapping");
+			  
+			  
+			    if (debugparam.haltoverlap)
+			      {
+				debugflag = 1;
+			      }
+			  
+			    /*
+			      multithread.drawing = 1;
+			      glrender(1);
+			    */
+			  }
+		      }
+		  }
+	      }
+	  }
+
+
+	if (found)
+	  {
+	    // check, whether new front line already exists
+
+	    for (int i = oldnl+1; i <= loclines.Size(); i++)
+	      {
+		int nlgpi1 = loclines.Get(i).I1();
+		int nlgpi2 = loclines.Get(i).I2();
+		if (nlgpi1 <= pindex.Size() && nlgpi2 <= pindex.Size())
+		  {
+		    nlgpi1 = adfront->GetGlobalIndex (pindex.Get(nlgpi1));
+		    nlgpi2 = adfront->GetGlobalIndex (pindex.Get(nlgpi2));
+
+		    int exval = adfront->ExistsLine (nlgpi1, nlgpi2);
+		    if (exval)
+		      {
+			cout << "ERROR: new line exits, val = " << exval << endl;
+			(*testout) << "ERROR: new line exits, val = " << exval << endl;
+			found = 0;
+
+
+			if (debugparam.haltexistingline)
+			  debugflag = 1;
+
+		      }
+		  }
+	      }
+	  
+	  }
+
+
+	/*
+	  if (found)
+	  {
+	  // check, whether new triangles insert edges twice
+	  for (i = 1; i <= locelements.Size(); i++)
+	  for (j = 1; j <= 3; j++)
+	  {
+	  int tpi1 = locelements.Get(i).PNumMod (j);
+	  int tpi2 = locelements.Get(i).PNumMod (j+1);
+	  if (tpi1 <= pindex.Size() && tpi2 <= pindex.Size())
+	  {
+	  tpi1 = adfront->GetGlobalIndex (pindex.Get(tpi1));
+	  tpi2 = adfront->GetGlobalIndex (pindex.Get(tpi2));
+
+	  if (doubleedge.Used (INDEX_2(tpi1, tpi2)))
+	  {
+	  if (debugparam.haltexistingline)
+	  debugflag = 1;
+	  cerr << "ERROR Insert edge "
+	  << tpi1 << " - " << tpi2 << " twice !!!" << endl;
+	  found = 0;
+	  }
+	  doubleedge.Set (INDEX_2(tpi1, tpi2), 1);
+	  }
+	  }
+	  }
+	*/
+
+
+	if (found)
+	  {
+	    // everything is ok, perform mesh update
+
+	    ruleused.Elem(rulenr)++;
+
+
+	    pindex.SetSize(locpoints.Size());
+	      
+	    for (int i = oldnp+1; i <= locpoints.Size(); i++)
+	      {
+		globind = mesh.AddPoint (locpoints.Get(i));
+		pindex.Elem(i) = adfront -> AddPoint (locpoints.Get(i), globind);
+	      }
+	      
+	    for (int i = oldnl+1; i <= loclines.Size(); i++)
+	      {
+		/*
+		  for (j = 1; j <= locpoints.Size(); j++)
+		  {
+		  (*testout) << j << ": " << locpoints.Get(j) << endl;
+		  }
+		*/
+	      
+		/*
+		  ComputeLineGeoInfo (locpoints.Get(loclines.Get(i).I1()),
+		  locpoints.Get(loclines.Get(i).I2()),
+		  gisize, geominfo);
+		*/		  
+
+		if (pindex.Get(loclines.Get(i).I1()) == -1 || 
+		    pindex.Get(loclines.Get(i).I2()) == -1)
+		  {
+		    (*testout) << "pindex is 0" << endl;
+		  }
+
+		if (!upgeominfo.Get(loclines.Get(i).I1()).trignum || 
+		    !upgeominfo.Get(loclines.Get(i).I2()).trignum)
+		  {
+		    cout << "new el: illegal geominfo" << endl;
+		  }
+
+		adfront -> AddLine (pindex.Get(loclines.Get(i).I1()),
+				    pindex.Get(loclines.Get(i).I2()),
+				    upgeominfo.Get(loclines.Get(i).I1()),
+				    upgeominfo.Get(loclines.Get(i).I2()));
+	      }
+	    for (int i = 1; i <= locelements.Size(); i++)
+	      {
+		Element2d mtri(locelements.Get(i).GetNP());
+		mtri = locelements.Get(i);
+		mtri.SetIndex (facenr);
+
+
+		// compute triangle geominfo:
+		//	      (*testout) << "triggeominfo: ";
+		for (int j = 1; j <= locelements.Get(i).GetNP(); j++)
+		  {
+		    mtri.GeomInfoPi(j) = upgeominfo.Get(locelements.Get(i).PNum(j));
+		    //		  (*testout) << mtri.GeomInfoPi(j).trignum << " ";
+		  }
+		//	      (*testout) << endl;
+
+		for (int j = 1; j <= locelements.Get(i).GetNP(); j++)
+		  {
+		    mtri.PNum(j) = 
+		      locelements.Elem(i).PNum(j) =
+		      adfront -> GetGlobalIndex (pindex.Get(locelements.Get(i).PNum(j)));
+		  }
+	      
+		
+	      
+	      
+		mesh.AddSurfaceElement (mtri);
+		cntelem++;
+		//	      cout << "elements: " << cntelem << endl;
+
+
+	      
+		Box<3> box;
+		box.Set (mesh[mtri[0]]);
+		box.Add (mesh[mtri[1]]);
+		box.Add (mesh[mtri[2]]);
+		surfeltree.Insert (box, mesh.GetNSE());
+
+		const Point3d & sep1 = mesh.Point (mtri.PNum(1));
+		const Point3d & sep2 = mesh.Point (mtri.PNum(2));
+		const Point3d & sep3 = mesh.Point (mtri.PNum(3));
+
+		double trigarea = Cross (Vec3d (sep1, sep2), 
+					 Vec3d (sep1, sep3)).Length() / 2;
+
+		if (mtri.GetNP() == 4)
+		  {
+		    const Point3d & sep4 = mesh.Point (mtri.PNum(4));
+		    trigarea += Cross (Vec3d (sep1, sep3), 
+				       Vec3d (sep1, sep4)).Length() / 2;
+		  }
+
+		meshedarea += trigarea;
+
+		if(maxarea > 0 && meshedarea-meshedarea_before > maxarea)
+		  {
+		    cerr << "meshed area = " << meshedarea-meshedarea_before << endl
+			 << "maximal area = " << maxarea << endl
+			 << "GIVING UP" << endl;
+		    return MESHING2_GIVEUP;
+		  }
+	      
+
+
+		for (int j = 1; j <= locelements.Get(i).GetNP(); j++)
+		  {
+		    int gpi = locelements.Get(i).PNum(j);
+
+		    int oldts = trigsonnode.Size();
+		    if (gpi >= oldts+PointIndex::BASE)
+		      {
+			trigsonnode.SetSize (gpi+1-PointIndex::BASE);
+			illegalpoint.SetSize (gpi+1-PointIndex::BASE);
+			for (int k = oldts+PointIndex::BASE; 
+			     k <= gpi; k++)
+			  {
+			    trigsonnode[k] = 0;
+			    illegalpoint[k] = 0;
+			  }
+		      }
+
+		    trigsonnode[gpi]++;
+		  
+		    if (trigsonnode[gpi] > 20)
+		      {
+			illegalpoint[gpi] = 1;
+			//		      cout << "illegal point: " << gpi << endl;
+			(*testout) << "illegal point: " << gpi << endl;
+		      }
+
+		    static int mtonnode = 0;
+		    if (trigsonnode[gpi] > mtonnode)
+		      mtonnode = trigsonnode[gpi];
+		  }
+		//	      cout << "els = " << cntelem << " trials = " << trials << endl;
+		//	      if (trials > 100)		return;
+	      }
+	      
+	    for (int i = 1; i <= dellines.Size(); i++)
+	      adfront -> DeleteLine (lindex.Get(dellines.Get(i)));
+	      
+	    //	  rname = rules.Get(rulenr)->Name();
+#ifdef MYGRAPH
+	    if (silentflag<3) 
+	      {
+		plotsurf.DrawPnL(locpoints, loclines);
+		plotsurf.Plot(testmode, testmode);
+	      }
+#endif
+
+	    if (morerisc)
+	      {
+		cout << "generated due to morerisc" << endl;
+		//	      multithread.drawing = 1;
+		//	      glrender(1);
+	      }
+
+
+
+	  
+	    if ( debugparam.haltsuccess || debugflag )
+	      {
+		// adfront -> PrintOpenSegments (*testout);
+		cout << "success of rule" << rules.Get(rulenr)->Name() << endl;
+		multithread.drawing = 1;
+		multithread.testmode = 1;
+		multithread.pause = 1;
+
+
+		/*
+		  extern STLGeometry * stlgeometry;
+		  stlgeometry->ClearMarkedSegs();
+		  for (i = 1; i <= loclines.Size(); i++)
+		  {
+		  stlgeometry->AddMarkedSeg(locpoints.Get(loclines.Get(i).I1()),
+		  locpoints.Get(loclines.Get(i).I2()));
+		  }
+		*/
+
+		(*testout) << "success of rule" << rules.Get(rulenr)->Name() << endl;
+		(*testout) << "trials = " << trials << endl;
+
+		(*testout) << "locpoints " << endl;
+		for (int i = 1; i <= pindex.Size(); i++)
+		  (*testout) << adfront->GetGlobalIndex (pindex.Get(i)) << endl;
+
+		(*testout) << "old number of lines = " << oldnl << endl;
+		for (int i = 1; i <= loclines.Size(); i++)
+		  {
+		    (*testout) << "line ";
+		    for (int j = 1; j <= 2; j++)
+		      {
+			int hi = 0;
+			if (loclines.Get(i).I(j) >= 1 &&
+			    loclines.Get(i).I(j) <= pindex.Size())
+			  hi = adfront->GetGlobalIndex (pindex.Get(loclines.Get(i).I(j)));
+
+			(*testout) << hi << " ";
+		      }
+		    (*testout) << " : " 
+			       << plainpoints.Get(loclines.Get(i).I1()) << " - "
+			       << plainpoints.Get(loclines.Get(i).I2()) << " 3d: "
+			       << locpoints.Get(loclines.Get(i).I1()) << " - "
+			       << locpoints.Get(loclines.Get(i).I2()) 
+			       << endl;
+		  }
+
+
+
+		glrender(1);
+	      }
+	  }
+	else
+	  {
+	    adfront -> IncrementClass (lindex.Get(1));
+
+	    if ( debugparam.haltnosuccess || debugflag )
+	      {
+		cout << "Problem with seg " << gpi1 << " - " << gpi2
+		     << ", class = " << qualclass << endl;
+
+		(*testout) << "Problem with seg " << gpi1 << " - " << gpi2
+			   << ", class = " << qualclass << endl;
+
+		multithread.drawing = 1;
+		multithread.testmode = 1;
+		multithread.pause = 1;
+
+
+		/*
+		  extern STLGeometry * stlgeometry;
+		  stlgeometry->ClearMarkedSegs();
+		  for (i = 1; i <= loclines.Size(); i++)
+		  {
+		  stlgeometry->AddMarkedSeg(locpoints.Get(loclines.Get(i).I1()),
+		  locpoints.Get(loclines.Get(i).I2()));
+		  }
+		*/
+
+		for (int i = 1; i <= loclines.Size(); i++)
+		  {
+		    (*testout) << "line ";
+		    for (int j = 1; j <= 2; j++)
+		      {
+			int hi = 0;
+			if (loclines.Get(i).I(j) >= 1 &&
+			    loclines.Get(i).I(j) <= pindex.Size())
+			  hi = adfront->GetGlobalIndex (pindex.Get(loclines.Get(i).I(j)));
+
+			(*testout) << hi << " ";
+		      }
+		    (*testout) << " : " 
+			       << plainpoints.Get(loclines.Get(i).I1()) << " - "
+			       << plainpoints.Get(loclines.Get(i).I2()) << " 3d: "
+			       << locpoints.Get(loclines.Get(i).I1()) << " - "
+			       << locpoints.Get(loclines.Get(i).I2()) 
+			       << endl;
+		  }
+
+
+		/*
+		  cout << "p1gi = " << blgeominfo[0].trignum 
+		  << ", p2gi = " << blgeominfo[1].trignum << endl;
+		*/
+
+		glrender(1);
+	      }
+
+	  
+#ifdef MYGRAPH      
+	    if (silentflag<3)
+	      {
+		if (testmode || trials%2 == 0)
+		  {
+		    plotsurf.DrawPnL(locpoints, loclines);
+		    plotsurf.Plot(testmode, testmode);
+		  }
+	      }
+#endif
+	  }
+
+      }
+
+    PrintMessage (3, "Surface meshing done");
+
+    adfront->PrintOpenSegments (*testout);
+
+    multithread.task = savetask;
+
+
+    //  cout << "surfeltree.depth = " << surfeltree.Tree().Depth() << endl;
+    EndMesh ();
+
+    if (!adfront->Empty())
+      return MESHING2_GIVEUP;
+    
+    return MESHING2_OK;
+  }
+
+
+
+
+
+
+
+
+
+}
+
+
+
+
+
+
+
+#ifdef OPENGL
+
+/* *********************** Draw Surface Meshing **************** */
+
+
+#include <visual.hpp>
+#include <stlgeom.hpp>
+
+namespace netgen 
+{
+
+  extern STLGeometry * stlgeometry;
+  extern Mesh * mesh;
+  VisualSceneSurfaceMeshing vssurfacemeshing;
+
+
+
+  void glrender (int wait)
+  {
+    //  cout << "plot adfront" << endl;
+
+    if (multithread.drawing)
+      {
+	//      vssurfacemeshing.Render();
+	Render ();
+      
+	if (wait || multithread.testmode)
+	  {
+	    multithread.pause = 1;
+	  }
+	while (multithread.pause);
+      }
+  }
+
+
+
+  VisualSceneSurfaceMeshing :: VisualSceneSurfaceMeshing ()
+    : VisualScene()
+  {
+    ;
+  }
+
+  VisualSceneSurfaceMeshing :: ~VisualSceneSurfaceMeshing ()
+  {
+    ;
+  }
+
+  void VisualSceneSurfaceMeshing :: DrawScene ()
+  {
+    int i, j, k;
+
+    if (loclines.Size() != changeval)
+      {
+	center = Point<3>(0,0,-5);
+	rad = 0.1;
+  
+	CalcTransformationMatrices();
+	changeval = loclines.Size();
+      }
+
+  glClearColor(backcolor, backcolor, backcolor, 1.0);
+  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+  SetLight();
+
+  //  glEnable (GL_COLOR_MATERIAL);
+
+  //  glDisable (GL_SHADING);
+  //  glColor3f (0.0f, 1.0f, 1.0f);
+  //  glLineWidth (1.0f);
+  //  glShadeModel (GL_SMOOTH);
+
+  //  glCallList (linelists.Get(1));
+
+  //  SetLight();
+
+  glPushMatrix();
+  glMultMatrixf (transformationmat);
+
+  glShadeModel (GL_SMOOTH);
+  // glDisable (GL_COLOR_MATERIAL);
+  glEnable (GL_COLOR_MATERIAL);
+  glPolygonMode (GL_FRONT_AND_BACK, GL_FILL);
+
+  glEnable (GL_BLEND);
+  glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
+  //  glEnable (GL_LIGHTING);
+
+  double shine = vispar.shininess;
+  double transp = vispar.transp;
+
+  glMaterialf (GL_FRONT_AND_BACK, GL_SHININESS, shine);
+  glLogicOp (GL_COPY);
+
+
+
+  /*
+
+  float mat_col[] = { 0.2, 0.2, 0.8, 1 };
+  glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, mat_col);
+
+  glPolygonOffset (1, 1);
+  glEnable (GL_POLYGON_OFFSET_FILL);
+
+    float mat_colbl[] = { 0.8, 0.2, 0.2, 1 };
+    float mat_cololdl[] = { 0.2, 0.8, 0.2, 1 };
+    float mat_colnewl[] = { 0.8, 0.8, 0.2, 1 };
+
+
+    glPolygonMode (GL_FRONT_AND_BACK, GL_FILL);
+    glPolygonOffset (1, -1);
+    glLineWidth (3);
+
+    for (i = 1; i <= loclines.Size(); i++)
+      {
+	if (i == 1)
+	  {
+	    glEnable (GL_POLYGON_OFFSET_FILL);
+	    glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, mat_colbl);
+	  }
+	else if (i <= oldnl) 
+	  glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, mat_cololdl);
+	else 
+	  glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, mat_colnewl);
+
+	int pi1 = loclines.Get(i).I1();
+	int pi2 = loclines.Get(i).I2();
+
+	if (pi1 >= 1 && pi2 >= 1)
+	  {
+	    Point3d p1 = locpoints.Get(pi1);
+	    Point3d p2 = locpoints.Get(pi2);
+	  
+	    glBegin (GL_LINES);
+	    glVertex3f (p1.X(), p1.Y(), p1.Z());
+	    glVertex3f (p2.X(), p2.Y(), p2.Z());
+	    glEnd();
+	  }
+
+	glDisable (GL_POLYGON_OFFSET_FILL);
+      }
+  
+
+    glLineWidth (1);
+
+
+    glPointSize (5);
+    float mat_colp[] = { 1, 0, 0, 1 };
+    glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, mat_colp);
+    glBegin (GL_POINTS);
+    for (i = 1; i <= locpoints.Size(); i++)
+      {
+	Point3d p = locpoints.Get(i);
+	glVertex3f (p.X(), p.Y(), p.Z());
+      }
+    glEnd();
+
+
+    glPopMatrix();
+  */
+
+    float mat_colp[] = { 1, 0, 0, 1 };
+
+    float mat_col2d1[] = { 1, 0.5, 0.5, 1 };
+    float mat_col2d[] = { 1, 1, 1, 1 };
+    glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, mat_col2d);
+  
+    double scalex = 0.1, scaley = 0.1;
+
+    glBegin (GL_LINES);
+    for (i = 1; i <= loclines.Size(); i++)
+      {
+	glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, mat_col2d);
+	if (i == 1)
+	  glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, mat_col2d1);
+
+	int pi1 = loclines.Get(i).I1();
+	int pi2 = loclines.Get(i).I2();
+
+	if (pi1 >= 1 && pi2 >= 1)
+	  {
+	    Point2d p1 = plainpoints.Get(pi1);
+	    Point2d p2 = plainpoints.Get(pi2);
+	  
+	    glBegin (GL_LINES);
+	    glVertex3f (scalex * p1.X(), scaley * p1.Y(), -5);
+	    glVertex3f (scalex * p2.X(), scaley * p2.Y(), -5);
+	    glEnd();
+	  }
+      }
+    glEnd ();
+
+
+    glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, mat_colp);
+    glBegin (GL_POINTS);
+    for (i = 1; i <= plainpoints.Size(); i++)
+      {
+	Point2d p = plainpoints.Get(i);
+	glVertex3f (scalex * p.X(), scaley * p.Y(), -5);
+      }
+    glEnd();
+
+
+
+
+
+
+  glDisable (GL_POLYGON_OFFSET_FILL);
+ 
+  glPopMatrix();
+  DrawCoordinateCross ();
+  DrawNetgenLogo ();
+  glFinish();  
+
+  /*
+    glDisable (GL_POLYGON_OFFSET_FILL);
+
+    //  cout << "draw surfacemeshing" << endl;
+    //
+    //  if (changeval != stlgeometry->GetNT())
+    //      BuildScene();
+    //      changeval = stlgeometry->GetNT();
+    
+
+    glClearColor(backcolor, backcolor, backcolor, 1.0);
+    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+    SetLight();
+
+    glPushMatrix();
+    glLoadMatrixf (transmat);
+    glMultMatrixf (rotmat);
+
+    glShadeModel (GL_SMOOTH);
+    glDisable (GL_COLOR_MATERIAL);
+    glPolygonMode (GL_FRONT_AND_BACK, GL_FILL);
+
+    glEnable (GL_BLEND);
+    glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
+    float mat_spec_col[] = { 1, 1, 1, 1 };
+    glMaterialfv (GL_FRONT_AND_BACK, GL_SPECULAR, mat_spec_col);
+
+    double shine = vispar.shininess;
+    double transp = vispar.transp;
+
+    glMaterialf (GL_FRONT_AND_BACK, GL_SHININESS, shine);
+    glLogicOp (GL_COPY);
+
+
+    float mat_col[] = { 0.2, 0.2, 0.8, transp };
+    float mat_colrt[] = { 0.2, 0.8, 0.8, transp };
+    glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, mat_col);
+
+    glPolygonOffset (1, 1);
+    glEnable (GL_POLYGON_OFFSET_FILL);
+
+    glColor3f (1.0f, 1.0f, 1.0f);
+
+    glEnable (GL_NORMALIZE);
+    
+    //  glBegin (GL_TRIANGLES);
+    //      for (j = 1; j <= stlgeometry -> GetNT(); j++)
+    //      {
+    //      glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, mat_col);
+    //      if (j == geomtrig)
+    //      glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, mat_colrt);
+	
+
+    //      const STLReadTriangle & tria = stlgeometry -> GetReadTriangle(j);
+    //      glNormal3f (tria.normal.X(),
+    //      tria.normal.Y(),
+    //      tria.normal.Z());
+		  
+    //      for (k = 0; k < 3; k++)
+    //      {
+    //      glVertex3f (tria.pts[k].X(),
+    //      tria.pts[k].Y(),
+    //      tria.pts[k].Z());
+    //      }
+    //      }    
+    //      glEnd ();
+    
+
+
+    glDisable (GL_POLYGON_OFFSET_FILL);
+
+    float mat_colbl[] = { 0.8, 0.2, 0.2, 1 };
+    float mat_cololdl[] = { 0.2, 0.8, 0.2, 1 };
+    float mat_colnewl[] = { 0.8, 0.8, 0.2, 1 };
+
+
+    glPolygonMode (GL_FRONT_AND_BACK, GL_FILL);
+    glPolygonOffset (1, -1);
+    glLineWidth (3);
+
+    for (i = 1; i <= loclines.Size(); i++)
+      {
+	if (i == 1)
+	  {
+	    glEnable (GL_POLYGON_OFFSET_FILL);
+	    glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, mat_colbl);
+	  }
+	else if (i <= oldnl) 
+	  glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, mat_cololdl);
+	else 
+	  glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, mat_colnewl);
+
+	int pi1 = loclines.Get(i).I1();
+	int pi2 = loclines.Get(i).I2();
+
+	if (pi1 >= 1 && pi2 >= 1)
+	  {
+	    Point3d p1 = locpoints.Get(pi1);
+	    Point3d p2 = locpoints.Get(pi2);
+	  
+	    glBegin (GL_LINES);
+	    glVertex3f (p1.X(), p1.Y(), p1.Z());
+	    glVertex3f (p2.X(), p2.Y(), p2.Z());
+	    glEnd();
+	  }
+
+	glDisable (GL_POLYGON_OFFSET_FILL);
+      }
+
+
+    glLineWidth (1);
+
+
+    glPointSize (5);
+    float mat_colp[] = { 1, 0, 0, 1 };
+    glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, mat_colp);
+    glBegin (GL_POINTS);
+    for (i = 1; i <= locpoints.Size(); i++)
+      {
+	Point3d p = locpoints.Get(i);
+	glVertex3f (p.X(), p.Y(), p.Z());
+      }
+    glEnd();
+
+
+    glPopMatrix();
+
+
+    float mat_col2d1[] = { 1, 0.5, 0.5, 1 };
+    float mat_col2d[] = { 1, 1, 1, 1 };
+    glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, mat_col2d);
+  
+    double scalex = 0.1, scaley = 0.1;
+
+    glBegin (GL_LINES);
+    for (i = 1; i <= loclines.Size(); i++)
+      {
+	glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, mat_col2d);
+	if (i == 1)
+	  glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, mat_col2d1);
+
+	int pi1 = loclines.Get(i).I1();
+	int pi2 = loclines.Get(i).I2();
+
+	if (pi1 >= 1 && pi2 >= 1)
+	  {
+	    Point2d p1 = plainpoints.Get(pi1);
+	    Point2d p2 = plainpoints.Get(pi2);
+	  
+	    glBegin (GL_LINES);
+	    glVertex3f (scalex * p1.X(), scaley * p1.Y(), -5);
+	    glVertex3f (scalex * p2.X(), scaley * p2.Y(), -5);
+	    glEnd();
+	  }
+      }
+    glEnd ();
+
+
+    glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, mat_colp);
+    glBegin (GL_POINTS);
+    for (i = 1; i <= plainpoints.Size(); i++)
+      {
+	Point2d p = plainpoints.Get(i);
+	glVertex3f (scalex * p.X(), scaley * p.Y(), -5);
+      }
+    glEnd();
+
+    glFinish();  
+*/
+  }
+
+
+  void VisualSceneSurfaceMeshing :: BuildScene (int zoomall)
+  {
+    int i, j, k;
+    /*
+      center = stlgeometry -> GetBoundingBox().Center();
+      rad = stlgeometry -> GetBoundingBox().Diam() / 2;
+
+      CalcTransformationMatrices();
+    */
+  }
+
+}
+
+
+#else
+namespace netgen
+{
+  void glrender (int wait)
+  { ; }
+}
+#endif
diff --git a/contrib/Netgen/libsrc/meshing/meshing2.hpp b/contrib/Netgen/libsrc/meshing/meshing2.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..0912fa34c66325e01aa317be08d89a3b3a64c504
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/meshing2.hpp
@@ -0,0 +1,156 @@
+#ifndef FILE_MESHING2
+#define FILE_MESHING2
+
+/**************************************************************************/
+/* File:   meshing2.hpp                                                   */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   01. Okt. 95                                                    */
+/**************************************************************************/
+
+
+
+enum MESHING2_RESULT
+{
+  MESHING2_OK = 0,
+  MESHING2_GIVEUP = 1,
+};
+
+
+/*
+   
+The basis class for 2D mesh generation. 
+Has the method GenerateMesh
+
+For surface mesh generation, or non-Euklidean meshing,
+derive from Meshing2, and replace transformation.
+
+*/
+
+class Meshing2
+{
+  /// the current advancing front
+  AdFront2 * adfront;
+  /// rules for mesh generation
+  ARRAY<netrule*> rules;
+  /// statistics
+  ARRAY<int> ruleused, canuse, foundmap;
+  /// 
+  Box<3> boundingbox;
+  ///
+  double starttime;
+  ///
+  double maxarea;
+
+public:
+  ///
+  Meshing2 (const Box<3> & aboundingbox);
+
+  ///
+  virtual ~Meshing2 ();
+
+  /// Load rules, either from file, or compiled rules
+  void LoadRules (const char * filename);
+
+  /// 
+  MESHING2_RESULT GenerateMesh (Mesh & mesh, double gh, int facenr);
+
+  ///
+  void AddPoint (const Point3d & p, PointIndex globind, MultiPointGeomInfo * mgi = NULL,
+		 bool pointonsurface = true);
+
+  ///
+  void AddBoundaryElement (INDEX i1, INDEX i2,
+			   const PointGeomInfo & gi1, const PointGeomInfo & gi2);
+  
+  ///
+  void SetStartTime (double astarttime);
+
+  ///
+  void SetMaxArea (double amaxarea);
+
+protected:
+  ///
+  virtual void StartMesh ();
+  ///
+  virtual void EndMesh ();
+  ///
+  virtual double CalcLocalH (const Point3d & p, double gh) const;
+
+  ///
+  virtual void DefineTransformation (const Point3d & p1, const Point3d & p2,
+				     const PointGeomInfo * geominfo1,
+				     const PointGeomInfo * geominfo2);
+  ///
+  virtual void TransformToPlain (const Point3d & locpoint, const MultiPointGeomInfo &  geominfo,
+				 Point2d & plainpoint, double h, int & zone);
+  /// return 0 .. ok
+  /// return >0 .. cannot transform point to true surface
+  virtual int TransformFromPlain (Point2d & plainpoint,
+				  Point3d & locpoint, 
+				  PointGeomInfo & geominfo, 
+				  double h);
+  
+  /// projects to surface
+  /// return 0 .. ok
+  virtual int BelongsToActiveChart (const Point3d & p, 
+				    const PointGeomInfo & gi);
+
+  /// computes geoinfo data for line with respect to
+  /// selected chart
+  virtual int ComputePointGeomInfo (const Point3d & p, 
+				    PointGeomInfo & gi);
+
+  /// Tries to select unique geominfo on active chart
+  /// return 0: success
+  /// return 1: failed
+  virtual int ChooseChartPointGeomInfo (const MultiPointGeomInfo & mpgi, 
+					PointGeomInfo & pgi);
+
+
+
+  /*
+    tests, whether endpoint (= 1 or 2) of line segment p1-p2
+    is inside of the selected chart. The endpoint must be on the
+    chart
+   */
+  virtual int IsLineVertexOnChart (const Point3d & p1, const Point3d & p2,
+				   int endpoint, const PointGeomInfo & geominfo);
+
+  /*
+    get (projected) boundary of current chart
+   */
+  virtual void GetChartBoundary (ARRAY<Point2d> & points, 
+				 ARRAY<Point3d> & points3d,
+				 ARRAY<INDEX_2> & lines, double p) const;
+
+  virtual double Area () const;
+
+
+/** Applies 2D rules.
+ Tests all 2D rules */
+  int ApplyRules (ARRAY<Point2d> & lpoints, 
+		  ARRAY<int> & legalpoints,
+		  int maxlegalpoint,
+		  ARRAY<INDEX_2> & llines,
+		  int maxlegelline,
+		  ARRAY<Element2d> & elements, ARRAY<INDEX> & dellines,
+		  int tolerance);
+  
+
+};
+
+
+
+
+
+
+
+
+#endif
+
+
+
+
+
+
+
diff --git a/contrib/Netgen/libsrc/meshing/meshing3.cpp b/contrib/Netgen/libsrc/meshing/meshing3.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..075fd6b384b97db7ff7ff8cf1cfaec5f4933bdd5
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/meshing3.cpp
@@ -0,0 +1,1292 @@
+#include <mystdlib.h>
+#include "meshing.hpp"
+
+namespace netgen
+{
+
+double minother;
+double minwithoutother;
+
+
+
+
+
+MeshingStat3d :: MeshingStat3d ()
+{
+  cntsucc = cnttrials = cntelem = qualclass = 0;
+  vol0 = h = 1;
+  problemindex = 1;
+}  
+  
+
+Meshing3 :: Meshing3 (const string & rulefilename) 
+{
+  tolfak = 1;
+
+  LoadRules (rulefilename.c_str(), NULL);
+  adfront = new AdFront3;
+
+  problems.SetSize (rules.Size());
+  foundmap.SetSize (rules.Size());
+  canuse.SetSize (rules.Size());
+  ruleused.SetSize (rules.Size());
+
+  for (int i = 1; i <= rules.Size(); i++)
+    {
+      problems.Elem(i) = new char[255];
+      foundmap.Elem(i) = 0;
+      canuse.Elem(i) = 0;
+      ruleused.Elem(i) = 0;
+    }
+}
+
+
+Meshing3 :: Meshing3 (const char ** rulep)
+{
+  tolfak = 1;
+
+  LoadRules (NULL, rulep);
+  adfront = new AdFront3;
+
+  problems.SetSize (rules.Size());
+  foundmap.SetSize (rules.Size());
+  canuse.SetSize (rules.Size());
+  ruleused.SetSize (rules.Size());
+
+  for (int i = 0; i < rules.Size(); i++)
+    {
+      problems[i] = new char[255];
+      foundmap[i] = 0;
+      canuse[i]   = 0;
+      ruleused[i] = 0;
+    }
+}
+
+Meshing3 :: ~Meshing3 ()
+{
+  delete adfront;
+  for (int i = 0; i < rules.Size(); i++)
+    {
+      delete [] problems[i];
+      delete rules[i];
+    }
+}
+
+
+
+static double CalcLocH (const ARRAY<Point3d> & locpoints,
+			const ARRAY<MiniElement2d> & locfaces,
+			double h)
+{
+  return h;
+
+  // was war das ????
+  
+  int i, j;
+  double hi, h1, d, dn, sum, weight, wi;
+  Point3d p0, pc;
+  Vec3d n, v1, v2;
+
+  p0.X() = p0.Y() = p0.Z() = 0;
+  for (j = 1; j <= 3; j++)
+    {
+      p0.X() += locpoints.Get(locfaces.Get(1).PNum(j)).X();
+      p0.Y() += locpoints.Get(locfaces.Get(1).PNum(j)).Y();
+      p0.Z() += locpoints.Get(locfaces.Get(1).PNum(j)).Z();
+    }
+  p0.X() /= 3; p0.Y() /= 3; p0.Z() /= 3;
+  
+  v1 = locpoints.Get(locfaces.Get(1).PNum(2)) -
+    locpoints.Get(locfaces.Get(1).PNum(1));
+  v2 = locpoints.Get(locfaces.Get(1).PNum(3)) -
+    locpoints.Get(locfaces.Get(1).PNum(1));
+
+  h1 = v1.Length();
+  n = Cross (v2, v1);
+  n /= n.Length();
+
+  sum = 0;
+  weight = 0;
+
+  for (i = 1; i <= locfaces.Size(); i++)
+    {
+      pc.X() = pc.Y() = pc.Z() = 0;
+      for (j = 1; j <= 3; j++)
+	{
+	  pc.X() += locpoints.Get(locfaces.Get(i).PNum(j)).X();
+	  pc.Y() += locpoints.Get(locfaces.Get(i).PNum(j)).Y();
+	  pc.Z() += locpoints.Get(locfaces.Get(i).PNum(j)).Z();
+	}
+      pc.X() /= 3; pc.Y() /= 3; pc.Z() /= 3;
+
+      d = Dist (p0, pc);
+      dn = n * (pc - p0);
+      hi = Dist (locpoints.Get(locfaces.Get(i).PNum(1)),
+		 locpoints.Get(locfaces.Get(i).PNum(2)));
+		 
+      if (dn > -0.2 * h1)
+	{
+	  wi = 1 / (h1 + d);
+	  wi *= wi;
+	}
+      else
+	wi = 0;
+
+      sum += hi * wi;
+      weight += wi;
+    }
+
+  return sum/weight;
+}
+
+
+PointIndex Meshing3 :: AddPoint (const Point3d & p, PointIndex globind)
+{
+  return adfront -> AddPoint (p, globind);  
+}  
+
+void Meshing3 :: AddBoundaryElement (const Element2d & elem)
+{
+  MiniElement2d mini(elem.GetNP());
+  for (int j = 0; j < elem.GetNP(); j++)
+    mini[j] = elem[j];
+  adfront -> AddFace(mini);
+}  
+
+
+void Meshing3 :: AddBoundaryElement (const MiniElement2d & elem)
+{
+  adfront -> AddFace(elem);
+}
+
+int Meshing3 :: AddConnectedPair (const INDEX_2 & apair)
+{
+  return adfront -> AddConnectedPair (apair);
+}
+
+MESHING3_RESULT Meshing3 :: 
+GenerateMesh (Mesh & mesh, const MeshingParameters & mp)
+{
+  static int meshing3_timer = NgProfiler::CreateTimer ("Meshing3::GenerateMesh");
+  static int meshing3_timer_a = NgProfiler::CreateTimer ("Meshing3::GenerateMesh a");
+  static int meshing3_timer_b = NgProfiler::CreateTimer ("Meshing3::GenerateMesh b");
+  static int meshing3_timer_c = NgProfiler::CreateTimer ("Meshing3::GenerateMesh c");
+  static int meshing3_timer_d = NgProfiler::CreateTimer ("Meshing3::GenerateMesh d");
+  NgProfiler::RegionTimer reg (meshing3_timer);
+
+
+  ARRAY<Point3d > locpoints;      // local points
+  ARRAY<MiniElement2d> locfaces;     // local faces
+  ARRAY<PointIndex> pindex;      // mapping from local to front point numbering
+  ARRAY<int> allowpoint;         // point is allowd ?
+  ARRAY<INDEX> findex;           // mapping from local to front face numbering
+  //INDEX_2_HASHTABLE<int> connectedpairs(100);  // connecgted pairs for prism meshing
+
+  ARRAY<Point3d > plainpoints;       // points in reference coordinates
+  ARRAY<int> delpoints, delfaces;   // points and lines to be deleted
+  ARRAY<Element> locelements;       // new generated elements
+
+  int i, j, oldnp, oldnf;
+  int found;
+  referencetransform trans;
+  int rotind;
+  INDEX globind;
+  Point3d inp;
+  float err;
+
+  INDEX locfacesplit;             //index for faces in outer area
+  
+  bool loktestmode = false;
+
+  int uselocalh = mp.uselocalh;
+
+  // int giveuptol = mp.giveuptol; // 
+  MeshingStat3d stat;      // statistics
+  int plotstat_oldne = -1;
+
+  
+  // for star-shaped domain meshing
+  ARRAY<MeshPoint> grouppoints;      
+  ARRAY<MiniElement2d> groupfaces;
+  ARRAY<PointIndex> grouppindex;
+  ARRAY<INDEX> groupfindex;
+  
+  
+  float minerr;
+  int hasfound;
+  double tetvol;
+  // int giveup = 0;
+
+  
+  ARRAY<Point3d> tempnewpoints;
+  ARRAY<MiniElement2d> tempnewfaces;
+  ARRAY<int> tempdelfaces;
+  ARRAY<Element> templocelements;
+
+
+  stat.h = mp.maxh;
+
+  adfront->SetStartFront (mp.baseelnp);
+
+
+  found = 0;
+  stat.vol0 = adfront -> Volume();
+  tetvol = 0;
+
+  stat.qualclass = 1;
+
+  while (1)
+    {
+      if (multithread.terminate)
+	throw NgException ("Meshing stopped");
+
+      // break if advancing front is empty
+      if (!mp.baseelnp && adfront->Empty())
+	break;
+
+      // break, if advancing front has no elements with
+      // mp.baseelnp nodes  
+      if (mp.baseelnp && adfront->Empty (mp.baseelnp))
+	break;
+
+      locpoints.SetSize(0);
+      locfaces.SetSize(0);
+      locelements.SetSize(0);
+      pindex.SetSize(0);
+      findex.SetSize(0);
+
+      INDEX_2_HASHTABLE<int> connectedpairs(100);  // connected pairs for prism meshing
+      
+      // select base-element (will be locface[1])
+      // and get local environment of radius (safety * h)
+
+
+      int baseelem = adfront -> SelectBaseElement ();
+      if (mp.baseelnp && adfront->GetFace (baseelem).GetNP() != mp.baseelnp)
+	{
+	  adfront->IncrementClass (baseelem);	  
+	  continue;
+	}
+
+      const MiniElement2d & bel = adfront->GetFace (baseelem);
+      const Point3d & p1 = adfront->GetPoint (bel.PNum(1));
+      const Point3d & p2 = adfront->GetPoint (bel.PNum(2));
+      const Point3d & p3 = adfront->GetPoint (bel.PNum(3));
+
+      // (*testout) << endl << "base = " << bel << endl;
+
+
+      Point3d pmid = Center (p1, p2, p3);
+
+      double his = (Dist (p1, p2) + Dist(p1, p3) + Dist(p2, p3)) / 3;
+      double hshould;
+
+      hshould = mesh.GetH (pmid);
+
+      if (adfront->GetFace (baseelem).GetNP() == 4)
+	hshould = max2 (his, hshould);
+
+      double hmax = (his > hshould) ? his : hshould;
+      
+      // qualclass should come from baseelem !!!!!
+      double hinner = hmax * (1 + stat.qualclass);
+      double houter = hmax * (1 + 2 * stat.qualclass);
+
+      NgProfiler::StartTimer (meshing3_timer_a);
+      stat.qualclass =
+        adfront -> GetLocals (baseelem, locpoints, locfaces, 
+			      pindex, findex, connectedpairs,
+			      houter, hinner,
+			      locfacesplit);
+      NgProfiler::StopTimer (meshing3_timer_a);
+
+      // (*testout) << "locfaces = " << endl << locfaces << endl;
+
+      int pi1 = pindex.Get(locfaces[0].PNum(1));
+      int pi2 = pindex.Get(locfaces[0].PNum(2));
+      int pi3 = pindex.Get(locfaces[0].PNum(3));
+
+      //loktestmode = 1;
+      testmode = loktestmode;  //changed 
+      // loktestmode = testmode =  (adfront->GetFace (baseelem).GetNP() == 4) && (rules.Size() == 5);
+
+      loktestmode = stat.qualclass > 5;
+      
+
+      if (loktestmode)
+	{
+	  (*testout) << "baseel = " << baseelem << ", ind = " << findex.Get(1) << endl;
+	  (*testout) << "pi = " << pi1 << ", " << pi2 << ", " << pi3 << endl;
+	}
+
+
+
+
+
+      if (testmode)
+	{
+	  (*testout) << "baseelem = " << baseelem << " qualclass = " << stat.qualclass << endl;
+	  (*testout) << "locpoints = " << endl << locpoints << endl;
+	  (*testout) << "connected = " << endl << connectedpairs << endl;
+	}
+
+
+
+      // loch = CalcLocH (locpoints, locfaces, h);
+      
+      stat.nff = adfront->GetNF();
+      stat.vol = adfront->Volume();
+      if (stat.vol < 0) break;
+
+      oldnp = locpoints.Size();
+      oldnf = locfaces.Size();
+
+
+      allowpoint.SetSize(locpoints.Size());
+      if (uselocalh && stat.qualclass <= 3)
+	for (i = 1; i <= allowpoint.Size(); i++)
+	  {
+	    allowpoint.Elem(i) =
+	      (mesh.GetH (locpoints.Get(i)) > 0.4 * hshould / mp.sloppy) ? 2 : 1;
+	  }
+      else
+	allowpoint = 2;
+
+
+      
+      if (stat.qualclass >= mp.starshapeclass &&
+	  mp.baseelnp != 4)   
+	{
+	  NgProfiler::RegionTimer reg1 (meshing3_timer_b);
+	  // star-shaped domain removing
+
+	  grouppoints.SetSize (0);
+	  groupfaces.SetSize (0);
+	  grouppindex.SetSize (0);
+	  groupfindex.SetSize (0);
+	  
+	  adfront -> GetGroup (findex[0], grouppoints, groupfaces, 
+			       grouppindex, groupfindex);
+
+	  bool onlytri = 1;
+	  for (i = 0; i < groupfaces.Size(); i++)
+	    if (groupfaces[i].GetNP() != 3) 
+	      onlytri = 0;
+	  
+	  if (onlytri && groupfaces.Size() <= 20 + 2*stat.qualclass &&
+	      FindInnerPoint (grouppoints, groupfaces, inp))
+	    {
+	      (*testout) << "inner point found" << endl;
+
+	      for (i = 1; i <= groupfaces.Size(); i++)
+		adfront -> DeleteFace (groupfindex.Get(i));
+	      
+	      for (i = 1; i <= groupfaces.Size(); i++)
+		for (j = 1; j <= locfaces.Size(); j++)
+		  if (findex.Get(j) == groupfindex.Get(i))
+		    delfaces.Append (j);
+	      
+	      
+	      delfaces.SetSize (0);
+	      
+	      INDEX npi;
+	      Element newel;
+	      
+	      npi = mesh.AddPoint (inp);
+	      newel.SetNP(4);
+	      newel.PNum(4) = npi;
+	      
+	      for (i = 1; i <= groupfaces.Size(); i++)
+		{
+		  for (j = 1; j <= 3; j++)
+		    {
+		      newel.PNum(j) = 
+			adfront->GetGlobalIndex 
+			(grouppindex.Get(groupfaces.Get(i).PNum(j)));
+		    }
+		  mesh.AddVolumeElement (newel);
+		}
+	      continue;
+	    }
+	}
+      
+      found = 0;
+      hasfound = 0;
+      minerr = 1e6;
+
+      //      int optother = 0;
+
+      /*
+      for (i = 1; i <= locfaces.Size(); i++)
+	{
+	  (*testout) << "Face " << i << ": ";
+	  for (j = 1; j <= locfaces.Get(i).GetNP(); j++)
+	    (*testout) << pindex.Get(locfaces.Get(i).PNum(j)) << " ";
+	  (*testout) << endl;
+	}
+      for (i = 1; i <= locpoints.Size(); i++)
+	{
+	  (*testout) << "p" << i 
+		     << ", gi = " << pindex.Get(i) 
+		     << " = " << locpoints.Get(i) << endl;
+	}
+	*/
+
+      minother = 1e10;
+      minwithoutother = 1e10;
+
+      bool impossible = 1;
+
+      for (rotind = 1; rotind <= locfaces[0].GetNP(); rotind++)
+	{
+	  // set transformatino to reference coordinates
+
+	  if (locfaces.Get(1).GetNP() == 3)
+	    {
+	      trans.Set (locpoints.Get(locfaces.Get(1).PNumMod(1+rotind)),
+			 locpoints.Get(locfaces.Get(1).PNumMod(2+rotind)),
+			 locpoints.Get(locfaces.Get(1).PNumMod(3+rotind)), hshould);
+	    }
+	  else
+	    {
+	      trans.Set (locpoints.Get(locfaces.Get(1).PNumMod(1+rotind)),
+			 locpoints.Get(locfaces.Get(1).PNumMod(2+rotind)),
+			 locpoints.Get(locfaces.Get(1).PNumMod(4+rotind)), hshould);
+	    }
+
+	  trans.ToPlain (locpoints, plainpoints);
+
+
+	  for (i = 1; i <= allowpoint.Size(); i++)
+	    {
+	      if (plainpoints.Get(i).Z() > 0)
+		{
+		  //if(loktestmode)
+		  //  (*testout) << "plainpoints.Get(i).Z() = " << plainpoints.Get(i).Z() << " > 0" << endl;
+		  allowpoint.Elem(i) = 0;
+		}
+	    }
+
+	  stat.cnttrials++;
+
+
+	  if (stat.cnttrials % 100 == 0)
+	    {
+	      (*testout) << "\n";
+	      for (i = 1; i <= canuse.Size(); i++)
+	      {
+		(*testout) << foundmap.Get(i) << "/" 
+			   << canuse.Get(i) << "/"
+			   << ruleused.Get(i) << " map/can/use rule " << rules.Get(i)->Name() << "\n";
+	      }
+	      (*testout) << endl;
+	    }
+
+	  NgProfiler::StartTimer (meshing3_timer_c);	  
+
+	  found = ApplyRules (plainpoints, allowpoint, 
+			      locfaces, locfacesplit, connectedpairs,
+			      locelements, delfaces, 
+			      stat.qualclass, mp.sloppy, rotind, err);
+
+	  if (found >= 0) impossible = 0;
+	  if (found < 0) found = 0;
+
+
+	  NgProfiler::StopTimer (meshing3_timer_c);	  
+
+	  if (!found) loktestmode = 0;
+
+	  NgProfiler::RegionTimer reg2 (meshing3_timer_d);	  
+	  
+	  if (loktestmode)
+	    {
+	      (*testout) << "plainpoints = " << endl << plainpoints << endl;
+	      (*testout) << "Applyrules found " << found << endl;
+	    }
+
+	  if (found) stat.cntsucc++;
+
+	  locpoints.SetSize (plainpoints.Size());
+	  for (i = oldnp+1; i <= plainpoints.Size(); i++)
+	    trans.FromPlain (plainpoints.Elem(i), locpoints.Elem(i));
+	  
+
+
+	  // avoid meshing from large to small mesh-size
+	  if (uselocalh && found && stat.qualclass <= 3)
+	    {
+	      for (i = 1; i <= locelements.Size(); i++)
+		{
+		  Point3d pmin = locpoints.Get(locelements.Get(i).PNum(1));
+		  Point3d pmax = pmin;
+		  for (j = 2; j <= 4; j++)
+		    {
+		      const Point3d & hp = locpoints.Get(locelements.Get(i).PNum(j));
+		      pmin.SetToMin (hp);
+		      pmax.SetToMax (hp);
+		    }
+
+		  if (mesh.GetMinH (pmin, pmax) < 0.4 * hshould / mp.sloppy)
+		    found = 0;
+		}
+	    }
+	  if (found)
+	    {
+	      for (i = 1; i <= locelements.Size(); i++)
+		for (j = 1; j <= 4; j++)
+		  {
+		    const Point3d & hp = locpoints.Get(locelements.Get(i).PNum(j));
+		    if (Dist (hp, pmid) > hinner)
+		      found = 0;
+		  }
+	    }
+
+
+	  if (found)
+	    ruleused.Elem(found)++;
+
+
+	  // plotstat->Plot(stat);
+	  
+	  if (stat.cntelem != plotstat_oldne)
+	    {
+	      plotstat_oldne = stat.cntelem;
+
+	      PrintMessageCR (5, "El: ", stat.cntelem,
+			      //	    << " trials: " << stat.cnttrials
+			      " faces: ", stat.nff,
+			      " vol = ", float(100 * stat.vol / stat.vol0));
+  
+	      multithread.percent = 100 -  100.0 * stat.vol / stat.vol0;
+	    }
+
+
+	  if (found && (!hasfound || err < minerr) )
+	    {
+	      
+	      if (testmode)
+		{
+		  (*testout) << "found is active, 3" << endl;
+		  for (i = 1; i <= plainpoints.Size(); i++)
+		    {
+		      (*testout) << "p";
+		      if (i <= pindex.Size())
+			(*testout) << pindex.Get(i) << ": ";
+		      else
+			(*testout) << "new: ";
+		      (*testout) << plainpoints.Get(i) << endl;
+		    }
+		}
+	      
+	      
+	      
+	      hasfound = found;
+	      minerr = err;
+	      
+	      tempnewpoints.SetSize (0);
+	      for (i = oldnp+1; i <= locpoints.Size(); i++)
+		tempnewpoints.Append (locpoints.Get(i));
+	      
+	      tempnewfaces.SetSize (0);
+	      for (i = oldnf+1; i <= locfaces.Size(); i++)
+		tempnewfaces.Append (locfaces.Get(i));
+	      
+	      tempdelfaces.SetSize (0);
+	      for (i = 1; i <= delfaces.Size(); i++)
+		tempdelfaces.Append (delfaces.Get(i));
+	      
+	      templocelements.SetSize (0);
+	      for (i = 1; i <= locelements.Size(); i++)
+		templocelements.Append (locelements.Get(i));
+
+	      /*
+	      optother =
+		strcmp (problems[found], "other") == 0;
+	      */
+	    }
+	  
+	  locpoints.SetSize (oldnp);
+	  locfaces.SetSize (oldnf);
+	  delfaces.SetSize (0);
+	  locelements.SetSize (0);
+	}
+      
+      
+
+      if (hasfound)
+	{
+
+	  /*
+	  if (optother)
+	    (*testout) << "Other is optimal" << endl;
+
+	  if (minother < minwithoutother)
+	    {
+	      (*testout) << "Other is better, " << minother << " less " << minwithoutother << endl;
+	    }
+	    */
+
+	  for (i = 1; i <= tempnewpoints.Size(); i++)
+	    locpoints.Append (tempnewpoints.Get(i));
+	  for (i = 1; i <= tempnewfaces.Size(); i++)
+	    locfaces.Append (tempnewfaces.Get(i));
+	  for (i = 1; i <= tempdelfaces.Size(); i++)
+	    delfaces.Append (tempdelfaces.Get(i));
+	  for (i = 1; i <= templocelements.Size(); i++)
+	    locelements.Append (templocelements.Get(i));
+
+
+	  if (loktestmode)
+	    {
+	      (*testout) << "apply rule" << endl;
+	      for (i = 1; i <= locpoints.Size(); i++)
+		{
+		  (*testout) << "p";
+		  if (i <= pindex.Size())
+		    (*testout) << pindex.Get(i) << ": ";
+		  else
+		    (*testout) << "new: ";
+		  (*testout) << locpoints.Get(i) << endl;
+		}
+	    }
+
+
+
+	  pindex.SetSize(locpoints.Size());
+
+	  for (i = oldnp+1; i <= locpoints.Size(); i++)
+	    {
+	      globind = mesh.AddPoint (locpoints.Get(i));
+	      pindex.Elem(i) = adfront -> AddPoint (locpoints.Get(i), globind);
+	    }
+
+	  for (i = 1; i <= locelements.Size(); i++)
+	    {
+	      Point3d * hp1, * hp2, * hp3, * hp4;
+	      hp1 = &locpoints.Elem(locelements.Get(i).PNum(1));
+	      hp2 = &locpoints.Elem(locelements.Get(i).PNum(2));
+	      hp3 = &locpoints.Elem(locelements.Get(i).PNum(3));
+	      hp4 = &locpoints.Elem(locelements.Get(i).PNum(4));
+	      
+	      tetvol += (1.0 / 6.0) * ( Cross ( *hp2 - *hp1, *hp3 - *hp1) * (*hp4 - *hp1) );
+
+	      for (j = 1; j <= locelements.Get(i).NP(); j++)
+		locelements.Elem(i).PNum(j) =
+		  adfront -> GetGlobalIndex (pindex.Get(locelements.Get(i).PNum(j)));
+
+	      mesh.AddVolumeElement (locelements.Get(i));
+	      stat.cntelem++;
+	    }
+
+	  for (i = oldnf+1; i <= locfaces.Size(); i++)
+	    {
+	      for (j = 1; j <= locfaces.Get(i).GetNP(); j++)
+		locfaces.Elem(i).PNum(j) = 
+		  pindex.Get(locfaces.Get(i).PNum(j));
+	      // (*testout) << "add face " << locfaces.Get(i) << endl;
+	      adfront->AddFace (locfaces.Get(i));
+	    }
+	  
+	  for (i = 1; i <= delfaces.Size(); i++)
+	    adfront->DeleteFace (findex.Get(delfaces.Get(i)));
+	}
+      else
+	{
+	  adfront->IncrementClass (findex.Get(1));
+	  if (impossible && mp.check_impossible)
+	    {
+	      (*testout) << "skip face since it is impossible" << endl;
+	      for (j = 0; j < 100; j++)
+		adfront->IncrementClass (findex.Get(1));
+	    }
+	}
+
+      locelements.SetSize (0);
+      delpoints.SetSize(0);
+      delfaces.SetSize(0);
+
+      if (stat.qualclass >= mp.giveuptol)
+	break;
+    }
+  
+  PrintMessage (5, "");  // line feed after statistics
+
+  for (i = 1; i <= ruleused.Size(); i++)
+    (*testout) << setw(4) << ruleused.Get(i)
+	       << " times used rule " << rules.Get(i) -> Name() << endl;
+
+
+  if (!mp.baseelnp && adfront->Empty())
+    return MESHING3_OK;
+
+  if (mp.baseelnp && adfront->Empty (mp.baseelnp))
+    return MESHING3_OK;
+
+  if (stat.vol < -1e-15)
+    return MESHING3_NEGVOL;
+
+  return MESHING3_NEGVOL;
+}
+
+
+
+
+enum blocktyp { BLOCKUNDEF, BLOCKINNER, BLOCKBOUND, BLOCKOUTER };
+
+void Meshing3 :: BlockFill (Mesh & mesh, double gh)
+{
+  PrintMessage (3, "Block-filling called (obsolete) ");
+
+  int i, j(0), i1, i2, i3, j1, j2, j3;
+  int n1, n2, n3, n, min1, min2, min3, max1, max2, max3;
+  int changed, filled;
+  double xmin(0), xmax(0), ymin(0), ymax(0), zmin(0), zmax(0);
+  double xminb, xmaxb, yminb, ymaxb, zminb, zmaxb;
+  //double rad = 0.7 * gh;
+  
+  for (i = 1; i <= adfront->GetNP(); i++)
+    {
+      const Point3d & p = adfront->GetPoint(i);
+      if (i == 1)
+	{
+	  xmin = xmax = p.X();
+	  ymin = ymax = p.Y();
+	  zmin = zmax = p.Z();
+	}
+      else
+	{
+	  if (p.X() < xmin) xmin = p.X();
+	  if (p.X() > xmax) xmax = p.X();
+	  if (p.Y() < ymin) ymin = p.Y();
+	  if (p.Y() > ymax) ymax = p.Y();
+	  if (p.Z() < zmin) zmin = p.Z();
+	  if (p.Z() > zmax) zmax = p.Z();
+	}
+    }
+  
+  xmin -= 5 * gh;
+  ymin -= 5 * gh;
+  zmin -= 5 * gh;
+  
+  n1 = int ((xmax-xmin) / gh + 5);
+  n2 = int ((ymax-ymin) / gh + 5);
+  n3 = int ((zmax-zmin) / gh + 5);
+  n = n1 * n2 * n3;
+  
+  PrintMessage (5, "n1 = ", n1, " n2 = ", n2, " n3 = ", n3);
+
+  ARRAY<blocktyp> inner(n);
+  ARRAY<int> pointnr(n), frontpointnr(n);
+
+
+  // initialize inner to 1
+
+  for (i = 1; i <= n; i++)
+    inner.Elem(i) = BLOCKUNDEF;
+
+
+  // set blocks cutting surfaces to 0
+
+  for (i = 1; i <= adfront->GetNF(); i++)
+    {
+      const MiniElement2d & el = adfront->GetFace(i);
+      xminb = xmax; xmaxb = xmin;
+      yminb = ymax; ymaxb = ymin;
+      zminb = zmax; zmaxb = zmin;
+
+      for (j = 1; j <= 3; j++)
+	{
+	  const Point3d & p = adfront->GetPoint (el.PNum(j));
+	  if (p.X() < xminb) xminb = p.X();
+	  if (p.X() > xmaxb) xmaxb = p.X();
+	  if (p.Y() < yminb) yminb = p.Y();
+	  if (p.Y() > ymaxb) ymaxb = p.Y();
+	  if (p.Z() < zminb) zminb = p.Z();
+	  if (p.Z() > zmaxb) zmaxb = p.Z();
+	}
+
+	
+
+      double filldist = 0.2; // globflags.GetNumFlag ("filldist", 0.4);
+      xminb -= filldist * gh;
+      xmaxb += filldist * gh;
+      yminb -= filldist * gh;
+      ymaxb += filldist * gh;
+      zminb -= filldist * gh;
+      zmaxb += filldist * gh;
+
+      min1 = int ((xminb - xmin) / gh) + 1;
+      max1 = int ((xmaxb - xmin) / gh) + 1;
+      min2 = int ((yminb - ymin) / gh) + 1;
+      max2 = int ((ymaxb - ymin) / gh) + 1;
+      min3 = int ((zminb - zmin) / gh) + 1;
+      max3 = int ((zmaxb - zmin) / gh) + 1;
+
+
+      for (i1 = min1; i1 <= max1; i1++)
+	for (i2 = min2; i2 <= max2; i2++)
+	  for (i3 = min3; i3 <= max3; i3++)
+	    inner.Elem(i3 + (i2-1) * n3 + (i1-1) * n2 * n3) = BLOCKBOUND;      
+    }
+
+  
+
+
+  while (1)
+    {
+      int undefi = 0;
+      Point3d undefp;
+
+      for (i1 = 1; i1 <= n1 && !undefi; i1++)
+	for (i2 = 1; i2 <= n2 && !undefi; i2++)
+	  for (i3 = 1; i3 <= n3 && !undefi; i3++)
+	    {
+	      i = i3 + (i2-1) * n3 + (i1-1) * n2 * n3;
+	      if (inner.Elem(i) == BLOCKUNDEF)
+		{
+		  undefi = i;
+		  undefp.X() = xmin + (i1-0.5) * gh;
+		  undefp.Y() = ymin + (i2-0.5) * gh;
+		  undefp.Z() = zmin + (i3-0.5) * gh;
+		}
+	    }
+	      
+      if (!undefi)
+	break;
+
+      //      PrintMessage (5, "Test point: ", undefp);
+      
+      if (adfront -> Inside (undefp))
+	{
+	  //	  (*mycout) << "inner" << endl;
+	  inner.Elem(undefi) = BLOCKINNER;
+	}
+      else
+	{
+	  //	  (*mycout) << "outer" << endl;
+	  inner.Elem(undefi) = BLOCKOUTER;
+	}
+
+      do
+	{
+	  changed = 0;
+	  for (i1 = 1; i1 <= n1; i1++)
+	    for (i2 = 1; i2 <= n2; i2++)
+	      for (i3 = 1; i3 <= n3; i3++)
+		{
+		  i = i3 + (i2-1) * n3 + (i1-1) * n2 * n3;
+
+		  for (int k = 1; k <= 3; k++)
+		    {
+		      switch (k)
+			{
+			case 1: j = i + n2 * n3; break;
+			case 2: j = i + n3; break;
+			case 3: j = i + 1; break;
+			}
+		  
+		      if (j > n1 * n2 * n3) continue;
+
+		      if (inner.Elem(i) == BLOCKOUTER && inner.Elem(j) == BLOCKUNDEF)
+			{
+			  changed = 1;
+			  inner.Elem(j) = BLOCKOUTER;
+			}
+		      if (inner.Elem(j) == BLOCKOUTER && inner.Elem(i) == BLOCKUNDEF)
+			{
+			  changed = 1;
+			  inner.Elem(i) = BLOCKOUTER;
+			}
+		      if (inner.Elem(i) == BLOCKINNER && inner.Elem(j) == BLOCKUNDEF)
+			{
+			  changed = 1;
+			  inner.Elem(j) = BLOCKINNER;
+			}
+		      if (inner.Elem(j) == BLOCKINNER && inner.Elem(i) == BLOCKUNDEF)
+			{
+			  changed = 1;
+			  inner.Elem(i) = BLOCKINNER;
+			}
+		    }
+		}
+	}
+      while (changed); 
+
+    }
+
+
+
+  filled = 0;
+  for (i = 1; i <= n; i++)
+    if (inner.Elem(i) == BLOCKINNER)
+      {
+	filled++;
+      }
+  PrintMessage (5, "Filled blocks: ", filled);
+
+  for (i = 1; i <= n; i++)
+    {
+      pointnr.Elem(i) = 0;
+      frontpointnr.Elem(i) = 0;
+    }
+  
+  for (i1 = 1; i1 <= n1-1; i1++)
+    for (i2 = 1; i2 <= n2-1; i2++)
+      for (i3 = 1; i3 <= n3-1; i3++)
+	{
+	  i = i3 + (i2-1) * n3 + (i1-1) * n2 * n3;
+	  if (inner.Elem(i) == BLOCKINNER)
+	    {
+	      for (j1 = i1; j1 <= i1+1; j1++)
+		for (j2 = i2; j2 <= i2+1; j2++)
+		  for (j3 = i3; j3 <= i3+1; j3++)
+		    {
+		      j = j3 + (j2-1) * n3 + (j1-1) * n2 * n3;
+		      if (pointnr.Get(j) == 0)
+			{
+			  Point3d hp(xmin + (j1-1) * gh, 
+				     ymin + (j2-1) * gh, 
+				     zmin + (j3-1) * gh);
+			  pointnr.Elem(j) = mesh.AddPoint (hp);
+			  frontpointnr.Elem(j) =
+			    AddPoint (hp, pointnr.Elem(j));
+
+			}
+		    }
+	    }
+	}
+
+
+  for (i1 = 2; i1 <= n1-1; i1++)
+    for (i2 = 2; i2 <= n2-1; i2++)
+      for (i3 = 2; i3 <= n3-1; i3++)
+	{
+	  i = i3 + (i2-1) * n3 + (i1-1) * n2 * n3;
+	  if (inner.Elem(i) == BLOCKINNER)
+	    {
+	      int pn[9];
+	      pn[1] = pointnr.Get(i);
+	      pn[2] = pointnr.Get(i+1);
+	      pn[3] = pointnr.Get(i+n3);
+	      pn[4] = pointnr.Get(i+n3+1);
+	      pn[5] = pointnr.Get(i+n2*n3);
+	      pn[6] = pointnr.Get(i+n2*n3+1);
+	      pn[7] = pointnr.Get(i+n2*n3+n3);
+	      pn[8] = pointnr.Get(i+n2*n3+n3+1);
+	      static int elind[][4] =
+	      {
+		{ 1, 8, 2, 4 },
+		{ 1, 8, 4, 3 },
+		{ 1, 8, 3, 7 },
+		{ 1, 8, 7, 5 },
+		{ 1, 8, 5, 6 },
+		{ 1, 8, 6, 2 }
+	      };
+	      for (j = 1; j <= 6; j++)
+		{
+		  Element el(4);
+		  for (int k = 1; k <= 4;  k++)
+		    el.PNum(k) = pn[elind[j-1][k-1]];
+
+		  mesh.AddVolumeElement (el);
+		}
+	    }
+	}
+
+
+
+  for (i1 = 2; i1 <= n1-1; i1++)
+    for (i2 = 2; i2 <= n2-1; i2++)
+      for (i3 = 2; i3 <= n3-1; i3++)
+	{
+	  i = i3 + (i2-1) * n3 + (i1-1) * n2 * n3;
+	  if (inner.Elem(i) == BLOCKINNER)
+	    {    
+	      int pi1(0), pi2(0), pi3(0), pi4(0);
+
+	      int pn1 = frontpointnr.Get(i);
+	      int pn2 = frontpointnr.Get(i+1);
+	      int pn3 = frontpointnr.Get(i+n3);
+	      int pn4 = frontpointnr.Get(i+n3+1);
+	      int pn5 = frontpointnr.Get(i+n2*n3);
+	      int pn6 = frontpointnr.Get(i+n2*n3+1);
+	      int pn7 = frontpointnr.Get(i+n2*n3+n3);
+	      int pn8 = frontpointnr.Get(i+n2*n3+n3+1);
+
+	      for (int k = 1; k <= 6; k++)
+		{
+		  switch (k)
+		    {
+		    case 1: // j3 = i3+1
+		      j = i + 1;
+		      pi1 = pn2;
+		      pi2 = pn6;
+		      pi3 = pn4;
+		      pi4 = pn8;
+		      break;
+		    case 2: // j3 = i3-1
+		      j = i - 1;
+		      pi1 = pn1;
+		      pi2 = pn3;
+		      pi3 = pn5;
+		      pi4 = pn7;
+		      break;
+		    case 3: // j2 = i2+1
+		      j = i + n3;
+		      pi1 = pn3;
+		      pi2 = pn4;
+		      pi3 = pn7;
+		      pi4 = pn8;
+		      break;
+		    case 4: // j2 = i2-1
+		      j = i - n3;
+		      pi1 = pn1;
+		      pi2 = pn5;
+		      pi3 = pn2;
+		      pi4 = pn6;
+		      break;
+		    case 5: // j1 = i1+1
+		      j = i + n3*n2;
+		      pi1 = pn5;
+		      pi2 = pn7;
+		      pi3 = pn6;
+		      pi4 = pn8;
+		      break;
+		    case 6: // j1 = i1-1
+		      j = i - n3*n2;
+		      pi1 = pn1;
+		      pi2 = pn2;
+		      pi3 = pn3;
+		      pi4 = pn4;
+		      break;
+		    }
+
+		  if (inner.Get(j) == BLOCKBOUND)
+		    {
+		      MiniElement2d face;
+		      face.PNum(1) = pi4;
+		      face.PNum(2) = pi1;
+		      face.PNum(3) = pi3;
+		      AddBoundaryElement (face);
+
+		      face.PNum(1) = pi1;
+		      face.PNum(2) = pi4;
+		      face.PNum(3) = pi2;
+		      AddBoundaryElement (face);
+
+		    }
+		}
+	    }
+	}
+}
+
+
+
+static const AdFront3 * locadfront;
+static int TestInner (const Point3d & p)
+{
+  return locadfront->Inside (p);
+}
+static int TestSameSide (const Point3d & p1, const Point3d & p2)
+{
+  return locadfront->SameSide (p1, p2);
+}
+
+
+
+
+void Meshing3 :: BlockFillLocalH (Mesh & mesh, 
+				  const MeshingParameters & mp)
+{
+  int i, j;
+  
+  double filldist = mp.filldist;
+
+  (*testout) << "blockfill local h" << endl;
+  (*testout) << "rel filldist = " << filldist << endl;
+  PrintMessage (3, "blockfill local h");
+
+  /*  
+  (*mycout) << "boxes: " << mesh.LocalHFunction().GetNBoxes() << endl
+	    << "filldist = " << filldist << endl;
+  */
+  ARRAY<Point3d> npoints;
+  
+  adfront -> CreateTrees();
+
+  Point3d mpmin, mpmax;
+  // mesh.GetBox (mpmin, mpmax);
+  bool firstp = 1;
+
+  double maxh = 0;
+  for (i = 1; i <= adfront->GetNF(); i++)
+    {
+      const MiniElement2d & el = adfront->GetFace(i);
+      for (j = 1; j <= 3; j++)
+	{
+	  const Point3d & p1 = adfront->GetPoint (el.PNumMod(j));
+	  const Point3d & p2 = adfront->GetPoint (el.PNumMod(j+1));
+	  double hi = Dist (p1, p2);
+	  if (hi > maxh)
+	    {
+	      maxh = hi;
+	      //(*testout) << "reducing maxh to " << maxh << " because of " << p1 << " and " << p2 << endl;
+	    }
+
+	  if (firstp)
+	    {
+	      mpmin = p1;
+	      mpmax = p1;
+	      firstp = 0;
+	    }
+	  else
+	    {
+	      mpmin.SetToMin  (p1);
+	      mpmax.SetToMax  (p1);
+	    }
+	}
+    }
+
+  Point3d mpc = Center (mpmin, mpmax);
+  double d = max3(mpmax.X()-mpmin.X(), 
+		  mpmax.Y()-mpmin.Y(), 
+		  mpmax.Z()-mpmin.Z()) / 2;
+  mpmin = mpc - Vec3d (d, d, d);
+  mpmax = mpc + Vec3d (d, d, d);
+  Box3d meshbox (mpmin, mpmax);
+
+  LocalH loch2 (mpmin, mpmax, 1);
+
+
+  if (mp.maxh < maxh)
+    {
+      maxh = mp.maxh;
+      //(*testout) << "reducing maxh to " << maxh << " because of mp.maxh" << endl;
+    }
+
+  int changed;
+  do 
+    {
+      mesh.LocalHFunction().ClearFlags();
+
+      for (i = 1; i <= adfront->GetNF(); i++)
+	{
+	  const MiniElement2d & el = adfront->GetFace(i);
+	  Point3d pmin = adfront->GetPoint (el.PNum(1));
+	  Point3d pmax = pmin;
+	  
+	  for (j = 2; j <= 3; j++)
+	    {
+	      const Point3d & p = adfront->GetPoint (el.PNum(j));
+	      pmin.SetToMin (p);
+	      pmax.SetToMax (p);
+	    }
+	  
+
+	  double filld = filldist * Dist (pmin, pmax);
+	  
+	  pmin = pmin - Vec3d (filld, filld, filld);
+	  pmax = pmax + Vec3d (filld, filld, filld);
+	  //	  (*testout) << "cut : " << pmin << " - " << pmax << endl;
+	  mesh.LocalHFunction().CutBoundary (pmin, pmax);
+	}
+
+      locadfront = adfront;
+      mesh.LocalHFunction().FindInnerBoxes (adfront, NULL);
+
+      npoints.SetSize(0);
+      mesh.LocalHFunction().GetInnerPoints (npoints);
+
+      changed = 0;
+      for (i = 1; i <= npoints.Size(); i++)
+	{
+	  if (mesh.LocalHFunction().GetH(npoints.Get(i)) > 1.5 * maxh)
+	    {
+	      mesh.LocalHFunction().SetH (npoints.Get(i), maxh);
+	      changed = 1;
+	    }
+	}
+    }
+  while (changed);
+
+  if (debugparam.slowchecks)
+    (*testout) << "Blockfill with points: " << endl;
+  for (i = 1; i <= npoints.Size(); i++)
+    {
+      if (meshbox.IsIn (npoints.Get(i)))
+	{
+	  int gpnum = mesh.AddPoint (npoints.Get(i));
+	  adfront->AddPoint (npoints.Get(i), gpnum);
+
+	  if (debugparam.slowchecks)
+	    {
+	      (*testout) << npoints.Get(i) << endl;
+	      if (!adfront->Inside(npoints.Get(i)))
+		{
+		  cout << "add outside point" << endl;
+		  (*testout) << "outside" << endl;
+		}
+	    }
+
+	}
+    }
+
+  
+
+  // find outer points
+  
+  loch2.ClearFlags();
+
+  for (i = 1; i <= adfront->GetNF(); i++)
+    {
+      const MiniElement2d & el = adfront->GetFace(i);
+      Point3d pmin = adfront->GetPoint (el.PNum(1));
+      Point3d pmax = pmin;
+      
+      for (j = 2; j <= 3; j++)
+	{
+	  const Point3d & p = adfront->GetPoint (el.PNum(j));
+	  pmin.SetToMin (p);
+	  pmax.SetToMax (p);
+	}
+      
+      loch2.SetH (Center (pmin, pmax), Dist (pmin, pmax));
+    }
+
+  for (i = 1; i <= adfront->GetNF(); i++)
+    {
+      const MiniElement2d & el = adfront->GetFace(i);
+      Point3d pmin = adfront->GetPoint (el.PNum(1));
+      Point3d pmax = pmin;
+      
+      for (j = 2; j <= 3; j++)
+	{
+	  const Point3d & p = adfront->GetPoint (el.PNum(j));
+	  pmin.SetToMin (p);
+	  pmax.SetToMax (p);
+	}
+      
+      double filld = filldist * Dist (pmin, pmax);
+      pmin = pmin - Vec3d (filld, filld, filld);
+      pmax = pmax + Vec3d (filld, filld, filld);
+      loch2.CutBoundary (pmin, pmax);
+    }
+
+  locadfront = adfront;
+  loch2.FindInnerBoxes (adfront, NULL);
+
+  npoints.SetSize(0);
+  loch2.GetOuterPoints (npoints);
+  
+  for (i = 1; i <= npoints.Size(); i++)
+    {
+      if (meshbox.IsIn (npoints.Get(i)))
+	{
+	  int gpnum = mesh.AddPoint (npoints.Get(i));
+	  adfront->AddPoint (npoints.Get(i), gpnum);
+	}
+    }  
+}
+
+}
diff --git a/contrib/Netgen/libsrc/meshing/meshing3.hpp b/contrib/Netgen/libsrc/meshing/meshing3.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..3a4732d1645da300533edf930114f377d820cda1
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/meshing3.hpp
@@ -0,0 +1,130 @@
+#ifndef FILE_MESHING3
+#define FILE_MESHING3
+
+
+
+
+enum MESHING3_RESULT
+{
+  MESHING3_OK = 0,
+  MESHING3_GIVEUP = 1,
+  MESHING3_NEGVOL = 2,
+  MESHING3_OUTERSTEPSEXCEEDED = 3,
+  MESHING3_TERMINATE = 4,
+  MESHING3_BADSURFACEMESH = 5
+};
+
+
+/// 3d volume mesh generation
+class Meshing3
+{
+  /// current state of front
+  AdFront3 * adfront;
+  /// 3d generation rules
+  ARRAY<vnetrule*> rules;
+  /// counts how often a rule is used
+  ARRAY<int> ruleused, canuse, foundmap;
+  /// describes, why a rule is not applied
+  ARRAY<char*> problems;
+  /// tolerance criterion
+  double tolfak;
+public:
+  /// 
+  Meshing3 (const string & rulefilename); 
+  /// 
+  Meshing3 (const char ** rulep);
+  ///
+  virtual ~Meshing3 ();
+  
+  ///
+  void LoadRules (const char * filename, const char ** prules);
+  ///
+  MESHING3_RESULT GenerateMesh (Mesh & mesh, const MeshingParameters & mp);
+  
+  ///
+  int ApplyRules (ARRAY<Point3d> & lpoints, ARRAY<int> & allowpoint,
+		  ARRAY<MiniElement2d> & lfaces, INDEX lfacesplit,
+		  INDEX_2_HASHTABLE<int> & connectedpairs,
+		  ARRAY<Element> & elements,
+		  ARRAY<INDEX> & delfaces, int tolerance, 
+		  double sloppy, int rotind1,
+		  float & retminerr);
+  
+  ///
+  PointIndex AddPoint (const Point3d & p, PointIndex globind);
+  ///
+  void AddBoundaryElement (const Element2d & elem);
+  ///
+  void AddBoundaryElement (const MiniElement2d & elem);
+  ///
+  int AddConnectedPair (const INDEX_2 & pair);
+  
+  ///
+  void BlockFill (Mesh & mesh, double gh);
+  ///
+  void BlockFillLocalH (Mesh & mesh, const MeshingParameters & mp);
+
+  /// uses points of adfront, and puts new elements into mesh
+  void Delaunay (Mesh & mesh, int domainnr, const MeshingParameters & mp);
+  ///
+  friend class PlotVolMesh;
+  ///
+  friend void TestRules ();
+};
+
+
+
+
+/// status of mesh generation
+class MeshingStat3d
+{
+public:
+  ///
+  MeshingStat3d ();
+  ///
+  int cntsucc;
+  ///
+  int cnttrials;
+  ///
+  int cntelem;
+  ///
+  int nff;
+  ///
+  int qualclass;
+  ///
+  double vol0;
+  ///
+  double vol;
+  ///
+  double h;
+  ///
+  int problemindex;
+};
+
+
+
+
+
+/*
+template <typename POINTARRAY, typename FACEARRAY>
+extern int FindInnerPoint (POINTARRAY & grouppoints,
+			   FACEARRAY & groupfaces,
+			   Point3d & p);
+
+*/
+
+
+
+
+
+#endif
+
+
+
+
+
+
+
+
+
+
diff --git a/contrib/Netgen/libsrc/meshing/meshtool.cpp b/contrib/Netgen/libsrc/meshing/meshtool.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..386e2bec0523819539bd77e07487ebbcf05f2c50
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/meshtool.cpp
@@ -0,0 +1,999 @@
+#include <mystdlib.h>
+
+#include "meshing.hpp"
+//#include <csg.hpp> // MODIFIED FOR GMSH
+//#include <geometry2d.hpp>// MODIFIED FOR GMSH
+
+namespace netgen
+{
+
+  int CheckSurfaceMesh (const Mesh & mesh)
+  {
+    PrintMessage (3, "Check Surface mesh");
+
+    int nf = mesh.GetNSE();
+    INDEX_2_HASHTABLE<int> edges(nf+2);
+    int i, j;
+    INDEX_2 i2;
+    int cnt1 = 0, cnt2 = 0;
+
+    for (i = 1; i <= nf; i++)
+      for (j = 1; j <= 3; j++)
+	{
+	  i2.I1() = mesh.SurfaceElement(i).PNumMod(j);
+	  i2.I2() = mesh.SurfaceElement(i).PNumMod(j+1);
+	  if (edges.Used(i2))
+	    {
+	      int hi;
+	      hi = edges.Get(i2);
+	      if (hi != 1) 
+		PrintSysError ("CheckSurfaceMesh, hi = ", hi);
+	      edges.Set(i2, 2);
+	      cnt2++;
+	    }
+	  else
+	    {
+	      Swap (i2.I1(), i2.I2());
+	      edges.Set(i2, 1);
+	      cnt1++;
+	    }
+	}
+  
+
+    if (cnt1 != cnt2)
+      {
+	PrintUserError ("Surface mesh not consistent");
+	//      MyBeep(2);
+	//      (*mycout) << "cnt1 = " << cnt1 << " cnt2 = " << cnt2 << endl;
+	return 0;
+      }
+    return 1;
+  }
+
+
+
+  int CheckSurfaceMesh2 (const Mesh & mesh)
+  {
+    int i, j, k;
+    const Point<3> *tri1[3], *tri2[3];
+
+    for (i = 1; i <= mesh.GetNOpenElements(); i++)
+      {
+	PrintDot ();
+	for (j = 1; j < i; j++)
+	  {
+	    for (k = 1; k <= 3; k++)
+	      {
+		tri1[k-1] = &mesh.Point (mesh.OpenElement(i).PNum(k));
+		tri2[k-1] = &mesh.Point (mesh.OpenElement(j).PNum(k));
+	      }
+	    if (IntersectTriangleTriangle (&tri1[0], &tri2[0]))
+	      {
+		PrintSysError ("Surface elements are intersecting");
+		(*testout) << "Intersecting: " << endl;
+		for (k = 0; k <= 2; k++)
+		  (*testout) << *tri1[k] << "   ";
+		(*testout) << endl;
+		for (k = 0; k <= 2; k++)
+		  (*testout) << *tri2[k] << "   ";
+		(*testout) << endl;
+	      }
+
+	  }
+      }
+    return 0;
+  }
+
+
+
+
+
+  static double TriangleQualityInst (const Point3d & p1, const Point3d & p2,
+				     const Point3d & p3)
+  {
+    // quality 0 (worst) .. 1 (optimal)
+
+    Vec3d v1, v2, v3;
+    double s1, s2, s3;
+    double an1, an2, an3;
+
+    v1 = p2 - p1;
+    v2 = p3 - p1;
+    v3 = p3 - p2;
+
+    an1 = Angle (v1, v2);
+    v1 *= -1;
+    an2 = Angle (v1, v3);
+    an3 = Angle (v2, v3);
+
+    s1 = sin (an1/2);
+    s2 = sin (an2/2);
+    s3 = sin (an3/2);
+
+    return 8 * s1 * s2 * s3;
+  }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+  void MeshQuality2d (const Mesh & mesh)
+  {
+    int ncl = 20, cl;
+    ARRAY<INDEX> incl(ncl);
+    INDEX i;
+    SurfaceElementIndex sei;
+    double qual;
+
+    incl = 0;
+
+    for (sei = 0; sei < mesh.GetNSE(); sei++)
+      {
+	qual = TriangleQualityInst (mesh[mesh[sei][0]],
+				    mesh[mesh[sei][1]],
+				    mesh[mesh[sei][2]]);
+
+	cl = int ( (ncl-1e-3) * qual ) + 1;
+	incl.Elem(cl)++;
+      }
+
+    (*testout) << endl << endl;
+
+    (*testout) << "Points:           " << mesh.GetNP() << endl;
+    (*testout) << "Surface Elements: " << mesh.GetNSE() << endl;
+
+    (*testout) << endl;
+    (*testout) << "Elements in qualityclasses:" << endl;
+    (*testout).precision(2);
+    for (i = 1; i <= ncl; i++)
+      {
+	(*testout) << setw(4) << double (i-1)/ncl << " - "
+		   << setw(4) << double (i) / ncl << ": "
+		   << incl.Get(i) << endl;
+      }
+  }
+
+
+  static double TetElementQuality (const Point3d & p1, const Point3d & p2,
+				   const Point3d & p3, const Point3d & p4)
+  {
+    double vol, l, l4, l5, l6;
+
+
+    Vec3d v1 = p2 - p1;
+    Vec3d v2 = p3 - p1;
+    Vec3d v3 = p4 - p1;
+
+    vol = fabs ((Cross (v1, v2) * v3)) / 6;
+    l4 = Dist (p2, p3);
+    l5 = Dist (p2, p4);
+    l6 = Dist (p3, p4);
+
+    l = v1.Length() + v2.Length() + v3.Length() + l4 + l5 + l6;
+
+    if (vol <= 1e-8 * l * l * l) return 1e-10;
+
+    return vol/(l*l*l) * 1832.82;    // 6^4 * sqrt(2)
+  }
+
+
+
+
+
+  double teterrpow = 2;
+
+  double CalcTetBadness (const Point3d & p1, const Point3d & p2,
+			 const Point3d & p3, const Point3d & p4, double h)
+  {
+    double vol, l, ll, lll, ll1, ll2, ll3, ll4, ll5, ll6;
+    double err;
+
+    Vec3d v1 (p1, p2);
+    Vec3d v2 (p1, p3);
+    Vec3d v3 (p1, p4);
+
+    vol = -Determinant (v1, v2, v3) / 6;
+
+    ll1 = v1.Length2();
+    ll2 = v2.Length2();
+    ll3 = v3.Length2();
+    ll4 = Dist2 (p2, p3);
+    ll5 = Dist2 (p2, p4);
+    ll6 = Dist2 (p3, p4);
+
+    ll = ll1 + ll2 + ll3 + ll4 + ll5 + ll6;
+    l = sqrt (ll);
+    lll = l * ll;
+
+    if (vol <= 1e-24 * lll)
+      return 1e24;
+
+    err = 0.0080187537 * lll / vol;    // sqrt(216) / (6^4 * sqrt(2))
+
+    if (h > 0)
+      err += ll / (h * h) + 
+	h * h * ( 1 / ll1 + 1 / ll2 + 1 / ll3 + 
+		  1 / ll4 + 1 / ll5 + 1 / ll6 ) - 12;
+    
+    if (teterrpow == 2)
+      return err*err;
+    return pow (err, teterrpow);
+  }
+
+
+  double CalcTetBadnessGrad (const Point3d & p1, const Point3d & p2,
+			     const Point3d & p3, const Point3d & p4, double h,
+			     int pi, Vec<3> & grad)
+  {
+    double vol, l, ll, lll;
+    double err;
+
+    const Point3d *pp1, *pp2, *pp3, *pp4;
+
+    pp1 = &p1;
+    pp2 = &p2;
+    pp3 = &p3;
+    pp4 = &p4;
+  
+    switch (pi)
+      {
+      case 2:
+	{
+	  swap (pp1, pp2);
+	  swap (pp3, pp4);
+	  break;
+	}
+      case 3:
+	{
+	  swap (pp1, pp3);
+	  swap (pp2, pp4);
+	  break;
+	}
+      case 4:
+	{
+	  swap (pp1, pp4);
+	  swap (pp3, pp2);
+	  break;
+	}
+      }
+  
+
+    Vec3d v1 (*pp1, *pp2);
+    Vec3d v2 (*pp1, *pp3);
+    Vec3d v3 (*pp1, *pp4);
+
+    Vec3d v4 (*pp2, *pp3);
+    Vec3d v5 (*pp2, *pp4);
+    Vec3d v6 (*pp3, *pp4);
+
+    vol = -Determinant (v1, v2, v3) / 6;  
+
+    Vec3d gradvol;
+    Cross (v5, v4, gradvol);
+    gradvol *= (-1.0/6.0);
+
+
+    double ll1 = v1.Length2();
+    double ll2 = v2.Length2();
+    double ll3 = v3.Length2();
+    double ll4 = v4.Length2();
+    double ll5 = v5.Length2();
+    double ll6 = v6.Length2();
+
+    ll = ll1 + ll2 + ll3 + ll4 + ll5 + ll6;
+    l = sqrt (ll);
+    lll = l * ll;
+
+    if (vol <= 1e-24 * lll)
+      { 
+	grad = Vec3d (0, 0, 0);
+	return 1e24;
+      }
+
+
+
+    Vec3d gradll1 (*pp2, *pp1);
+    Vec3d gradll2 (*pp3, *pp1);
+    Vec3d gradll3 (*pp4, *pp1);
+    gradll1 *= 2;
+    gradll2 *= 2;
+    gradll3 *= 2;
+
+    Vec3d gradll (gradll1);
+    gradll += gradll2;
+    gradll += gradll3;
+
+    /*
+    Vec3d gradll;
+    gradll = v1+v2+v3;
+    gradll *= -2;
+    */
+
+    err = 0.0080187537 * lll / vol; 
+
+
+    gradll *= (0.0080187537 * 1.5 * l / vol);
+    Vec3d graderr(gradll);
+    gradvol *= ( -0.0080187537 * lll / (vol * vol) );
+    graderr += gradvol;
+  
+    if (h > 0)
+      {
+	/*
+	Vec3d gradll1 (*pp2, *pp1);
+	Vec3d gradll2 (*pp3, *pp1);
+	Vec3d gradll3 (*pp4, *pp1);
+	gradll1 *= 2;
+	gradll2 *= 2;
+	gradll3 *= 2;
+	*/
+	err += ll / (h*h) + 
+	  h*h * ( 1 / ll1 + 1 / ll2 + 1 / ll3 + 
+		  1 / ll4 + 1 / ll5 + 1 / ll6 ) - 12;
+
+	graderr += (1/(h*h) - h*h/(ll1*ll1)) * gradll1;
+	graderr += (1/(h*h) - h*h/(ll2*ll2)) * gradll2;
+	graderr += (1/(h*h) - h*h/(ll3*ll3)) * gradll3;
+	cout << "?";
+      }
+
+
+    double errpow;
+    if (teterrpow == 2)
+      {
+        errpow = err*err;   
+        grad = (2 * err) * graderr;
+      }
+    else
+      {
+        errpow = pow (err, teterrpow);
+        grad = (teterrpow * errpow / err) * graderr;
+      }
+    return errpow;
+  }
+  
+
+
+
+
+  /*
+
+  double CalcTetBadness (const Point3d & p1, const Point3d & p2,
+  const Point3d & p3, const Point3d & p4, double h)
+  {
+  double vol, l;
+  double err;
+
+
+  Vec3d v1 (p1, p2);
+  Vec3d v2 (p1, p3);
+  Vec3d v3 (p1, p4);
+
+  vol = -Determinant (v1, v2, v3) / 6;
+
+  double l1 = v1.Length();
+  double l2 = v2.Length();
+  double l3 = v3.Length();
+  double l4 = Dist (p2, p3);
+  double l5 = Dist (p2, p4);
+  double l6 = Dist (p3, p4);
+
+  l = l1 + l2 + l3 + l4 + l5 + l6;
+
+  // just for timing
+  // l += 1e-40 * CalcTetBadnessNew (p1, p2, p3, p4, h);
+
+  if (vol <= 1e-24 * l * l * l)
+  { 
+  return 1e24;
+  }
+
+  err = (l*l*l) / (1832.82 * vol);    // 6^4 * sqrt(2)
+  
+  if (h > 0)
+  err += l / h + 
+  h * (1 / l1 + 1/l2 + 1/l3 + 1/l4 + 1/l5 + 1/l6) - 12;
+
+  return pow (err, teterrpow);
+  }
+
+
+  
+  double CalcTetBadnessGrad (const Point3d & p1, const Point3d & p2,
+  const Point3d & p3, const Point3d & p4, double h,
+  int pi, Vec3d & grad)
+  {
+  double vol, l;
+  double err;
+
+  const Point3d *pp1, *pp2, *pp3, *pp4;
+
+  pp1 = &p1;
+  pp2 = &p2;
+  pp3 = &p3;
+  pp4 = &p4;
+  
+  switch (pi)
+  {
+  case 2:
+  {
+  swap (pp1, pp2);
+  swap (pp3, pp4);
+  break;
+  }
+  case 3:
+  {
+  swap (pp1, pp3);
+  swap (pp2, pp4);
+  break;
+  }
+  case 4:
+  {
+  swap (pp1, pp4);
+  swap (pp3, pp2);
+  break;
+  }
+  }
+  
+
+  Vec3d v1 (*pp1, *pp2);
+  Vec3d v2 (*pp1, *pp3);
+  Vec3d v3 (*pp1, *pp4);
+
+  Vec3d v4 (*pp2, *pp3);
+  Vec3d v5 (*pp2, *pp4);
+  Vec3d v6 (*pp3, *pp4);
+
+
+  //   Vec3d n;
+  //   Cross (v1, v2, n);
+  //   vol = - (n * v3) / 6;
+
+
+  vol = -Determinant (v1, v2, v3) / 6;  
+
+  Vec3d gradvol;
+  Cross (v5, v4, gradvol);
+  gradvol *= (-1.0/6.0);
+
+
+  double l1 = v1.Length();
+  double l2 = v2.Length();
+  double l3 = v3.Length();
+  double l4 = v4.Length();
+  double l5 = v5.Length();
+  double l6 = v6.Length();
+
+  l = l1 + l2 + l3 +l4 + l5 + l6;
+
+  Vec3d gradl1 (*pp2, *pp1);
+  Vec3d gradl2 (*pp3, *pp1);
+  Vec3d gradl3 (*pp4, *pp1);
+  gradl1 /= l1;
+  gradl2 /= l2;
+  gradl3 /= l3;
+
+  Vec3d gradl (gradl1);
+  gradl += gradl2;
+  gradl += gradl3;
+
+
+  if (vol <= 1e-24 * l * l * l)
+  { 
+  grad = Vec3d (0, 0, 0);
+  return 1e24;
+  }
+
+
+  double c1 = 1.0 / 1832.82;      // 6^4 * sqrt(2)
+  err = c1 * (l*l*l) / vol; 
+
+
+  gradl *= (c1 * 3 * l * l / vol);
+  Vec3d graderr(gradl);
+  gradvol *= ( -c1 * l * l * l / (vol * vol) );
+  graderr+= gradvol;
+  
+  if (h > 0)
+  {
+  err += l / h + 
+  h * ( 1 / l1 + 1 / l2 + 1 / l3 + 
+  1 / l4 + 1 / l5 + 1 / l6 ) - 12;
+
+  graderr += (1/h - h/(l1*l1)) * gradl1;
+  graderr += (1/h - h/(l2*l2)) * gradl2;
+  graderr += (1/h - h/(l3*l3)) * gradl3;
+  cout << "?";
+  }
+
+  double errpow = pow (err, teterrpow);
+  grad = (teterrpow * errpow / err) * graderr;
+  
+  return errpow;
+  }
+  
+  */
+
+
+
+
+  
+  /*
+    double CalcVolume (const ARRAY<Point3d> & points,
+    const Element & el)
+    {
+    Vec3d v1 = points.Get(el.PNum(2)) - 
+    points.Get(el.PNum(1));
+    Vec3d v2 = points.Get(el.PNum(3)) - 
+    points.Get(el.PNum(1));
+    Vec3d v3 = points.Get(el.PNum(4)) - 
+    points.Get(el.PNum(1)); 
+         
+    return -(Cross (v1, v2) * v3) / 6;	 
+    }  
+  */
+
+  double CalcVolume (const ARRAY<Point3d> & points, 
+		     const ARRAY<Element> & elements)
+  {
+    double vol;
+    Vec3d v1, v2, v3;
+  
+    vol = 0;
+    for (int i = 0; i < elements.Size(); i++)
+      {
+	v1 = points.Get(elements[i][1]) - points.Get(elements[i][0]);
+	v2 = points.Get(elements[i][2]) - points.Get(elements[i][0]);
+	v3 = points.Get(elements[i][3]) - points.Get(elements[i][0]);
+	vol -= (Cross (v1, v2) * v3) / 6;	 
+      }
+    return vol;
+  }
+
+  
+  
+
+  void MeshQuality3d (const Mesh & mesh, ARRAY<int> * inclass)
+  { 
+    int ncl = 20;
+    signed int cl;
+    ARRAY<INDEX> incl(ncl);
+    INDEX i;
+    double qual;
+    double sum = 0;
+    int nontet  = 0;
+
+    for (i = 1; i <= incl.Size(); i++)
+      incl.Elem(i) = 0;
+
+    for (ElementIndex ei = 0; ei < mesh.GetNE(); ei++)
+      {
+	if (mesh[ei].GetType() != TET)
+	  {
+	    nontet++;
+	    continue;
+	  }
+
+	qual = TetElementQuality (mesh.Point(mesh[ei][0]),
+				  mesh.Point(mesh[ei][1]),
+				  mesh.Point(mesh[ei][2]),
+				  mesh.Point(mesh[ei][3]));
+
+	if (qual > 1) qual = 1;
+	cl = int (ncl * qual ) + 1;
+     
+	if (cl < 1) cl = 1; 
+	if (cl > ncl) cl = ncl;
+
+	incl.Elem(cl)++;
+	if (inclass) (*inclass)[ei] = cl;
+	sum += 1/qual;
+      }
+
+    (*testout) << endl << endl;
+    (*testout) << "Points:           " << mesh.GetNP() << endl;
+    (*testout) << "Volume Elements:  " << mesh.GetNE() << endl;
+    if (nontet)
+      (*testout) << nontet << " non tetrahedral elements" << endl;
+    (*testout) << endl;
+
+    (*testout) << "Volume elements in qualityclasses:" << endl;
+    (*testout).precision(2);
+    for (i = 1; i <= ncl; i++)
+      {
+	(*testout) << setw(4) << double (i-1)/ncl << " - "
+		   << setw(4) << double (i) / ncl << ": "
+		   << incl.Get(i) << endl;
+      }
+    (*testout) << "total error: " << sum << endl;
+  }
+
+
+  void SaveEdges (const Mesh & mesh, const char * geomfile, double h, char * filename)
+  {
+    ofstream of (filename);
+    int i;
+    const Segment * seg;
+  
+    of << "edges" << endl;
+    of << geomfile << endl;
+    of << h << endl;
+
+    of << mesh.GetNP() << endl;
+    for (i = 1; i <= mesh.GetNP(); i++)
+      of << mesh.Point(i)(0) << " "
+	 << mesh.Point(i)(1) << " "
+	 << mesh.Point(i)(2) << "\n";
+    
+    of << 2 * mesh.GetNSeg() << endl;
+    for (i = 1; i <= mesh.GetNSeg(); i++)
+      {
+	seg = &mesh.LineSegment(i);
+
+	of << seg->p2 << " " << seg->p1 << " " << seg->si << "\n";
+      }
+   
+  }
+
+
+  void SaveSurfaceMesh (const Mesh & mesh,
+			double h,
+			char * filename)
+
+  {
+    INDEX i;
+
+    ofstream outfile(filename);
+
+    outfile << "surfacemesh" << endl;
+    outfile << h << endl;
+
+    outfile << mesh.GetNP() << endl;
+    for (i = 1; i <= mesh.GetNP(); i++)
+      outfile << mesh.Point(i)(0) << " "
+	      << mesh.Point(i)(1) << " "
+	      << mesh.Point(i)(2) << endl;
+
+  
+
+    outfile << mesh.GetNSE() << endl;
+    for (i = 1; i <= mesh.GetNSE(); i++)
+      {
+	const Element2d & el = mesh.SurfaceElement(i);
+
+	if (mesh.GetFaceDescriptor(el.GetIndex()).DomainOut() == 0)
+	  outfile << mesh.SurfaceElement(i).PNum(1) << " "
+		  << mesh.SurfaceElement(i).PNum(2) << " "
+		  << mesh.SurfaceElement(i).PNum(3) << endl;
+	if (mesh.GetFaceDescriptor(el.GetIndex()).DomainIn() == 0)
+	  outfile << mesh.SurfaceElement(i).PNum(1) << " "
+		  << mesh.SurfaceElement(i).PNum(3) << " "
+		  << mesh.SurfaceElement(i).PNum(2) << endl;
+      }
+  }
+
+
+#ifdef OLD
+  void Save2DMesh (
+		   const Mesh & mesh2d,
+		   const ARRAY<SplineSegment *> * splines,
+		   ostream & outfile)
+
+  {
+    int i, j;
+    outfile.precision (6);
+  
+    outfile << "areamesh2" << endl;
+
+
+    outfile << endl;
+    outfile << mesh2d.GetNSeg() << endl;
+    for (i = 1; i <= mesh2d.GetNSeg(); i++)
+      outfile << mesh2d.LineSegment(i).si << "        "
+	      << mesh2d.LineSegment(i).p1 << " "
+	      << mesh2d.LineSegment(i).p2 << "  " << endl;
+  
+
+    outfile << mesh2d.GetNSE() << endl;
+    for (i = 1; i <= mesh2d.GetNSE(); i++)
+      {
+	outfile << mesh2d.SurfaceElement(i).GetIndex() << "         ";
+	outfile << mesh2d.SurfaceElement(i).GetNP() << " ";
+	for (j = 1; j <= mesh2d.SurfaceElement(i).GetNP(); j++)
+	  outfile << mesh2d.SurfaceElement(i).PNum(j) << " ";
+	outfile << endl;
+      }
+
+    outfile << mesh2d.GetNP() << endl;
+    for (i = 1; i <= mesh2d.GetNP(); i++)
+      outfile << mesh2d.Point(i).X() << " "
+	      << mesh2d.Point(i).Y() << endl;
+
+    if (splines)
+      {
+	outfile << splines->Size() << endl;
+	for (i = 1; i <= splines->Size(); i++)
+	  splines->Get(i) -> PrintCoeff (outfile);
+      }
+    else
+      outfile << "0" << endl;
+  }
+#endif
+
+
+
+
+
+
+  void SaveVolumeMesh (const Mesh & mesh, 
+		       const CSGeometry & geometry,
+		       char * filename)
+  {
+    INDEX i;
+
+    ofstream outfile(filename);
+    outfile << "volumemesh" << endl;
+
+    outfile << mesh.GetNSE() << endl;
+    for (i = 1; i <= mesh.GetNSE(); i++)
+      {
+	if (mesh.SurfaceElement(i).GetIndex())
+	  outfile << mesh.GetFaceDescriptor(mesh.SurfaceElement(i).GetIndex ()).SurfNr()
+		  << "\t";
+	else
+	  outfile << "0" << "\t";
+	outfile << mesh.SurfaceElement(i)[0] << " "
+		<< mesh.SurfaceElement(i)[1] << " "
+		<< mesh.SurfaceElement(i)[2] << endl;
+      }
+    outfile << mesh.GetNE() << endl;
+    for (ElementIndex ei = 0; ei < mesh.GetNE(); ei++)
+      outfile << mesh[ei].GetIndex() << "\t"
+	      << mesh[ei][0] << " " << mesh[ei][1] << " "
+	      << mesh[ei][2] << " " << mesh[ei][3] << endl;
+
+    outfile << mesh.GetNP() << endl;
+    for (i = 1; i <= mesh.GetNP(); i++)
+      outfile << mesh.Point(i)(0) << " "
+	      << mesh.Point(i)(1) << " "
+	      << mesh.Point(i)(2) << endl;
+
+#ifdef SOLIDGEOM
+    outfile << geometry.GetNSurf() << endl;
+    for (i = 1; i <= geometry.GetNSurf(); i++)
+      geometry.GetSurface(i) -> Print (outfile);
+#endif
+  }
+
+
+
+  int CheckCode ()
+  {
+    return 1;
+
+    /*
+      char st[100];
+      ifstream ist("pw");
+
+      if (!ist.good()) return 0;
+      ist >> st;
+      if (strcmp (st, "JKULinz") == 0) return 1;
+      return 0;
+    */
+  }
+
+
+
+  /* ******************** CheckMesh ******************************* */
+
+  /// Checks, whether mesh contains a valid 3d mesh
+  int CheckMesh3D (const Mesh & mesh)
+  {
+    INDEX_3_HASHTABLE<int> faceused(mesh.GetNE()/3);
+    INDEX i;
+    int j, k, l;
+    INDEX_3 i3;
+    int ok = 1;
+    ElementIndex ei;
+
+    for (i = 1; i <= mesh.GetNSE(); i++)
+      {
+	const Element2d & el = mesh.SurfaceElement(i);
+      
+	if (mesh.GetFaceDescriptor(el.GetIndex()).DomainIn() == 0 ||
+	    mesh.GetFaceDescriptor(el.GetIndex()).DomainOut() == 0)
+	  {
+	    for (j = 1; j <= 3; j++)
+	      i3.I(j) = el.PNum(j);
+	  
+	    i3.Sort();
+	    faceused.Set (i3, 1);
+	  }
+      }
+  
+    for (ei = 0; ei < mesh.GetNE(); ei++)
+      {
+	const Element & el = mesh[ei];
+
+	for (j = 1; j <= 4; j++)
+	  {
+	    l = 0;
+	    for (k = 1; k <= 4; k++)
+	      {
+		if (j != k)
+		  {
+		    l++;
+		    i3.I(l) = el.PNum(k);
+		  }
+	      }
+
+	    i3.Sort();
+	    if (faceused.Used(i3))
+	      faceused.Set(i3, faceused.Get(i3)+1);
+	    else
+	      faceused.Set (i3, 1);
+	  }
+      }
+
+
+    for (i = 1; i <= mesh.GetNSE(); i++)
+      {
+	const Element2d & el = mesh.SurfaceElement(i);
+
+	for (j = 1; j <= 3; j++)
+	  i3.I(j) = el.PNum(j);
+      
+	i3.Sort();
+	k = faceused.Get (i3);
+	if (k != 2)
+	  {
+	    ok = 0;
+	    (*testout) << "face " << i << " with points " 
+		       << i3.I1() << "-" << i3.I2() << "-" << i3.I3() 
+		       << " has " << k << " elements" << endl;
+	  }
+      }
+  
+    for (ei = 0; ei < mesh.GetNE(); ei++)
+      {
+	const Element & el = mesh[ei];
+
+	for (j = 1; j <= 4; j++)
+	  {
+	    l = 0;
+	    for (k = 1; k <= 4; k++)
+	      {
+		if (j != k)
+		  {
+		    l++;
+		    i3.I(l) = el.PNum(k);
+		  }
+	      }
+
+	    i3.Sort();
+	    k = faceused.Get(i3);
+	    if (k != 2)
+	      {
+		ok = 0;
+		(*testout) << "element " << ei << " with face " 
+			   << i3.I1() << "-" << i3.I2() << "-"
+			   << i3.I3() 
+			   << " has " << k << " elements" << endl;
+	      }
+	  }
+      }
+
+
+
+
+
+    /*
+      for (i = 1; i <= faceused.GetNBags(); i++)
+      for (j = 1; j <= faceused.GetBagSize(i); j++)
+      {
+      faceused.GetData(i, j, i3, k);
+      if (k != 2)
+      {
+      (*testout) << "Face: " << i3.I1() << "-" 
+      << i3.I2() << "-" << i3.I3() << " has " 
+      << k << " Faces " << endl;
+      cerr << "Face Error" << endl;
+      ok = 0;
+      }
+      }
+    */
+
+
+    if (!ok)
+      {
+	(*testout) << "surfelements: " << endl;
+	for (i = 1; i <= mesh.GetNSE(); i++)
+	  {
+	    const Element2d & el = mesh.SurfaceElement(i);
+	    (*testout) << setw(5) << i << ":" 
+		       << setw(6) << el.GetIndex() 
+		       << setw(6) << el.PNum(1) 
+		       << setw(4) << el.PNum(2) 
+		       << setw(4) << el.PNum(3)  << endl;
+	  }
+	(*testout) << "volelements: " << endl;
+	for (ei = 0; ei < mesh.GetNE(); ei++)
+	  {
+	    const Element & el = mesh[ei];
+	    (*testout) << setw(5) << i << ":" 
+		       << setw(6) << el.GetIndex() 
+		       << setw(6) << el[0] << setw(4) << el[1]
+		       << setw(4) << el[2] << setw(4) << el[3] << endl;
+	  }
+      }
+
+
+    return ok;
+  }
+
+
+
+  void RemoveProblem (Mesh & mesh, int domainnr)
+  {
+    int i, j, k;
+  
+    mesh.FindOpenElements(domainnr);
+    int np = mesh.GetNP();
+
+    BitArrayChar<PointIndex::BASE> ppoints(np);
+  
+    // int ndom = mesh.GetNDomains();
+
+    PrintMessage (3, "Elements before Remove: ", mesh.GetNE());
+    // for (k = 1; k <= ndom; k++)
+    k = domainnr;
+      {
+	ppoints.Clear();
+      
+	for (i = 1; i <= mesh.GetNOpenElements(); i++)
+	  {
+	    const Element2d & sel = mesh.OpenElement(i);
+	    if (sel.GetIndex() == k)
+	      {
+		for (j = 1; j <= sel.GetNP(); j++)
+		  ppoints.Set (sel.PNum(j));
+	      }
+	  }
+
+	for (ElementIndex ei = 0; ei < mesh.GetNE(); ei++)
+	  {
+	    const Element & el = mesh[ei];
+	    if (el.GetIndex() == k)
+	      {
+		int todel = 0;
+		for (j = 0; j < el.GetNP(); j++)
+		  if (ppoints.Test (el[j]))
+		    todel = 1;
+	      
+		if (el.GetNP() != 4)
+		  todel = 0;
+	      
+		if (todel)
+		  {
+		    mesh[ei].Delete();
+		    // ei--;
+		  }
+	      }
+	  }
+      }
+  
+    mesh.Compress();
+    PrintMessage (3, "Elements after Remove: ", mesh.GetNE());
+  }
+
+
+}
diff --git a/contrib/Netgen/libsrc/meshing/meshtool.hpp b/contrib/Netgen/libsrc/meshing/meshtool.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..9ffaad113cad58bf9f4c3f5926758b992b2f2376
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/meshtool.hpp
@@ -0,0 +1,83 @@
+#ifndef FILE_MESHTOOL
+#define FILE_MESHTOOL
+
+
+///
+extern void MeshQuality2d (const Mesh & mesh);
+
+///
+extern void MeshQuality3d (const Mesh & mesh,
+			   ARRAY<int> * inclass = NULL);
+
+///
+extern void SaveEdges (const Mesh & mesh, 
+		       const char * geomfile, 
+		       double h, 
+		       char * filename);
+
+///
+extern void SaveSurfaceMesh (const Mesh & mesh,
+			     double h,
+			     char * filename);
+/*
+///
+extern void Save2DMesh (
+         const Mesh & mesh2d,
+	 const ARRAY<class SplineSegment*> * splines,
+         ostream & outfile);
+*/
+
+class Surface;
+///
+extern void SaveVolumeMesh (
+         const ARRAY<Point3d> & points,
+         const ARRAY<Element> & elements,
+         const ARRAY<Element> & volelements,
+         const ARRAY<Surface*> & surfaces,
+         char * filename);
+
+///
+void SaveVolumeMesh (const Mesh & mesh, 
+		     const class CSGeometry & geometry,
+		     char * filename);
+
+///
+extern int CheckCode ();
+
+
+///
+extern double CalcTetBadness (const Point3d & p1, 
+			      const Point3d & p2,
+			      const Point3d & p3, 
+			      const Point3d & p4, 
+			      double h);
+///
+extern double CalcTetBadnessGrad (const Point3d & p1, 
+				const Point3d & p2,
+				const Point3d & p3, 
+				const Point3d & p4, 
+				double h, int pi,
+				Vec<3> & grad);
+
+
+/** Calculates volume of an element.
+  The volume of the tetrahedron el is computed
+ */
+// extern double CalcVolume (const ARRAY<Point3d> & points,
+//        const Element & el);  
+
+/** The total volume of all elements is computed.
+  This function calculates the volume of the mesh */
+extern double CalcVolume (const ARRAY<Point3d> & points, 
+	const ARRAY<Element> & elements);
+
+///
+extern int CheckSurfaceMesh (const Mesh & mesh);
+
+///
+extern int CheckSurfaceMesh2 (const Mesh & mesh);
+///
+extern int CheckMesh3D (const Mesh & mesh);
+///
+extern void RemoveProblem (Mesh & mesh, int domainnr);
+#endif
diff --git a/contrib/Netgen/libsrc/meshing/meshtype.cpp b/contrib/Netgen/libsrc/meshing/meshtype.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..9c7baf22146a68f0bcd976dc514ca4af4dc1436d
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/meshtype.cpp
@@ -0,0 +1,2632 @@
+#include <mystdlib.h>
+
+#include "meshing.hpp"  
+
+namespace netgen
+{
+
+
+  ostream & operator<<(ostream  & s, const MeshPoint & pt)
+  {
+    s << Point<3> (pt);
+    return s;
+  }
+
+  /*
+  MultiPointGeomInfo :: MultiPointGeomInfo()
+  {
+    cnt = 0;
+  }
+  */
+
+  int MultiPointGeomInfo :: 
+  AddPointGeomInfo (const PointGeomInfo & gi)
+  {
+    for (int k = 0; k < cnt; k++)
+      if (mgi[k].trignum == gi.trignum)
+	return 0;
+  
+    if (cnt < MULTIPOINTGEOMINFO_MAX)
+      {
+	mgi[cnt] = gi;
+	cnt++;
+	return 0;
+      }
+
+    throw NgException ("Please report error: MPGI Size too small\n");
+  }
+  
+
+  /*
+  void MultiPointGeomInfo :: 
+  Init ()
+  {
+    cnt = 0;
+  }
+
+  void MultiPointGeomInfo :: 
+  DeleteAll ()
+  {
+    cnt = 0;
+  }
+  */
+
+
+
+  Segment :: Segment() 
+  {
+    p1 = -1;
+    p2 = -1; 
+    edgenr = -1;
+
+    singedge_left = 0.;
+    singedge_right = 0.;
+    seginfo = 0;
+
+    si = -1;
+
+    domin = -1;
+    domout = -1;
+    tlosurf = -1;
+
+    surfnr1 = -1;
+    surfnr2 = -1;
+    pmid = -1;
+    meshdocval = 0;
+    /*
+    geominfo[0].trignum=-1; 
+    geominfo[1].trignum=-1; 
+
+    epgeominfo[0].edgenr = 1;
+    epgeominfo[0].dist = 0;
+    epgeominfo[1].edgenr = 1;
+    epgeominfo[1].dist = 0;
+    */
+
+    bcname = 0;
+  }    
+
+  Segment::Segment (const Segment & other)
+    : p1(other.p1),
+      p2(other.p2),
+      edgenr(other.edgenr),
+      singedge_left(other.singedge_left),
+      singedge_right(other.singedge_right),
+      seginfo(other.seginfo),
+      si(other.si),
+      domin(other.domin),
+      domout(other.domout),
+      tlosurf(other.tlosurf),
+      geominfo(),
+      surfnr1(other.surfnr1),
+      surfnr2(other.surfnr2),
+      epgeominfo(),
+      pmid(other.pmid),
+      meshdocval(other.meshdocval),
+      hp_elnr(other.hp_elnr)
+  {
+    geominfo[0] = other.geominfo[0];
+    geominfo[1] = other.geominfo[1];
+    epgeominfo[0] = other.epgeominfo[0];
+    epgeominfo[1] = other.epgeominfo[1];
+    bcname = other.bcname;
+  }
+
+  Segment& Segment::operator=(const Segment & other)
+  {
+    if (&other != this)
+      {
+	p1 = other.p1;
+	p2 = other.p2;
+	edgenr = other.edgenr;
+	singedge_left = other.singedge_left;
+	singedge_right = other.singedge_right;
+	seginfo = other.seginfo;
+	si = other.si;
+	domin = other.domin;
+	domout = other.domout;
+	tlosurf = other.tlosurf;
+	geominfo[0] = other.geominfo[0];
+	geominfo[1] = other.geominfo[1];
+	surfnr1 = other.surfnr1;
+	surfnr2 = other.surfnr2;
+	epgeominfo[0] = other.epgeominfo[0];
+	epgeominfo[1] = other.epgeominfo[1];
+	pmid = other.pmid;
+	meshdocval = other.meshdocval;
+	hp_elnr = other.hp_elnr;
+	bcname = other.bcname;
+      }
+    
+    return *this;
+  }
+
+
+  ostream & operator<<(ostream  & s, const Segment & seg)
+  {
+    s << seg.p1 << "(gi=" << seg.geominfo[0].trignum << ") - "
+      << seg.p2 << "(gi=" << seg.geominfo[1].trignum << ")"
+      << " domin = " << seg.domin << ", domout = " << seg.domout 
+      << " si = " << seg.si << ", edgenr = " << seg.edgenr;
+    return s;
+  }
+
+
+  Element2d :: Element2d ()
+  { 
+    for (int i = 0; i < ELEMENT2D_MAXPOINTS; i++)
+      {
+	pnum[i] = 0;
+	geominfo[i].trignum = 0;
+      }
+    np = 3;
+    index = 0;
+    badel = 0;
+    deleted = 0;
+    typ = TRIG;
+    orderx = ordery = 1;
+    refflag = 1;
+    strongrefflag = false;
+#ifdef PARALLEL
+    isghost = 0;
+#endif
+  } 
+
+
+  Element2d :: Element2d (int anp)
+  { 
+    for (int i = 0; i < ELEMENT2D_MAXPOINTS; i++)
+      {
+	pnum[i] = 0;
+	geominfo[i].trignum = 0;
+      }
+    np = anp;
+    index = 0;
+    badel = 0;
+    deleted = 0;
+    switch (np)
+      {
+      case 3: typ = TRIG; break;
+      case 4: typ = QUAD; break;
+      case 6: typ = TRIG6; break;
+      case 8: typ = QUAD8; break;
+      }
+    orderx = ordery = 1;
+    refflag = 1;
+    strongrefflag = false;
+#ifdef PARALLEL
+    isghost = 0;
+#endif
+  } 
+
+  Element2d :: Element2d (ELEMENT_TYPE atyp)
+  { 
+    for (int i = 0; i < ELEMENT2D_MAXPOINTS; i++)
+      {
+	pnum[i] = 0;
+	geominfo[i].trignum = 0;
+      }
+
+    SetType (atyp);
+
+    index = 0;
+    badel = 0;
+    deleted = 0;
+    orderx = ordery = 1;
+    refflag = 1;
+    strongrefflag = false;
+#ifdef PARALLEL
+  isghost = 0;
+#endif
+
+  } 
+
+
+
+  Element2d :: Element2d (int pi1, int pi2, int pi3)
+{
+  pnum[0] = pi1;
+  pnum[1] = pi2;
+  pnum[2] = pi3;
+  np = 3;
+  typ = TRIG;
+  pnum[3] = 0;
+  pnum[4] = 0;
+  pnum[5] = 0;
+  
+  for (int i = 0; i < ELEMENT2D_MAXPOINTS; i++)
+    geominfo[i].trignum = 0;
+  index = 0;
+  badel = 0;
+  refflag = 1;
+  strongrefflag = false;
+  deleted = 0;
+  orderx = ordery = 1;
+
+#ifdef PARALLEL
+  isghost = 0;
+#endif
+
+}
+
+Element2d :: Element2d (int pi1, int pi2, int pi3, int pi4)
+{
+  pnum[0] = pi1;
+  pnum[1] = pi2;
+  pnum[2] = pi3;
+  pnum[3] = pi4;
+  np = 4;
+  typ = QUAD;
+
+  pnum[4] = 0;
+  pnum[5] = 0;
+  
+  for (int i = 0; i < ELEMENT2D_MAXPOINTS; i++)
+    geominfo[i].trignum = 0;
+  index = 0;
+  badel = 0;
+  refflag = 1;
+  strongrefflag = false;
+  deleted = 0;
+  orderx = ordery = 1;
+
+#ifdef PARALLEL
+  isghost = 0;
+#endif
+}
+
+
+/*
+void Element2d :: SetType (ELEMENT_TYPE atyp)
+{
+  typ = atyp;
+  switch (typ)
+    {
+    case TRIG: np = 3; break;
+    case QUAD: np = 4; break;
+    case TRIG6: np = 6; break;
+    case QUAD6: np = 6; break;
+    default:
+      PrintSysError ("Element2d::SetType, illegal type ", typ);
+    }
+}
+*/
+
+
+void Element2d :: GetBox (const T_POINTS & points, Box3d & box) const
+{
+  box.SetPoint (points.Get(pnum[0]));
+  for (unsigned i = 1; i < np; i++)
+    box.AddPoint (points.Get(pnum[i]));
+}
+
+bool Element2d :: operator==(const Element2d & el2) const
+{
+  bool retval = (el2.GetNP() == np);
+  for(int i= 0; retval && i<np; i++)
+    retval = (el2[i] == (*this)[i]);
+
+  return retval;
+}
+
+
+void Element2d :: Invert2()
+{
+  switch (typ)
+    {
+    case TRIG:
+      {
+	Swap (pnum[1], pnum[2]);
+	break;
+      }
+    case QUAD:
+      {
+	Swap (pnum[0], pnum[3]);
+	Swap (pnum[1], pnum[2]);
+	break;
+      }
+    default:
+      {
+	cerr << "Element2d::Invert2, illegal element type " << int(typ) << endl;
+      }
+    }
+}
+
+int Element2d::HasFace(const Element2d& el) const
+{
+  //nur f�r tets!!! hannes
+  for (int i = 1; i <= 3; i++)
+    {
+      if (PNumMod(i)   == el[0] && 
+	  PNumMod(i+1) == el[1] && 
+	  PNumMod(i+2) == el[2])
+	{
+	  return 1;
+	}
+    }
+  return 0;
+}
+
+void Element2d :: NormalizeNumbering2 ()
+{
+  if (GetNP() == 3)
+    {
+      if (PNum(1) < PNum(2) && PNum(1) < PNum(3))
+	return;
+      else
+	{
+	  if (PNum(2) < PNum(3))
+	    {
+	      PointIndex pi1 = PNum(2);
+	      PNum(2) = PNum(3);
+	      PNum(3) = PNum(1);
+	      PNum(1) = pi1;
+	    }
+	  else
+	    {
+	      PointIndex pi1 = PNum(3);
+	      PNum(3) = PNum(2);
+	      PNum(2) = PNum(1);
+	      PNum(1) = pi1;
+	    }
+	}
+    }
+  else
+    {
+      int mini = 1;
+      for (int i = 2; i <= GetNP(); i++)
+	if (PNum(i) < PNum(mini)) mini = i;
+      
+      Element2d hel = (*this);
+      for (int i = 1; i <= GetNP(); i++)
+	PNum(i) = hel.PNumMod (i+mini-1);
+    }
+}
+
+
+
+
+ARRAY<IntegrationPointData*> ipdtrig;
+ARRAY<IntegrationPointData*> ipdquad;
+
+
+int Element2d :: GetNIP () const
+{
+  int nip;
+  switch (np)
+    {
+    case 3: nip = 1; break;
+    case 4: nip = 4; break;
+    default: nip = 0; break;
+    }
+  return nip;
+}
+
+void Element2d :: 
+GetIntegrationPoint (int ip, Point2d & p, double & weight) const
+{
+  static double eltriqp[1][3] =
+  {
+    { 1.0/3.0, 1.0/3.0, 0.5 }
+  };
+
+  static double elquadqp[4][3] =
+  { 
+    { 0, 0, 0.25 },
+    { 0, 1, 0.25 },
+    { 1, 0, 0.25 },
+    { 1, 1, 0.25 }
+  };
+  
+  double * pp = 0;
+  switch (typ)
+    {
+    case TRIG: pp = &eltriqp[0][0]; break;
+    case QUAD: pp = &elquadqp[ip-1][0]; break;
+    default:
+      PrintSysError ("Element2d::GetIntegrationPoint, illegal type ", typ);
+    }
+
+  p.X() = pp[0];
+  p.Y() = pp[1];
+  weight = pp[2];
+}
+
+void Element2d :: 
+GetTransformation (int ip, const ARRAY<Point2d> & points,
+		   DenseMatrix & trans) const
+{
+  int np = GetNP();
+  static DenseMatrix pmat(2, np), dshape(2, np);
+  pmat.SetSize (2, np);
+  dshape.SetSize (2, np);
+
+  Point2d p;
+  double w;
+
+  GetPointMatrix (points, pmat);
+  GetIntegrationPoint (ip, p, w);
+  GetDShape (p, dshape);
+  
+  CalcABt (pmat, dshape, trans);
+
+  /*
+  (*testout) << "p = " << p  << endl
+	     << "pmat = " << pmat << endl
+	     << "dshape = " << dshape << endl
+	     << "tans = " << trans << endl;
+  */
+}
+
+void Element2d :: 
+GetTransformation (int ip, class DenseMatrix & pmat,
+		   class DenseMatrix & trans) const
+{
+  int np = GetNP();
+
+#ifdef DEBUG
+  if (pmat.Width() != np || pmat.Height() != 2)
+    {
+      (*testout) << "GetTransofrmation: pmat doesn't fit" << endl;
+      return;
+    }
+#endif
+
+  ComputeIntegrationPointData ();
+  DenseMatrix * dshapep;
+  switch (typ)
+    {
+    case TRIG: dshapep = &ipdtrig.Get(ip)->dshape; break;
+    case QUAD: dshapep = &ipdquad.Get(ip)->dshape; break;
+    default:
+      PrintSysError ("Element2d::GetTransformation, illegal type ", typ);
+    }
+  
+  CalcABt (pmat, *dshapep, trans);
+}
+
+
+
+void Element2d :: GetShape (const Point2d & p, Vector & shape) const
+{
+  if (shape.Size() != GetNP())
+    {
+      cerr << "Element::GetShape: Length not fitting" << endl;
+      return;
+    }
+
+  switch (typ)
+    {
+    case TRIG:
+      shape.Elem(1) = 1 - p.X() - p.Y();
+      shape.Elem(2) = p.X();
+      shape.Elem(3) = p.Y();
+      break;
+    case QUAD:
+      shape.Elem(1) = (1-p.X()) * (1-p.Y());
+      shape.Elem(2) = p.X() * (1-p.Y());
+      shape.Elem(3) = p.X() * p.Y();
+      shape.Elem(4) = (1-p.X()) * p.Y();
+      break;
+    default:
+      PrintSysError ("Element2d::GetShape, illegal type ", typ);
+    }
+}
+
+
+
+void Element2d :: GetShapeNew (const Point<2> & p, FlatVector & shape) const
+{
+  switch (typ)
+    {
+    case TRIG:
+      {
+	shape(0) = p(0);
+	shape(1) = p(1);
+	shape(2) = 1-p(0)-p(1);
+	break;
+      }
+
+    case QUAD:
+      {
+	shape(0) = (1-p(0))*(1-p(1));
+	shape(1) =    p(0) *(1-p(1));
+	shape(2) =    p(0) *   p(1) ;
+	shape(3) = (1-p(0))*   p(1) ;
+	break;
+      }
+    }
+}
+
+
+
+
+
+
+
+
+
+void Element2d :: 
+GetDShape (const Point2d & p, DenseMatrix & dshape) const
+{
+#ifdef DEBUG
+  if (dshape.Height() != 2 || dshape.Width() != np)
+    {
+      PrintSysError ("Element::DShape: Sizes don't fit");
+      return;
+    }
+#endif
+
+  switch (typ)
+    {
+    case TRIG:
+      dshape.Elem(1, 1) = -1;
+      dshape.Elem(1, 2) = 1;
+      dshape.Elem(1, 3) = 0;
+      dshape.Elem(2, 1) = -1;
+      dshape.Elem(2, 2) = 0;
+      dshape.Elem(2, 3) = 1;
+      break;
+    case QUAD:
+      dshape.Elem(1, 1) = -(1-p.Y());
+      dshape.Elem(1, 2) = (1-p.Y());
+      dshape.Elem(1, 3) = p.Y();
+      dshape.Elem(1, 4) = -p.Y();
+      dshape.Elem(2, 1) = -(1-p.X());
+      dshape.Elem(2, 2) = -p.X();
+      dshape.Elem(2, 3) = p.X();
+      dshape.Elem(2, 4) = (1-p.X());
+      break;
+
+    default:
+      PrintSysError ("Element2d::GetDShape, illegal type ", typ);
+    }
+}
+
+
+
+
+void Element2d :: 
+GetDShapeNew (const Point<2> & p, MatrixFixWidth<2> & dshape) const
+{
+  switch (typ)
+    {
+    case TRIG:
+      {
+	dshape = 0;
+	dshape(0,0) = 1;
+	dshape(1,1) = 1;
+	dshape(2,0) = -1;
+	dshape(2,1) = -1;
+	break;
+      }
+    case QUAD:
+      {
+	dshape(0,0) = -(1-p(1));
+	dshape(0,1) = -(1-p(0));
+
+	dshape(1,0) =  (1-p(1));
+	dshape(1,1) =  -p(0);
+
+	dshape(2,0) = p(1);
+	dshape(2,1) = p(0);
+
+	dshape(3,0) = -p(1);
+	dshape(3,1) = (1-p(0));
+	break;
+      }
+    }
+}
+
+
+
+
+
+void Element2d :: 
+GetPointMatrix (const ARRAY<Point2d> & points,
+		DenseMatrix & pmat) const
+{
+  int np = GetNP();
+
+#ifdef DEBUG
+  if (pmat.Width() != np || pmat.Height() != 2)
+    {
+      cerr << "Element::GetPointMatrix: sizes don't fit" << endl;
+      return;
+    }
+#endif
+  
+  for (int i = 1; i <= np; i++)
+    {
+      const Point2d & p = points.Get(PNum(i));
+      pmat.Elem(1, i) = p.X();
+      pmat.Elem(2, i) = p.Y();
+    }
+}
+
+
+
+
+
+double Element2d :: CalcJacobianBadness (const ARRAY<Point2d> & points) const
+{
+  int i, j;
+  int nip = GetNIP();
+  static DenseMatrix trans(2,2);
+  static DenseMatrix pmat;
+  
+  pmat.SetSize (2, GetNP());
+  GetPointMatrix (points, pmat);
+
+  double err = 0;
+  for (i = 1; i <= nip; i++)
+    {
+      GetTransformation (i, pmat, trans);
+
+      // Frobenius norm
+      double frob = 0;
+      for (j = 1; j <= 4; j++)
+	frob += sqr (trans.Get(j));
+      frob = sqrt (frob);
+      frob /= 2;
+
+      double det = trans.Det();
+
+      if (det <= 0)
+	err += 1e12;
+      else
+	err += frob * frob / det;
+    }
+
+  err /= nip;
+  return err;
+}
+
+
+
+static const int qip_table[4][4] =
+  { { 0, 1, 0, 3 },
+    { 0, 1, 1, 2 },
+    { 3, 2, 0, 3 },
+    { 3, 2, 1, 2 }
+  };
+
+double Element2d :: 
+CalcJacobianBadnessDirDeriv (const ARRAY<Point2d> & points,
+			     int pi, Vec2d & dir, double & dd) const
+{
+  if (typ == QUAD)
+    {
+      Mat<2,2> trans, dtrans;
+      Mat<2,4> vmat, pmat;
+      
+      for (int j = 0; j < 4; j++)
+	{
+	  const Point2d & p = points.Get( (*this)[j] );
+	  pmat(0, j) = p.X();
+	  pmat(1, j) = p.Y();
+	}
+
+      vmat = 0.0;
+      vmat(0, pi-1) = dir.X();
+      vmat(1, pi-1) = dir.Y();
+      
+      double err = 0;
+      dd = 0;
+
+      for (int i = 0; i < 4; i++)
+	{
+	  int ix1 = qip_table[i][0];
+	  int ix2 = qip_table[i][1];
+	  int iy1 = qip_table[i][2];
+	  int iy2 = qip_table[i][3];
+	      
+	  trans(0,0) = pmat(0, ix2) - pmat(0,ix1);
+	  trans(1,0) = pmat(1, ix2) - pmat(1,ix1);
+	  trans(0,1) = pmat(0, iy2) - pmat(0,iy1);
+	  trans(1,1) = pmat(1, iy2) - pmat(1,iy1);
+
+	  double det = trans(0,0)*trans(1,1)-trans(1,0)*trans(0,1);
+
+	  if (det <= 0)
+	    {
+	      dd = 0;
+	      return 1e12;
+	    }
+	  
+	  dtrans(0,0) = vmat(0, ix2) - vmat(0,ix1);
+	  dtrans(1,0) = vmat(1, ix2) - vmat(1,ix1);
+	  dtrans(0,1) = vmat(0, iy2) - vmat(0,iy1);
+	  dtrans(1,1) = vmat(1, iy2) - vmat(1,iy1);
+
+
+	  // Frobenius norm
+	  double frob = 0;
+	  for (int j = 0; j < 4; j++) 
+	    frob += sqr (trans(j));
+	  frob = sqrt (frob);
+	  
+	  double dfrob = 0;
+	  for (int j = 0; j < 4; j++)
+	    dfrob += trans(j) * dtrans(j);
+	  dfrob = dfrob / frob;
+	  
+	  frob /= 2;      
+	  dfrob /= 2;
+	  
+	  
+	  // ddet = \sum_j det (m_j)   with m_j = trans, except col j = dtrans
+	  double ddet 
+	    = dtrans(0,0) * trans(1,1) - trans(0,1) * dtrans(1,0)
+	    + trans(0,0) * dtrans(1,1) - dtrans(0,1) * trans(1,0);
+	  
+	  err += frob * frob / det;
+	  dd += (2 * frob * dfrob * det - frob * frob * ddet) / (det * det);
+	}
+      
+      err /= 4;
+      dd /= 4;
+      return err;
+    }
+
+  int nip = GetNIP();
+  static DenseMatrix trans(2,2), dtrans(2,2);
+  static DenseMatrix pmat, vmat;
+  
+  pmat.SetSize (2, GetNP());
+  vmat.SetSize (2, GetNP());
+
+  GetPointMatrix (points, pmat);
+  
+  vmat = 0.0;
+  vmat.Elem(1, pi) = dir.X();
+  vmat.Elem(2, pi) = dir.Y();
+
+
+  double err = 0;
+  dd = 0;
+
+  for (int i = 1; i <= nip; i++)
+    {
+      GetTransformation (i, pmat, trans);
+      GetTransformation (i, vmat, dtrans);
+
+      // Frobenius norm
+      double frob = 0;
+      for (int j = 1; j <= 4; j++)
+	frob += sqr (trans.Get(j));
+      frob = sqrt (frob);
+      
+      double dfrob = 0;
+      for (int j = 1; j <= 4; j++)
+	dfrob += trans.Get(j) * dtrans.Get(j);
+      dfrob = dfrob / frob;
+      
+      frob /= 2;      
+      dfrob /= 2;
+      
+      double det = trans(0,0)*trans(1,1)-trans(1,0)*trans(0,1);
+
+      // ddet = \sum_j det (m_j)   with m_j = trans, except col j = dtrans
+      double ddet 
+	= dtrans(0,0) * trans(1,1) - trans(0,1) * dtrans(1,0)
+	+ trans(0,0) * dtrans(1,1) - dtrans(0,1) * trans(1,0);
+
+      if (det <= 0)
+	err += 1e12;
+      else
+	{
+	  err += frob * frob / det;
+	  dd += (2 * frob * dfrob * det - frob * frob * ddet) / (det * det);
+	}
+    }
+
+  err /= nip;
+  dd /= nip;
+  return err;
+}
+
+
+
+double Element2d :: 
+CalcJacobianBadness (const T_POINTS & points, const Vec<3> & n) const
+{
+  int i, j;
+  int nip = GetNIP();
+  static DenseMatrix trans(2,2);
+  static DenseMatrix pmat;
+  
+  pmat.SetSize (2, GetNP());
+
+  Vec<3> t1, t2;
+  t1 = n.GetNormal();
+  t2 = Cross (n, t1);
+
+  for (i = 1; i <= GetNP(); i++)
+    {
+      Point3d p = points.Get(PNum(i));
+      pmat.Elem(1, i) = p.X() * t1(0) + p.Y() * t1(1) + p.Z() * t1(2);
+      pmat.Elem(2, i) = p.X() * t2(0) + p.Y() * t2(1) + p.Z() * t2(2);
+    }
+
+  double err = 0;
+  for (i = 1; i <= nip; i++)
+    {
+      GetTransformation (i, pmat, trans);
+
+      // Frobenius norm
+      double frob = 0;
+      for (j = 1; j <= 4; j++)
+	frob += sqr (trans.Get(j));
+      frob = sqrt (frob);
+      frob /= 2;
+
+      double det = trans.Det();
+      if (det <= 0)
+	err += 1e12;
+      else
+	err += frob * frob / det;
+    }
+
+  err /= nip;
+  return err;
+}
+
+
+
+void Element2d :: ComputeIntegrationPointData () const
+{
+  switch (np)
+    {
+    case 3: if (ipdtrig.Size()) return; break;
+    case 4: if (ipdquad.Size()) return; break;
+    }
+
+  for (int i = 1; i <= GetNIP(); i++)
+    {
+      IntegrationPointData * ipd = new IntegrationPointData;
+      Point2d hp;
+      GetIntegrationPoint (i, hp, ipd->weight);
+      ipd->p(0) = hp.X();
+      ipd->p(1) = hp.Y();
+      ipd->p(2) = 0;
+
+      ipd->shape.SetSize(GetNP());
+      ipd->dshape.SetSize(2, GetNP());
+
+      GetShape (hp, ipd->shape);
+      GetDShape (hp, ipd->dshape);
+
+      switch (np)
+	{
+	case 3: ipdtrig.Append (ipd); break;
+	case 4: ipdquad.Append (ipd); break;
+	}
+    }
+}
+
+
+
+
+
+
+
+
+
+
+ostream & operator<<(ostream  & s, const Element2d & el)
+{
+  s << "np = " << el.GetNP();
+  for (int j = 1; j <= el.GetNP(); j++)
+    s << " " << el.PNum(j);
+  return s;
+}
+
+
+ostream & operator<<(ostream  & s, const Element & el)
+{
+  s << "np = " << el.GetNP();
+  for (int j = 0; j < el.GetNP(); j++)
+    s << " " << int(el[j]);
+  return s;
+}
+
+
+Element :: Element ()
+{
+  typ = TET;
+  np = 4;
+  for (int i = 0; i < ELEMENT_MAXPOINTS; i++)
+    pnum[i] = 0;
+  index = 0;
+  flags.marked = 1;
+  flags.badel = 0;
+  flags.reverse = 0;
+  flags.illegal = 0;
+  flags.illegal_valid = 0;
+  flags.badness_valid = 0;
+  flags.refflag = 1;
+  flags.strongrefflag = false;
+  flags.deleted = 0;
+  flags.fixed = 0;
+  orderx = ordery = orderz = 1;
+
+#ifdef PARALLEL
+  partitionNumber = -1;
+  isghost = 0;
+#endif
+
+}
+
+
+Element :: Element (int anp)
+{
+  np = anp;
+  int i;
+  for (i = 0; i < ELEMENT_MAXPOINTS; i++)
+    pnum[i] = 0;
+  index = 0;
+  flags.marked = 1;
+  flags.badel = 0;
+  flags.reverse = 0;
+  flags.illegal = 0;
+  flags.illegal_valid = 0;
+  flags.badness_valid = 0;
+  flags.refflag = 1;
+  flags.strongrefflag = false;
+  flags.deleted = 0;
+  flags.fixed = 0;
+
+  switch (np)
+    {
+    case 4: typ = TET; break;
+    case 5: typ = PYRAMID; break;
+    case 6: typ = PRISM; break;
+    case 8: typ = HEX; break;
+    case 10: typ = TET10; break;
+    default: cerr << "Element::Element: unknown element with " << np << " points" << endl;
+    }
+  orderx = ordery = orderz = 1;
+
+#ifdef PARALLEL
+  isghost = 0;
+#endif
+}
+
+void Element :: SetOrder (const int aorder) 
+  { 
+    orderx = aorder; 
+    ordery = aorder; 
+    orderz = aorder;
+  }
+
+
+void Element :: SetOrder (const int ox, const int oy, const int oz) 
+{ 
+  orderx = ox; 
+  ordery = oy;
+  orderz = oz; 
+}
+
+
+Element :: Element (ELEMENT_TYPE type)
+{
+  SetType (type);
+
+  int i;
+  for (i = 0; i < ELEMENT_MAXPOINTS; i++)
+    pnum[i] = 0;
+  index = 0;
+  flags.marked = 1;
+  flags.badel = 0;
+  flags.reverse = 0;
+  flags.illegal = 0;
+  flags.illegal_valid = 0;
+  flags.badness_valid = 0;
+  flags.refflag = 1;
+  flags.strongrefflag = false;
+  flags.deleted = 0;
+  flags.fixed = 0;
+  orderx = ordery = orderz = 1;
+
+#ifdef PARALLEL
+  isghost = 0;
+#endif
+}
+
+
+
+
+
+Element & Element :: operator= (const Element & el2)
+{
+  typ = el2.typ;
+  np = el2.np;
+  for (int i = 0; i < ELEMENT_MAXPOINTS; i++)
+    pnum[i] = el2.pnum[i];
+  index = el2.index;
+  flags = el2.flags;
+  orderx = el2.orderx;
+  ordery = el2.ordery;
+  orderz = el2.orderz;
+  hp_elnr = el2.hp_elnr;
+  flags = el2.flags;
+  return *this;
+}
+
+
+
+void Element :: SetNP (int anp)
+{
+  np = anp; 
+  switch (np)
+    {
+    case 4: typ = TET; break;
+    case 5: typ = PYRAMID; break;
+    case 6: typ = PRISM; break;
+    case 8: typ = HEX; break;
+    case 10: typ = TET10; break;
+      // 
+    default: break;
+      cerr << "Element::SetNP unknown element with " << np << " points" << endl;
+    }
+}
+
+
+
+void Element :: SetType (ELEMENT_TYPE atyp)
+{
+  typ = atyp;
+  switch (atyp)
+    {
+    case TET: np = 4; break;
+    case PYRAMID: np = 5; break;
+    case PRISM: np = 6; break;
+    case HEX: np = 8; break;
+    case TET10: np = 10; break;
+    case PRISM12: np = 12; break;
+    }
+}
+
+
+
+void Element :: Invert()
+{
+  switch (GetNP())
+    {
+    case 4:
+      {
+	Swap (PNum(3), PNum(4));
+	break;
+      }
+    case 5:
+      {
+	Swap (PNum(1), PNum(4));
+	Swap (PNum(2), PNum(3));
+	break;
+      }
+    case 6:
+      {
+	Swap (PNum(1), PNum(4));
+	Swap (PNum(2), PNum(5));
+	Swap (PNum(3), PNum(6));
+	break;
+      }
+    }
+}
+
+
+void Element :: Print (ostream & ost) const
+{
+  ost << np << " Points: ";
+  for (int i = 1; i <= np; i++)
+    ost << pnum[i-1] << " " << endl;
+}
+
+void Element :: GetBox (const T_POINTS & points, Box3d & box) const
+{
+  box.SetPoint (points.Get(PNum(1)));
+  box.AddPoint (points.Get(PNum(2)));
+  box.AddPoint (points.Get(PNum(3)));
+  box.AddPoint (points.Get(PNum(4)));
+}
+
+double Element :: Volume (const T_POINTS & points) const
+{
+  Vec<3> v1 = points.Get(PNum(2)) - points.Get(PNum(1));
+  Vec<3> v2 = points.Get(PNum(3)) - points.Get(PNum(1));
+  Vec<3> v3 = points.Get(PNum(4)) - points.Get(PNum(1)); 
+  
+  return -(Cross (v1, v2) * v3) / 6;	 
+}  
+
+
+void Element :: GetFace2 (int i, Element2d & face) const
+{
+  static const int tetfaces[][5] = 
+  { { 3, 2, 3, 4, 0 },
+    { 3, 3, 1, 4, 0 },
+    { 3, 1, 2, 4, 0 },
+    { 3, 2, 1, 3, 0 } };
+
+  static const int pyramidfaces[][5] =
+  { { 4, 1, 4, 3, 2 },
+    { 3, 1, 2, 5, 0 },
+    { 3, 2, 3, 5, 0 },
+    { 3, 3, 4, 5, 0 },
+    { 3, 4, 1, 5, 0 } };
+
+  static const int prismfaces[][5] =
+  {
+    { 3, 1, 3, 2, 0 },
+    { 3, 4, 5, 6, 0 },
+    { 4, 1, 2, 5, 4 },
+    { 4, 2, 3, 6, 5 },
+    { 4, 3, 1, 4, 6 }
+  };
+
+  switch (np)
+    {
+    case 4: // tet
+    case 10: // tet
+      {
+	face.SetType(TRIG);
+	for (int j = 1; j <= 3; j++)
+	  face.PNum(j) = PNum(tetfaces[i-1][j]);
+	break;
+      }
+    case 5: // pyramid
+      {
+	// face.SetNP(pyramidfaces[i-1][0]);
+	face.SetType ( (i == 1) ? QUAD : TRIG);
+	for (int j = 1; j <= face.GetNP(); j++)
+	  face.PNum(j) = PNum(pyramidfaces[i-1][j]);
+	break;
+      }
+    case 6: // prism
+      {
+	//	face.SetNP(prismfaces[i-1][0]);
+	face.SetType ( (i >= 3) ? QUAD : TRIG);
+	for (int j = 1; j <= face.GetNP(); j++)
+	  face.PNum(j) = PNum(prismfaces[i-1][j]);
+	break;
+      }
+    }
+}
+
+
+
+void Element :: GetTets (ARRAY<Element> & locels) const
+{
+  GetTetsLocal (locels);
+  int i, j;
+  for (i = 1; i <= locels.Size(); i++)
+    for (j = 1; j <= 4; j++)
+      locels.Elem(i).PNum(j) = PNum ( locels.Elem(i).PNum(j) );
+}
+
+void Element :: GetTetsLocal (ARRAY<Element> & locels) const
+{
+  int i, j;
+  locels.SetSize(0);
+  switch (GetType())
+    {
+    case TET:
+      {
+	int linels[1][4] = 
+	{ { 1, 2, 3, 4 },
+	};
+	for (i = 0; i < 1; i++)
+	  {
+	    Element tet(4);
+	    for (j = 1; j <= 4; j++)
+	      tet.PNum(j) = linels[i][j-1];
+	    locels.Append (tet);
+	  }
+	break;
+      }
+    case TET10:
+      {
+	int linels[8][4] = 
+	{ { 1, 5, 6, 7 },
+	  { 5, 2, 8, 9 },
+	  { 6, 8, 3, 10 },
+	  { 7, 9, 10, 4 },
+	  { 5, 6, 7, 9 },
+	  { 5, 6, 9, 8 },
+	  { 6, 7, 9, 10 },
+	  { 6, 8, 10, 9 } };
+	for (i = 0; i < 8; i++)
+	  {
+	    Element tet(4);
+	    for (j = 1; j <= 4; j++)
+	      tet.PNum(j) = linels[i][j-1];
+	    locels.Append (tet);
+	  }
+	break;
+      }
+    case PYRAMID:
+      {
+	int linels[2][4] = 
+	{ { 1, 2, 3, 5 },
+	  { 1, 3, 4, 5 } };
+	for (i = 0; i < 2; i++)
+	  {
+	    Element tet(4);
+	    for (j = 1; j <= 4; j++)
+	      tet.PNum(j) = linels[i][j-1];
+	    locels.Append (tet);
+	  }
+	break;
+      }
+    case PRISM:
+    case PRISM12:
+      {
+	int linels[3][4] = 
+	{ { 1, 2, 3, 4 },
+	  { 4, 2, 3, 5 },
+	  { 6, 5, 4, 3 }
+	};
+	for (i = 0; i < 3; i++)
+	  {
+	    Element tet(4);
+	    for (j = 0; j < 4; j++)
+	      tet[j] = linels[i][j];
+	    locels.Append (tet);
+	  }
+	break;
+      }
+    case HEX:
+      {
+	int linels[6][4] = 
+	{ { 1, 7, 2, 3 },
+	  { 1, 7, 3, 4 },
+	  { 1, 7, 4, 8 },
+	  { 1, 7, 8, 5 },
+	  { 1, 7, 5, 6 },
+	  { 1, 7, 6, 2 }
+	};
+	for (i = 0; i < 6; i++)
+	  {
+	    Element tet(4);
+	    for (j = 0; j < 4; j++)
+	      tet[j] = linels[i][j];
+	    locels.Append (tet);
+	  }
+	break;
+      }
+    default:
+      {
+	cerr << "GetTetsLocal not implemented for el with " << GetNP() << " nodes" << endl;
+      }
+    }
+}
+
+bool Element :: operator==(const Element & el2) const
+{
+  bool retval = (el2.GetNP() == np);
+  for(int i= 0; retval && i<np; i++)
+    retval = (el2[i] == (*this)[i]);
+
+  return retval;
+}
+
+
+#ifdef OLD
+void Element :: GetNodesLocal (ARRAY<Point3d> & points) const
+{
+  const static double tetpoints[4][3] =
+    { { 0, 0, 0 },
+      { 1, 0, 0 },
+      { 0, 1, 0 },
+      { 0, 0, 1 }};
+  
+  const static double prismpoints[6][3] =
+    { { 0, 0, 0 },
+      { 1, 0, 0 },
+      { 0, 1, 0 },
+      { 0, 0, 1 },
+      { 1, 0, 1 },
+      { 0, 1, 1 } };
+  
+  const static double pyramidpoints[6][3] =
+    { { 0, 0, 0 },
+      { 1, 0, 0 },
+      { 1, 1, 0 },
+      { 0, 1, 0 },
+      { 0, 0, 1 } };
+  
+  const static double tet10points[10][3] =
+    { { 0, 0, 0 },
+      { 1, 0, 0 },
+      { 0, 1, 0 },
+      { 0, 0, 1 },
+      { 0.5, 0, 0 },
+      { 0, 0.5, 0 },
+      { 0, 0, 0.5 },
+      { 0.5, 0.5, 0 },
+      { 0.5, 0, 0.5 },
+      { 0, 0.5, 0.5 } };
+
+  const static double hexpoints[8][3] =
+    { 
+      { 0, 0, 0 },
+      { 1, 0, 0 },
+      { 1, 1, 0 },
+      { 0, 1, 0 },
+      { 0, 0, 1 },
+      { 1, 0, 1 },
+      { 1, 1, 1 },
+      { 0, 1, 1 }
+    };
+  
+  int np, i;
+  const double (*pp)[3];
+  switch (GetType())
+    {
+    case TET:
+      {
+	np = 4;
+	pp = tetpoints;
+	break;
+      }
+    case PRISM:
+    case PRISM12:
+      {
+	np = 6;
+	pp = prismpoints;
+	break;
+      }
+    case TET10:
+      {
+	np = 10;
+	pp = tet10points;
+	break;
+      }
+    case PYRAMID:
+      {
+	np = 5;
+	pp = pyramidpoints;
+	break;
+      }
+    case HEX:
+      {
+	np = 8;
+	pp = hexpoints;
+	break;
+      }
+    default:
+      {
+	cout << "GetNodesLocal not impelemented for element " << GetType() << endl;
+	np = 0;
+      }
+    }
+  
+  points.SetSize(0);
+  for (i = 0; i < np; i++)
+    points.Append (Point3d (pp[i][0], pp[i][1], pp[i][2]));
+}
+#endif
+
+
+
+
+
+
+void Element :: GetNodesLocalNew (ARRAY<Point<3> > & points) const
+{
+  const static double tetpoints[4][3] =
+    {      
+      { 1, 0, 0 },
+      { 0, 1, 0 },
+      { 0, 0, 1 },
+      { 0, 0, 0 }
+    };
+  
+  const static double prismpoints[6][3] =
+    {
+      { 1, 0, 0 },
+      { 0, 1, 0 },
+      { 0, 0, 0 },
+      { 1, 0, 1 },
+      { 0, 1, 1 },
+      { 0, 0, 1 }
+    };
+  
+  const static double pyramidpoints[6][3] =
+    { { 0, 0, 0 },
+      { 1, 0, 0 },
+      { 1, 1, 0 },
+      { 0, 1, 0 },
+      { 0, 0, 1 } };
+  
+  const static double tet10points[10][3] =
+    { { 0, 0, 0 },
+      { 1, 0, 0 },
+      { 0, 1, 0 },
+      { 0, 0, 1 },
+      { 0.5, 0, 0 },
+      { 0, 0.5, 0 },
+      { 0, 0, 0.5 },
+      { 0.5, 0.5, 0 },
+      { 0.5, 0, 0.5 },
+      { 0, 0.5, 0.5 } };
+
+  const static double hexpoints[8][3] =
+    { 
+      { 0, 0, 0 },
+      { 1, 0, 0 },
+      { 1, 1, 0 },
+      { 0, 1, 0 },
+      { 0, 0, 1 },
+      { 1, 0, 1 },
+      { 1, 1, 1 },
+      { 0, 1, 1 }
+    };
+  
+
+  
+  int np, i;
+  const double (*pp)[3];
+  switch (GetType())
+    {
+    case TET:
+      {
+	np = 4;
+	pp = tetpoints;
+	break;
+      }
+    case PRISM:
+    case PRISM12:
+      {
+	np = 6;
+	pp = prismpoints;
+	break;
+      }
+    case TET10:
+      {
+	np = 10;
+	pp = tet10points;
+	break;
+      }
+    case PYRAMID:
+      {
+	np = 5;
+	pp = pyramidpoints;
+	break;
+      }
+    case HEX:
+      {
+	np = 8;
+	pp = hexpoints;
+	break;
+      }
+    default:
+      {
+	cout << "GetNodesLocal not impelemented for element " << GetType() << endl;
+	np = 0;
+      }
+    }
+  
+  points.SetSize(0);
+  for (i = 0; i < np; i++)
+    points.Append (Point<3> (pp[i][0], pp[i][1], pp[i][2]));
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+void Element :: GetSurfaceTriangles (ARRAY<Element2d> & surftrigs) const
+{
+  static int tet4trigs[][3] = 
+  { { 2, 3, 4 },
+    { 3, 1, 4 },
+    { 1, 2, 4 },
+    { 2, 1, 3 } };
+
+  static int tet10trigs[][3] = 
+  { { 2, 8, 9 }, { 3, 10, 8}, { 4, 9, 10 }, { 9, 8, 10 },
+    { 3, 6, 10 }, { 1, 7, 6 }, { 4, 10, 7 }, { 6, 7, 10 },
+    { 1, 5, 7 }, { 2, 9, 5 }, { 4, 7, 9 }, { 5, 9, 7 },
+    { 1, 6, 5 }, { 2, 5, 8 }, { 3, 8, 6 }, { 5, 6, 8 }
+  };
+
+  static int pyramidtrigs[][3] =
+  {
+    { 1, 3, 2 },
+    { 1, 4, 3 },
+    { 1, 2, 5 },
+    { 2, 3, 5 },
+    { 3, 4, 5 },
+    { 4, 1, 5 }
+  };
+
+  static int prismtrigs[][3] =
+    {
+      { 1, 3, 2 },
+      { 4, 5, 6 },
+      { 1, 2, 4 },
+      { 4, 2, 5 },
+      { 2, 3, 5 },
+      { 5, 3, 6 },
+      { 3, 1, 6 },
+      { 6, 1, 4 }
+    };
+  
+  static int hextrigs[][3] = 
+    {
+      { 1, 3, 2 },
+      { 1, 4, 3 }, 
+      { 5, 6, 7 },
+      { 5, 7, 8 },
+      { 1, 2, 6 },
+      { 1, 6, 5 },
+      { 2, 3, 7 },
+      { 2, 7, 6 },
+      { 3, 4, 8 },
+      { 3, 8, 7 },
+      { 4, 1, 8 },
+      { 1, 5, 8 }
+    };
+
+  int j;
+
+  int nf;
+  int (*fp)[3];
+
+  switch (GetType())
+    {
+    case TET:
+      {
+	nf = 4;
+	fp = tet4trigs;
+	break;
+      }
+    case PYRAMID:
+      {
+	nf = 6;
+	fp = pyramidtrigs;
+	break;
+      }
+    case PRISM:
+    case PRISM12:
+      {
+	nf = 8;
+	fp = prismtrigs;
+	break;
+      }
+    case TET10:
+      {
+	nf = 16;
+	fp = tet10trigs;
+	break;
+      }
+    case HEX:
+      {
+	nf = 12;
+	fp = hextrigs;
+	break;
+      }
+    default:
+      {
+	nf = 0;
+	fp = NULL;
+      }
+    }
+
+  
+  surftrigs.SetSize (nf);
+  for (j = 0; j < nf; j++)
+    {
+      surftrigs.Elem(j+1) = Element2d(TRIG);
+      surftrigs.Elem(j+1).PNum(1) = fp[j][0];
+      surftrigs.Elem(j+1).PNum(2) = fp[j][1];
+      surftrigs.Elem(j+1).PNum(3) = fp[j][2];
+    }
+}
+
+
+
+
+
+ARRAY< AutoPtr < IntegrationPointData > > ipdtet;
+ARRAY< AutoPtr < IntegrationPointData > > ipdtet10;
+
+
+
+int Element :: GetNIP () const
+{
+  int nip;
+  switch (typ)
+    {
+    case TET: nip = 1; break;
+    case TET10: nip = 8; break;
+    default: nip = 0; break;
+    }
+  return nip;
+}
+
+void Element :: 
+GetIntegrationPoint (int ip, Point<3> & p, double & weight) const
+{
+  static double eltetqp[1][4] =
+  {
+    { 0.25, 0.25, 0.25, 1.0/6.0 }
+  };
+
+  static double eltet10qp[8][4] =
+  {
+    { 0.585410196624969, 0.138196601125011, 0.138196601125011, 1.0/24.0 },
+    { 0.138196601125011, 0.585410196624969, 0.138196601125011, 1.0/24.0 },
+    { 0.138196601125011, 0.138196601125011, 0.585410196624969, 1.0/24.0 },
+    { 0.138196601125011, 0.138196601125011, 0.138196601125011, 1.0/24.0 },
+    { 1, 0, 0, 1 },
+    { 0, 1, 0, 1 },
+    { 0, 0, 1, 1 },
+    { 0, 0, 0, 1 },
+  };
+  
+  double * pp;
+  switch (typ)
+    {
+    case TET: pp = &eltetqp[0][0]; break;
+    case TET10: pp = &eltet10qp[ip-1][0]; break;
+    }
+
+  p(0) = pp[0];
+  p(1) = pp[1];
+  p(2) = pp[2];
+  weight = pp[3];
+}
+
+void Element :: 
+GetTransformation (int ip, const T_POINTS & points,
+		   DenseMatrix & trans) const
+{
+  int np = GetNP();
+  static DenseMatrix pmat(3, np), dshape(3, np);
+  pmat.SetSize (3, np);
+  dshape.SetSize (3, np);
+
+  Point<3> p;
+  double w;
+
+  GetPointMatrix (points, pmat);
+  GetIntegrationPoint (ip, p, w);
+  GetDShape (p, dshape);
+  
+  CalcABt (pmat, dshape, trans);
+
+  /*
+  (*testout) << "p = " << p  << endl
+	     << "pmat = " << pmat << endl
+	     << "dshape = " << dshape << endl
+	     << "tans = " << trans << endl;
+  */
+}
+
+void Element :: 
+GetTransformation (int ip, class DenseMatrix & pmat,
+		   class DenseMatrix & trans) const
+{
+  int np = GetNP();
+
+  if (pmat.Width() != np || pmat.Height() != 3)
+    {
+      (*testout) << "GetTransofrmation: pmat doesn't fit" << endl;
+      return;
+    }
+
+  ComputeIntegrationPointData ();
+  DenseMatrix * dshapep;
+  switch (GetType())
+    {
+    case TET: dshapep = &ipdtet.Get(ip)->dshape; break;
+    case TET10: dshapep = &ipdtet10.Get(ip)->dshape; break;
+    }
+  
+  CalcABt (pmat, *dshapep, trans);
+}
+
+
+
+void Element :: GetShape (const Point<3> & hp, Vector & shape) const
+{
+  Point3d p = hp;
+
+  if (shape.Size() != GetNP())
+    {
+      cerr << "Element::GetShape: Length not fitting" << endl;
+      return;
+    }
+
+  switch (typ)
+    {
+    case TET:
+      {
+	shape.Elem(1) = 1 - p.X() - p.Y() - p.Z(); 
+	shape.Elem(2) = p.X();
+	shape.Elem(3) = p.Y();
+	shape.Elem(4) = p.Z();
+	break;
+      }
+    case TET10:
+      {
+	double lam1 = 1 - p.X() - p.Y() - p.Z();
+	double lam2 = p.X();
+	double lam3 = p.Y();
+	double lam4 = p.Z();
+	
+	shape.Elem(5) = 4 * lam1 * lam2;
+	shape.Elem(6) = 4 * lam1 * lam3;
+	shape.Elem(7) = 4 * lam1 * lam4;
+	shape.Elem(8) = 4 * lam2 * lam3;
+	shape.Elem(9) = 4 * lam2 * lam4;
+	shape.Elem(10) = 4 * lam3 * lam4;
+	
+	shape.Elem(1) = lam1 - 
+	  0.5 * (shape.Elem(5) + shape.Elem(6) + shape.Elem(7));
+	shape.Elem(2) = lam2 - 
+	  0.5 * (shape.Elem(5) + shape.Elem(8) + shape.Elem(9));
+	shape.Elem(3) = lam3 - 
+	  0.5 * (shape.Elem(6) + shape.Elem(8) + shape.Elem(10));
+	shape.Elem(4) = lam4 - 
+	  0.5 * (shape.Elem(7) + shape.Elem(9) + shape.Elem(10));
+	break;
+      }
+
+    case PRISM:
+      {
+	Point<3> hp = p; 
+	shape(0) = hp(0) * (1-hp(2));
+	shape(1) = hp(1) * (1-hp(2));
+	shape(2) = (1-hp(0)-hp(1)) * (1-hp(2));
+	shape(3) = hp(0) * hp(2);
+	shape(4) = hp(1) * hp(2);
+	shape(5) = (1-hp(0)-hp(1)) * hp(2);
+	break;
+      }
+    case HEX:
+      {
+	Point<3> hp = p; 
+	shape(0) = (1-hp(0))*(1-hp(1))*(1-hp(2));
+	shape(1) = (  hp(0))*(1-hp(1))*(1-hp(2));
+	shape(2) = (  hp(0))*(  hp(1))*(1-hp(2));
+	shape(3) = (1-hp(0))*(  hp(1))*(1-hp(2));
+	shape(4) = (1-hp(0))*(1-hp(1))*(  hp(2));
+	shape(5) = (  hp(0))*(1-hp(1))*(  hp(2));
+	shape(6) = (  hp(0))*(  hp(1))*(  hp(2));
+	shape(7) = (1-hp(0))*(  hp(1))*(  hp(2));
+	break;
+      }
+    }
+}
+
+
+
+void Element :: GetShapeNew (const Point<3> & p, FlatVector & shape) const
+{
+  /*
+  if (shape.Size() < GetNP())
+    {
+      cerr << "Element::GetShape: Length not fitting" << endl;
+      return;
+    }
+  */
+
+  switch (typ)
+    {
+    case TET:
+      {
+	shape(0) = p(0);
+	shape(1) = p(1);
+	shape(2) = p(2);
+	shape(3) = 1-p(0)-p(1)-p(2);
+	break;
+      }
+
+    case PYRAMID:
+      {
+	double noz = 1-p(2);
+	if (noz == 0.0) noz = 1e-10;
+
+	double xi  = p(0) / noz;
+	double eta = p(1) / noz;
+	shape(0) = (1-xi)*(1-eta) * (noz);
+	shape(1) = (  xi)*(1-eta) * (noz);
+	shape(2) = (  xi)*(  eta) * (noz);
+	shape(3) = (1-xi)*(  eta) * (noz);
+	shape(4) = p(2);
+	break;
+      }
+
+    case PRISM:
+      {
+	shape(0) = p(0) * (1-p(2));
+	shape(1) = p(1) * (1-p(2));
+	shape(2) = (1-p(0)-p(1)) * (1-p(2));
+	shape(3) = p(0) * p(2);
+	shape(4) = p(1) * p(2);
+	shape(5) = (1-p(0)-p(1)) * p(2);
+	break;
+      }
+    case HEX:
+      {
+	shape(0) = (1-p(0))*(1-p(1))*(1-p(2));
+	shape(1) = (  p(0))*(1-p(1))*(1-p(2));
+	shape(2) = (  p(0))*(  p(1))*(1-p(2));
+	shape(3) = (1-p(0))*(  p(1))*(1-p(2));
+	shape(4) = (1-p(0))*(1-p(1))*(  p(2));
+	shape(5) = (  p(0))*(1-p(1))*(  p(2));
+	shape(6) = (  p(0))*(  p(1))*(  p(2));
+	shape(7) = (1-p(0))*(  p(1))*(  p(2));
+	break;
+      }
+    }
+}
+
+
+
+
+void Element :: 
+GetDShape (const Point<3> & hp, DenseMatrix & dshape) const
+{
+  Point3d p = hp;
+
+  int np = GetNP();
+  if (dshape.Height() != 3 || dshape.Width() != np)
+    {
+      cerr << "Element::DShape: Sizes don't fit" << endl;
+      return;
+    }
+
+  int i, j;
+  double eps = 1e-6;
+  Vector shaper(np), shapel(np);
+
+  for (i = 1; i <= 3; i++)
+    {
+      Point3d pr(p), pl(p);
+      pr.X(i) += eps;
+      pl.X(i) -= eps;
+      
+      GetShape (pr, shaper);
+      GetShape (pl, shapel);
+      for (j = 1; j <= np; j++)
+	dshape.Elem(i, j) = (shaper.Get(j) - shapel.Get(j)) / (2 * eps);
+    }
+}
+
+
+
+void Element :: 
+GetDShapeNew (const Point<3> & p, MatrixFixWidth<3> & dshape) const
+{
+  switch (typ)
+    {
+    case TET:
+      {
+	dshape = 0;
+	dshape(0,0) = 1;
+	dshape(1,1) = 1;
+	dshape(2,2) = 1;
+	dshape(3,0) = -1;
+	dshape(3,1) = -1;
+	dshape(3,2) = -1;
+	break;
+      }
+    case PRISM:
+      {
+	dshape = 0;
+	dshape(0,0) = 1-p(2);
+	dshape(0,2) = -p(0);
+	dshape(1,1) = 1-p(2);
+	dshape(1,2) = -p(1);
+	dshape(2,0) = -(1-p(2));
+	dshape(2,1) = -(1-p(2));
+	dshape(2,2) = -(1-p(0)-p(1));
+
+	dshape(3,0) = p(2);
+	dshape(3,2) = p(0);
+	dshape(4,1) = p(2);
+	dshape(4,2) = p(1);
+	dshape(5,0) = -p(2);
+	dshape(5,1) = -p(2);
+	dshape(5,2) = 1-p(0)-p(1);
+	break;
+      }
+
+    default:
+      {
+	int np = GetNP();
+	double eps = 1e-6;
+	Vector shaper(np), shapel(np);
+	
+	for (int i = 1; i <= 3; i++)
+	  {
+	    Point3d pr(p), pl(p);
+	    pr.X(i) += eps;
+	    pl.X(i) -= eps;
+	    
+	    GetShapeNew (pr, shaper);
+	    GetShapeNew (pl, shapel);
+	    for (int j = 1; j <= np; j++)
+	      dshape.Elem(j, i) = (shaper.Get(j) - shapel.Get(j)) / (2 * eps);
+	  }
+      }
+    }
+}
+
+void Element :: 
+GetPointMatrix (const T_POINTS & points,
+		DenseMatrix & pmat) const
+{
+  int np = GetNP();
+  /*
+  if (pmat.Width() != np || pmat.Height() != 3)
+    {
+      cerr << "Element::GetPointMatrix: sizes don't fit" << endl;
+      return;
+    }
+  */
+  for (int i = 1; i <= np; i++)
+    {
+      const Point3d & p = points.Get(PNum(i));
+      pmat.Elem(1, i) = p.X();
+      pmat.Elem(2, i) = p.Y();
+      pmat.Elem(3, i) = p.Z();
+    }
+}
+
+
+
+
+
+
+double Element :: CalcJacobianBadness (const T_POINTS & points) const
+{
+  int i, j;
+  int nip = GetNIP();
+  static DenseMatrix trans(3,3);
+  static DenseMatrix pmat;
+  
+  pmat.SetSize (3, GetNP());
+  GetPointMatrix (points, pmat);
+
+  double err = 0;
+  for (i = 1; i <= nip; i++)
+    {
+      GetTransformation (i, pmat, trans);
+
+      // Frobenius norm
+      double frob = 0;
+      for (j = 1; j <= 9; j++)
+	frob += sqr (trans.Get(j));
+      frob = sqrt (frob);
+      frob /= 3;
+
+      double det = -trans.Det();
+      
+      if (det <= 0)
+	err += 1e12;
+      else
+	err += frob * frob * frob / det;
+    }
+
+  err /= nip;
+  return err;
+}
+
+double Element :: 
+CalcJacobianBadnessDirDeriv (const T_POINTS & points,
+			     int pi, Vec<3> & dir, double & dd) const
+{
+  int i, j, k, l;
+  int nip = GetNIP();
+  static DenseMatrix trans(3,3), dtrans(3,3), hmat(3,3);
+  static DenseMatrix pmat, vmat;
+  
+  pmat.SetSize (3, GetNP());
+  vmat.SetSize (3, GetNP());
+
+  GetPointMatrix (points, pmat);
+  
+  for (i = 1; i <= np; i++)
+    for (j = 1; j <= 3; j++)
+      vmat.Elem(j, i) = 0;
+  for (j = 1; j <= 3; j++)
+    vmat.Elem(j, pi) = dir(j-1);
+
+
+
+  double err = 0;
+  dd = 0;
+
+  for (i = 1; i <= nip; i++)
+    {
+      GetTransformation (i, pmat, trans);
+      GetTransformation (i, vmat, dtrans);
+
+
+      // Frobenius norm
+      double frob = 0;
+      for (j = 1; j <= 9; j++)
+	frob += sqr (trans.Get(j));
+      frob = sqrt (frob);
+      
+      double dfrob = 0;
+      for (j = 1; j <= 9; j++)
+	dfrob += trans.Get(j) * dtrans.Get(j);
+      dfrob = dfrob / frob;
+      
+      frob /= 3;      
+      dfrob /= 3;
+
+      
+      double det = trans.Det();
+      double ddet = 0;
+      
+      for (j = 1; j <= 3; j++)
+	{
+	  hmat = trans;
+	  for (k = 1; k <= 3; k++)
+	    hmat.Elem(k, j) = dtrans.Get(k, j);
+	  ddet += hmat.Det();
+	}
+
+
+      det *= -1;
+      ddet *= -1;
+
+      
+      if (det <= 0)
+	err += 1e12;
+      else
+	{
+	  err += frob * frob * frob / det;
+	  dd += (3 * frob * frob * dfrob * det - frob * frob * frob * ddet) / (det * det);
+	}
+    }
+
+  err /= nip;
+  dd /= nip;
+  return err;
+}
+
+double Element :: 
+CalcJacobianBadnessGradient (const T_POINTS & points,
+			     int pi, Vec<3> & grad) const
+{
+  int i, j, k, l;
+  int nip = GetNIP();
+  static DenseMatrix trans(3,3), dtrans(3,3), hmat(3,3);
+  static DenseMatrix pmat, vmat;
+  
+  pmat.SetSize (3, GetNP());
+  vmat.SetSize (3, GetNP());
+
+  GetPointMatrix (points, pmat);
+  
+  for (i = 1; i <= np; i++)
+    for (j = 1; j <= 3; j++)
+      vmat.Elem(j, i) = 0;
+  for (j = 1; j <= 3; j++)
+    vmat.Elem(j, pi) = 1.;
+
+
+  double err = 0;
+
+  double dfrob[3];
+
+  grad = 0;
+
+  for (i = 1; i <= nip; i++)
+    {
+      GetTransformation (i, pmat, trans);
+      GetTransformation (i, vmat, dtrans);
+ 
+      // Frobenius norm
+      double frob = 0;
+      for (j = 1; j <= 9; j++)
+	frob += sqr (trans.Get(j));
+      frob = sqrt (frob);
+
+      for(k = 0; k<3; k++)
+	{
+	  dfrob[k] = 0;
+	  for (j = 1; j <= 3; j++)
+	    dfrob[k] += trans.Get(k+1,j) * dtrans.Get(k+1,j);
+	  dfrob[k] = dfrob[k] / (3.*frob);
+	}
+
+      frob /= 3;      
+
+      double det = trans.Det();
+      double ddet[3]; // = 0;
+      
+      for(k=1; k<=3; k++)
+	{
+	  int km1 = (k > 1) ? (k-1) : 3;
+	  int kp1 = (k < 3) ? (k+1) : 1;
+	  ddet[k-1] = 0;
+	  for(j=1; j<=3; j++)
+	    {
+	      int jm1 = (j > 1) ? (j-1) : 3;
+	      int jp1 = (j < 3) ? (j+1) : 1;
+	      
+	      ddet[k-1] += (-1.)* dtrans.Get(k,j) * ( trans.Get(km1,jm1)*trans.Get(kp1,jp1) - 
+						     trans.Get(km1,jp1)*trans.Get(kp1,jm1) );
+	    }
+	}
+
+      
+      det *= -1;
+      
+      if (det <= 0)
+	err += 1e12;
+      else
+	{
+	  err += frob * frob * frob / det;
+	  double fac = (frob * frob)/(det * det);
+	  for(j=0; j<3; j++)
+	    grad(j) += fac * (3 * dfrob[j] * det - frob * ddet[j]);
+	}
+    }
+
+  err /= nip;
+  grad *= 1./nip;
+  return err;
+}
+
+
+
+
+
+
+void Element :: ComputeIntegrationPointData () const
+{
+  switch (GetType())
+    {
+    case TET: if (ipdtet.Size()) return; break;
+    case TET10: if (ipdtet10.Size()) return; break;
+    default:
+      PrintSysError ("Element::ComputeIntegrationPoint, illegal type ", int(typ));
+    }
+
+  switch (GetType())
+    {
+    case TET: ipdtet.SetSize(GetNIP()); break;
+    case TET10: ipdtet10.SetSize(GetNIP()); break;
+    }
+
+
+  for (int i = 1; i <= GetNIP(); i++)
+    {
+      IntegrationPointData * ipd = new IntegrationPointData;
+      GetIntegrationPoint (i, ipd->p, ipd->weight);
+      ipd->shape.SetSize(GetNP());
+      ipd->dshape.SetSize(3, GetNP());
+
+      GetShape (ipd->p, ipd->shape);
+      GetDShape (ipd->p, ipd->dshape);
+
+      switch (GetType())
+	{
+	case TET: ipdtet.Elem(i).Reset(ipd); break;
+	case TET10: ipdtet10.Elem(i).Reset(ipd); break;
+	default:
+	  PrintSysError ("Element::ComputeIntegrationPoint(2), illegal type ", int(typ));
+	}
+    }
+}
+
+
+
+
+
+
+
+
+FaceDescriptor ::  FaceDescriptor()
+{ 
+  surfnr = domin = domout  = bcprop = 0; 
+  domin_singular = domout_singular = 0.;
+  tlosurf = -1; 
+  bcname = 0;
+  firstelement = -1;
+}
+
+FaceDescriptor ::  FaceDescriptor(const FaceDescriptor& other)
+  : surfnr(other.surfnr), domin(other.domin), domout(other.domout),
+    tlosurf(other.tlosurf), bcprop(other.bcprop), bcname(other.bcname),
+    domin_singular(other.domin_singular), domout_singular(other.domout_singular)
+{ 
+  firstelement = -1;
+}
+
+FaceDescriptor :: 
+FaceDescriptor(int surfnri, int domini, int domouti, int tlosurfi)
+{ 
+  surfnr = surfnri; 
+  domin = domini; 
+  domout = domouti;
+  tlosurf = tlosurfi; 
+  bcprop = surfnri;
+  domin_singular = domout_singular = 0.;
+  bcname = 0;
+  firstelement = -1;
+}
+
+FaceDescriptor :: FaceDescriptor(const Segment & seg)
+{ 
+  surfnr = seg.si; 
+  domin = seg.domin+1;
+  domout = seg.domout+1;
+  tlosurf = seg.tlosurf+1;
+  bcprop = 0;
+  domin_singular = domout_singular = 0.;
+  bcname = 0;
+  firstelement = -1;
+}
+
+int FaceDescriptor ::  SegmentFits (const Segment & seg)
+{
+  return
+    surfnr == seg.si &&
+    domin == seg.domin+1 &&
+    domout == seg.domout+1  &&
+    tlosurf == seg.tlosurf+1;
+}
+
+
+string FaceDescriptor :: GetBCName () const
+{
+  if ( bcname )
+    return *bcname;
+  else 
+    return "default";
+  
+}
+
+/*
+void FaceDescriptor :: SetBCName (string * bcn)
+{
+  bcname = bcn;
+}
+*/
+
+
+ostream & operator<<(ostream  & s, const FaceDescriptor & fd)
+{
+  s << "surfnr = " << fd.surfnr 
+    << ", domin = " << fd.domin
+    << ", domout = " << fd.domout
+    << ", tlosurf = " << fd.tlosurf
+    << ", bcprop = " << fd.bcprop
+    << ", domin_sing = " << fd.domin_singular
+    << ", domout_sing = " << fd.domout_singular;
+  return s;
+}
+
+
+
+
+
+
+Identifications :: Identifications (Mesh & amesh)
+  : mesh(amesh)
+{
+  identifiedpoints = new INDEX_2_HASHTABLE<int>(100);
+  identifiedpoints_nr = new INDEX_3_HASHTABLE<int>(100);
+  maxidentnr = 0;
+}
+
+Identifications :: ~Identifications ()
+{
+  delete identifiedpoints;
+  delete identifiedpoints_nr;
+}
+
+void Identifications :: Delete ()
+{
+  delete identifiedpoints;
+  identifiedpoints = new INDEX_2_HASHTABLE<int>(100);
+  delete identifiedpoints_nr;
+  identifiedpoints_nr = new INDEX_3_HASHTABLE<int>(100);
+  maxidentnr = 0;
+}
+
+void Identifications :: Add (PointIndex pi1, PointIndex pi2, int identnr)
+{
+  //  (*testout) << "Identification::Add, pi1 = " << pi1 << ", pi2 = " << pi2 << ", identnr = " << identnr << endl;
+  INDEX_2 pair (pi1, pi2);
+  identifiedpoints->Set (pair, identnr);
+
+  INDEX_3 tripl (pi1, pi2, identnr);
+  identifiedpoints_nr->Set (tripl, 1);
+
+  if (identnr > maxidentnr) maxidentnr = identnr;
+
+  if (identnr+1 > idpoints_table.Size())
+    idpoints_table.ChangeSize (identnr+1);
+  idpoints_table.Add (identnr, pair);
+  
+  //  timestamp = NextTimeStamp();
+}
+
+int Identifications :: Get (PointIndex pi1, PointIndex pi2) const
+{
+  INDEX_2 pair(pi1, pi2);
+  if (identifiedpoints->Used (pair))
+    return identifiedpoints->Get(pair);
+  else
+    return 0;
+}
+
+bool Identifications :: Get (PointIndex pi1, PointIndex pi2, int nr) const
+{
+  INDEX_3 tripl(pi1, pi2, nr);
+  if (identifiedpoints_nr->Used (tripl))
+    return 1;
+  else
+    return 0;
+}
+
+
+
+int Identifications :: GetSymmetric (PointIndex pi1, PointIndex pi2) const
+{
+  INDEX_2 pair(pi1, pi2);
+  if (identifiedpoints->Used (pair))
+    return identifiedpoints->Get(pair);
+
+  pair = INDEX_2 (pi2, pi1);
+  if (identifiedpoints->Used (pair))
+    return identifiedpoints->Get(pair);
+
+  return 0;
+}
+
+
+void Identifications :: GetMap (int identnr, ARRAY<int,PointIndex::BASE> & identmap, bool symmetric) const
+{
+  identmap.SetSize (mesh.GetNP());
+  identmap = 0;
+
+  if (identnr)
+    for (int i = 0; i < idpoints_table[identnr].Size(); i++)
+      {
+	INDEX_2 pair = idpoints_table[identnr][i];
+	identmap[pair.I1()] = pair.I2();
+	if(symmetric)
+	  identmap[pair.I2()] = pair.I1();
+      }
+
+  else
+    {
+      cout << "getmap, identnr = " << identnr << endl;
+
+      for (int i = 1; i <= identifiedpoints_nr->GetNBags(); i++)
+	for (int j = 1; j <= identifiedpoints_nr->GetBagSize(i); j++)
+	  {
+	    INDEX_3 i3;
+	    int dummy;
+	    identifiedpoints_nr->GetData (i, j, i3, dummy);
+	    
+	    if (i3.I3() == identnr || !identnr)
+	      {
+		identmap.Elem(i3.I1()) = i3.I2();
+		if(symmetric)
+		  identmap.Elem(i3.I2()) = i3.I1();
+	      }
+	  }  
+    }
+
+}
+
+
+void Identifications :: GetPairs (int identnr, 
+				  ARRAY<INDEX_2> & identpairs) const
+{
+  identpairs.SetSize(0);
+  
+  if (identnr == 0)
+    for (int i = 1; i <= identifiedpoints->GetNBags(); i++)
+      for (int j = 1; j <= identifiedpoints->GetBagSize(i); j++)
+	{
+	  INDEX_2 i2;
+	  int nr;
+	  identifiedpoints->GetData (i, j, i2, nr);
+	  identpairs.Append (i2);
+	}  
+  else
+    for (int i = 1; i <= identifiedpoints_nr->GetNBags(); i++)
+      for (int j = 1; j <= identifiedpoints_nr->GetBagSize(i); j++)
+	{
+	  INDEX_3 i3;
+	  int dummy;
+	  identifiedpoints_nr->GetData (i, j, i3 , dummy);
+	  
+	  if (i3.I3() == identnr)
+	    identpairs.Append (INDEX_2(i3.I1(), i3.I2()));
+	}  
+}
+
+
+void Identifications :: SetMaxPointNr (int maxpnum)
+{
+  for (int i = 1; i <= identifiedpoints->GetNBags(); i++)
+    for (int j = 1; j <= identifiedpoints->GetBagSize(i); j++)
+      {
+	INDEX_2 i2;
+	int nr;
+	identifiedpoints->GetData (i, j, i2, nr);
+	
+	if (i2.I1() > maxpnum || i2.I2() > maxpnum)
+	  {
+	    i2.I1() = i2.I2() = -1;
+	    identifiedpoints->SetData (i, j, i2, -1);	    
+	  }
+      }
+}
+
+
+void Identifications :: Print (ostream & ost) const
+{
+  ost << "Identifications:" << endl;
+  ost << "pairs: " << endl << *identifiedpoints << endl;
+  ost << "pairs and nr: " << endl << *identifiedpoints_nr << endl;
+  ost << "table: " << endl << idpoints_table << endl;
+}
+
+
+MeshingParameters :: MeshingParameters ()
+{
+  optimize3d = "cmdmustm";
+  //optimize3d = "cmdmstm";
+  optsteps3d = 3;
+  optimize2d = "smsmsmSmSmSm";
+  optsteps2d = 3;
+  opterrpow = 2;
+  blockfill = 1;
+  filldist = 0.1;
+  safety = 5;
+  relinnersafety = 3;
+  uselocalh = 1;
+  grading = 0.3;
+  delaunay = 1;
+  maxh = 1e10;
+  minh = 0;
+  meshsizefilename = NULL;
+  startinsurface = 0;
+  checkoverlap = 1;
+  checkoverlappingboundary = 1;
+  checkchartboundary = 1;
+  curvaturesafety = 2;
+  segmentsperedge = 1;
+  parthread = 0;
+
+  elsizeweight = 0.2;
+  giveuptol2d = 200;
+  giveuptol = 10;
+  maxoutersteps = 10;
+  starshapeclass = 5;
+  baseelnp = 0;
+  sloppy = 1;
+
+  badellimit = 175;
+  check_impossible = 0;
+  secondorder = 0;
+}
+
+void MeshingParameters :: Print (ostream & ost) const
+{
+  ost << "Meshing parameters: " << endl
+      << "optimize3d = " << optimize3d << endl
+      << "optsteps3d = " << optsteps3d << endl
+      << " optimize2d = " <<  optimize2d << endl
+      << " optsteps2d = " <<  optsteps2d << endl
+      << " opterrpow = " <<  opterrpow << endl
+      << " blockfill = " <<  blockfill << endl
+      << " filldist = " <<  filldist << endl
+      << " safety = " <<  safety << endl
+      << " relinnersafety = " <<  relinnersafety << endl
+      << " uselocalh = " <<  uselocalh << endl
+      << " grading = " <<  grading << endl
+      << " delaunay = " <<  delaunay << endl
+      << " maxh = " <<  maxh << endl;
+  if(meshsizefilename)
+    ost << " meshsizefilename = " <<  meshsizefilename << endl;
+  else
+    ost << " meshsizefilename = NULL" << endl;
+  ost << " startinsurface = " <<  startinsurface << endl
+      << " checkoverlap = " <<  checkoverlap << endl
+      << " checkchartboundary = " <<  checkchartboundary << endl
+      << " curvaturesafety = " <<  curvaturesafety << endl
+      << " segmentsperedge = " <<  segmentsperedge << endl
+      << " parthread = " <<  parthread << endl
+      << " elsizeweight = " <<  elsizeweight << endl
+      << " giveuptol2d = " <<  giveuptol2d << endl
+      << " giveuptol = " <<  giveuptol << endl
+      << " maxoutersteps = " <<  maxoutersteps << endl
+      << " starshapeclass = " <<  starshapeclass << endl
+      << " baseelnp        = " <<  baseelnp        << endl
+      << " sloppy = " <<  sloppy << endl
+      << " badellimit = " <<  badellimit << endl
+      << " secondorder = " <<  secondorder << endl
+      << " elementorder = " <<  elementorder << endl
+      << " quad = " <<  quad << endl
+      << " inverttets = " <<  inverttets << endl
+      << " inverttrigs = " <<  inverttrigs << endl;
+}
+
+void MeshingParameters :: CopyFrom(const MeshingParameters & other)
+{
+  //strcpy(optimize3d,other.optimize3d); 
+  optimize3d = other.optimize3d;
+  optsteps3d = other.optsteps3d;
+  //strcpy(optimize2d,other.optimize2d); 
+  optimize2d = other.optimize2d;
+  optsteps2d = other.optsteps2d;
+  opterrpow = other.opterrpow;
+  blockfill = other.blockfill;
+  filldist = other.filldist;
+  safety = other.safety;
+  relinnersafety = other.relinnersafety;
+  uselocalh = other.uselocalh;
+  grading = other.grading;
+  delaunay = other.delaunay;
+  maxh = other.maxh;
+  //strcpy(const_cast<char*>(meshsizefilename), other.meshsizefilename);
+  //const_cast<char*>(meshsizefilename) = other.meshsizefilename; //???
+  startinsurface = other.startinsurface;
+  checkoverlap = other.checkoverlap;
+  checkoverlappingboundary = other.checkoverlappingboundary;
+  checkchartboundary = other.checkchartboundary;
+  curvaturesafety = other.curvaturesafety;
+  segmentsperedge = other.segmentsperedge;
+  parthread = other.parthread;
+  elsizeweight = other.elsizeweight;
+  giveuptol2d = other.giveuptol2d;
+  giveuptol = other.giveuptol;
+  maxoutersteps = other.maxoutersteps;
+  starshapeclass = other.starshapeclass;
+  baseelnp = other.baseelnp;       
+  sloppy = other.sloppy;
+  badellimit = other.badellimit;
+  secondorder = other.secondorder;
+  elementorder = other.elementorder;
+  quad = other.quad;
+  inverttets = other.inverttets;
+  inverttrigs = other.inverttrigs;
+}
+
+
+DebugParameters :: DebugParameters ()
+{
+  slowchecks = 0;
+  haltsuccess = 0;
+  haltnosuccess = 0;
+  haltlargequalclass = 0;
+  haltsegment = 0;
+  haltsegmentp1 = 0;
+  haltsegmentp2 = 0;
+};
+
+
+
+}
+
diff --git a/contrib/Netgen/libsrc/meshing/meshtype.hpp b/contrib/Netgen/libsrc/meshing/meshtype.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..fdae56b4546774e85ac67c666241e53c18979d08
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/meshtype.hpp
@@ -0,0 +1,1229 @@
+#ifndef MESHTYPE
+#define MESHTYPE
+
+
+/**************************************************************************/
+/* File:   meshtype.hpp                                                   */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   01. Okt. 95                                                    */
+/**************************************************************************/
+
+/*
+    Classes for NETGEN
+*/
+
+
+enum ELEMENT_TYPE { 
+  SEGMENT = 1, SEGMENT3 = 2,
+  TRIG = 10, QUAD=11, TRIG6 = 12, QUAD6 = 13, QUAD8 = 14,
+  TET = 20, TET10 = 21, 
+  PYRAMID = 22, PRISM = 23, PRISM12 = 24,
+  HEX = 25
+};
+
+typedef int ELEMENT_EDGE[2];      // initial point, end point
+typedef int ELEMENT_FACE[4];      // points, last one is -1 for trig
+
+
+#define ELEMENT_MAXPOINTS 12
+#define ELEMENT2D_MAXPOINTS 8
+
+
+enum POINTTYPE { FIXEDPOINT = 1, EDGEPOINT = 2, SURFACEPOINT = 3, INNERPOINT = 4 };
+enum ELEMENTTYPE { FREEELEMENT, FIXEDELEMENT };
+enum OPTIMIZEGOAL { OPT_QUALITY, OPT_CONFORM, OPT_REST, OPT_WORSTCASE, OPT_LEGAL };
+
+
+
+extern int GetTimeStamp();
+extern int NextTimeStamp();
+
+class PointGeomInfo
+{
+public:
+  int trignum;   // for STL Meshing
+  double u, v;   // for OCC Meshing
+
+  PointGeomInfo () 
+    : trignum(-1), u(0), v(0) { ; }
+};
+
+inline ostream & operator<< (ostream & ost, const PointGeomInfo & gi)
+{
+  return (ost << gi.trignum << " " << gi.u << " " << gi.v);
+}
+
+inline istream & operator>> (istream & ist, PointGeomInfo & gi)
+{
+  return (ist >> gi.trignum >> gi.u >> gi.v);
+}
+
+
+
+#define MULTIPOINTGEOMINFO_MAX 100
+class MultiPointGeomInfo
+{
+  int cnt;
+  PointGeomInfo mgi[MULTIPOINTGEOMINFO_MAX];
+public:
+  MultiPointGeomInfo () { cnt = 0; }
+  int AddPointGeomInfo (const PointGeomInfo & gi);
+  void Init () { cnt = 0; }
+  void DeleteAll () { cnt = 0; }
+
+  int GetNPGI () const { return cnt; }
+  const PointGeomInfo & GetPGI (int i) const { return mgi[i-1]; }
+};
+
+
+class EdgePointGeomInfo
+{
+public:
+  int edgenr;
+  int body;    // for ACIS
+  double u, v; // for OCC Meshing
+  double dist; // for 2d meshing
+
+public:
+  EdgePointGeomInfo ()
+    : edgenr(0), body(0), dist(0.0), u(0.0), v(0.0) { ; }
+
+
+  EdgePointGeomInfo & operator= (const EdgePointGeomInfo & gi2)
+  {
+    edgenr = gi2.edgenr;  
+    body = gi2.body;
+    dist = gi2.dist;
+    u = gi2.u; v = gi2.v;
+    return *this;
+  }
+};
+
+inline ostream & operator<< (ostream & ost, const EdgePointGeomInfo & gi)
+{
+  ost << "epgi: edgnr=" << gi.edgenr << ", dist=" << gi.dist;
+  return ost;
+}
+
+
+
+
+
+class PointIndex
+{
+  int i;
+public:
+  PointIndex () { ; }
+  PointIndex (int ai) : i(ai) { ; }
+  PointIndex & operator= (const PointIndex &ai) { i = ai.i; return *this; }
+  PointIndex & operator= (int ai) { i = ai; return *this; }
+  operator int () const { return i; }
+  int GetInt () const { return i; }
+  PointIndex operator++ (int) { int hi = i; i++; return PointIndex(hi); }
+  PointIndex operator-- (int) { int hi = i; i--; return PointIndex(hi); }
+
+#ifdef BASE0
+  enum { BASE = 0 };
+#else
+  enum { BASE = 1 };
+#endif  
+};
+
+inline istream & operator>> (istream & ist, PointIndex & pi)
+{
+  int i; ist >> i; pi = i; return ist;
+}
+
+inline ostream & operator<< (ostream & ost, const PointIndex & pi)
+{
+  return (ost << pi.GetInt());
+}
+
+
+
+
+class ElementIndex
+{
+  int i;
+public:
+  ElementIndex () { ; }
+  ElementIndex (int ai) : i(ai) { ; }
+  ElementIndex & operator= (const ElementIndex & ai) { i = ai.i; return *this; }
+  ElementIndex & operator= (int ai) { i = ai; return *this; }
+  operator int () const { return i; }
+  ElementIndex & operator++ (int) { i++; return *this; }
+  ElementIndex & operator-- (int) { i--; return *this; }
+};
+
+inline istream & operator>> (istream & ist, ElementIndex & pi)
+{
+  int i; ist >> i; pi = i; return ist;
+}
+
+inline ostream & operator<< (ostream & ost, const ElementIndex & pi)
+{
+  return (ost << int(pi));
+}
+
+
+class SurfaceElementIndex
+{
+  int i;
+public:
+  SurfaceElementIndex () { ; }
+  SurfaceElementIndex (int ai) : i(ai) { ; }
+  SurfaceElementIndex & operator= (const SurfaceElementIndex & ai) 
+    { i = ai.i; return *this; }
+  SurfaceElementIndex & operator= (int ai) { i = ai; return *this; }
+  operator int () const { return i; }
+  SurfaceElementIndex & operator++ (int) { i++; return *this; }
+  SurfaceElementIndex & operator-- (int) { i--; return *this; }
+};
+
+inline istream & operator>> (istream & ist, SurfaceElementIndex & pi)
+{
+  int i; ist >> i; pi = i; return ist;
+}
+
+inline ostream & operator<< (ostream & ost, const SurfaceElementIndex & pi)
+{
+  return (ost << int(pi));
+}
+
+class SegmentIndex
+{
+  int i;
+public:
+  SegmentIndex () { ; }
+  SegmentIndex (int ai) : i(ai) { ; }
+  SegmentIndex & operator= (const SegmentIndex & ai) 
+    { i = ai.i; return *this; }
+  SegmentIndex & operator= (int ai) { i = ai; return *this; }
+  operator int () const { return i; }
+  SegmentIndex & operator++ (int) { i++; return *this; }
+  SegmentIndex & operator-- (int) { i--; return *this; }
+};
+
+inline istream & operator>> (istream & ist, SegmentIndex & pi)
+{
+  int i; ist >> i; pi = i; return ist;
+}
+
+inline ostream & operator<< (ostream & ost, const SegmentIndex & pi)
+{
+  return (ost << int(pi));
+}
+
+
+
+
+/**
+   Point in the mesh.
+   Contains layer (a new feature in 4.3 for overlapping meshes.
+ */
+class MeshPoint : public Point<3>
+{
+  int layer;
+  double singular; // singular factor for hp-refinement
+  POINTTYPE type;
+
+#ifdef PARALLEL
+  bool isghost;
+#endif
+
+public:
+  MeshPoint () : layer(1), singular(0.), type(INNERPOINT) 
+{ 
+#ifdef PARALLEL
+  isghost = 0;
+#endif
+  ;
+}
+
+  MeshPoint (const Point<3> & ap, int alayer = 1, POINTTYPE apt = INNERPOINT)
+    : Point<3> (ap), layer(alayer), singular(0.),type(apt) 
+  { 
+#ifdef PARALLEL
+    isghost = 0;
+#endif  
+    ;
+  }
+  
+  void SetPoint (const Point<3> & ap)
+  { 
+    Point<3>::operator= (ap); 
+    layer = 0; 
+    singular = 0; 
+#ifdef PARALLEL
+    isghost = 0;
+#endif
+  }
+
+  int GetLayer() const { return layer; }
+
+  POINTTYPE Type() const { return type; }
+  void SetType(POINTTYPE at) { type = at; }
+ 
+  double Singularity() const { return singular; }
+  void Singularity(double s) { singular = s; }
+  bool IsSingular() const { return (singular != 0.0); }
+
+#ifdef PARALLEL
+  bool IsGhost () const { return isghost; }
+  void SetGhost ( bool aisghost ) { isghost = aisghost; }
+#endif
+
+};
+
+ostream & operator<<(ostream  & s, const MeshPoint & pt);
+
+
+
+
+typedef MoveableArray<MeshPoint,PointIndex::BASE> T_POINTS;
+// typedef ARRAY<MeshPoint,PointIndex::BASE> T_POINTS;
+
+
+class Element2d;
+ostream & operator<<(ostream  & s, const Element2d & el);
+
+/**
+  Triangle element for surface mesh generation.
+ */
+class Element2d
+{ 
+  /// point numbers
+  PointIndex pnum[ELEMENT2D_MAXPOINTS];
+  /// geom info of points
+  PointGeomInfo geominfo[ELEMENT2D_MAXPOINTS];
+
+  /// surface nr
+  int index:16;
+  ///
+  ELEMENT_TYPE typ:6;
+  /// number of points
+  unsigned int np:4;
+  bool badel:1;
+  bool refflag:1;  // marked for refinement
+  bool strongrefflag:1;
+  bool deleted:1;  // element is deleted
+
+  /// order for hp-FEM
+  unsigned int orderx:6;
+  unsigned int ordery:6;
+
+#ifdef PARALLEL
+  bool isghost;
+  int partitionNumber; 
+#endif
+
+  /// a linked list for all segments in the same face
+  SurfaceElementIndex next;
+
+public:
+  ///
+  Element2d ();
+  ///
+  Element2d (int anp);
+  ///
+  Element2d (ELEMENT_TYPE type);
+  ///
+  Element2d (int pi1, int pi2, int pi3);
+  ///
+  Element2d (int pi1, int pi2, int pi3, int pi4);
+  ///
+  ELEMENT_TYPE GetType () const { return typ; }
+  /// 
+  void SetType (ELEMENT_TYPE atyp)
+  {
+    typ = atyp;
+    switch (typ)
+      {
+      case TRIG: np = 3; break;
+      case QUAD: np = 4; break;
+      case TRIG6: np = 6; break;
+      case QUAD6: np = 6; break;
+      case QUAD8: np = 8; break;
+      default:
+	PrintSysError ("Element2d::SetType, illegal type ", typ);
+      }
+  }
+  ///
+  int GetNP() const { return np; }
+  ///
+  int GetNV() const
+  {
+    switch (typ)
+      {
+      case TRIG:
+      case TRIG6: return 3;
+
+      case QUAD:
+      case QUAD8:
+      case QUAD6: return 4;
+      default:
+#ifdef DEBUG
+	PrintSysError ("element2d::GetNV not implemented for typ", typ)
+#endif
+	;
+      }
+    return np;
+  }
+
+  ///
+  PointIndex & operator[] (int i) { return pnum[i]; }
+  ///
+  const PointIndex & operator[] (int i) const { return pnum[i]; }
+
+  ///
+  PointIndex & PNum (int i) { return pnum[i-1]; }
+  ///
+  const PointIndex & PNum (int i) const { return pnum[i-1]; }
+  ///
+  PointIndex & PNumMod (int i) { return pnum[(i-1) % np]; }
+  ///
+  const PointIndex & PNumMod (int i) const { return pnum[(i-1) % np]; }
+  ///
+
+  ///
+  PointGeomInfo & GeomInfoPi (int i) { return geominfo[i-1]; }
+  ///
+  const PointGeomInfo & GeomInfoPi (int i) const { return geominfo[i-1]; }
+  ///
+  PointGeomInfo & GeomInfoPiMod (int i) { return geominfo[(i-1) % np]; }
+  ///
+  const PointGeomInfo & GeomInfoPiMod (int i) const { return geominfo[(i-1) % np]; }
+
+
+  void SetIndex (int si) { index = si; }
+  ///
+  int GetIndex () const { return index; }
+
+  int GetOrder () const { return orderx; }
+  void SetOrder (int aorder) { orderx = ordery = aorder; }
+
+
+  void GetOrder (int & ox, int & oy) const { ox = orderx, oy =ordery;};
+  void GetOrder (int & ox, int & oy, int & oz) const { ox = orderx; oy = ordery; oz=0; }
+  void SetOrder (int ox, int oy, int  oz) { orderx = ox; ordery = oy;}
+  void SetOrder (int ox, int oy) { orderx = ox; ordery = oy;}
+
+
+  ///
+  void GetBox (const T_POINTS & points, Box3d & box) const;
+  /// invert orientation
+  inline void Invert ();
+  ///
+  void Invert2 ();
+  /// first point number is smallest
+  inline void NormalizeNumbering ();
+  ///
+  void NormalizeNumbering2 ();
+
+  bool BadElement() const { return badel; }
+
+  friend ostream & operator<<(ostream  & s, const Element2d & el);
+  friend class Mesh;
+
+
+  /// get number of 'integration points'
+  int GetNIP () const;
+  void GetIntegrationPoint (int ip, Point2d & p, double & weight) const;
+  void GetTransformation (int ip, const ARRAY<Point2d> & points,
+			  class DenseMatrix & trans) const;
+  void GetTransformation (int ip, class DenseMatrix & pmat,
+			  class DenseMatrix & trans) const;
+
+  void GetShape (const Point2d & p, class Vector & shape) const;
+  void GetShapeNew (const Point<2> & p, class FlatVector & shape) const;
+  /// matrix 2 * np
+  void GetDShape (const Point2d & p, class DenseMatrix & dshape) const;
+  void GetDShapeNew (const Point<2> & p, class MatrixFixWidth<2> & dshape) const;
+  /// matrix 2 * np
+  void GetPointMatrix (const ARRAY<Point2d> & points,
+		       class DenseMatrix & pmat) const; 
+
+  void ComputeIntegrationPointData () const;
+  
+
+  double CalcJacobianBadness (const ARRAY<Point2d> & points) const;
+  double CalcJacobianBadness (const T_POINTS & points, 
+			      const Vec<3> & n) const;
+  double CalcJacobianBadnessDirDeriv (const ARRAY<Point2d> & points,
+				      int pi, Vec2d & dir, double & dd) const;
+
+
+
+  void Delete () { deleted = 1; pnum[0] = pnum[1] = pnum[2] = pnum[3] = PointIndex::BASE-1; }
+  bool IsDeleted () const 
+  {
+#ifdef DEBUG
+    if (pnum[0] < PointIndex::BASE && !deleted)
+      cerr << "Surfelement has illegal pnum, but not marked as deleted" << endl;
+#endif    
+    return deleted; 
+  }
+
+  void SetRefinementFlag (bool rflag = 1) 
+  { refflag = rflag; }
+  bool TestRefinementFlag () const
+  { return refflag; }
+
+  void SetStrongRefinementFlag (bool rflag = 1) 
+  { strongrefflag = rflag; }
+  bool TestStrongRefinementFlag () const
+  { return strongrefflag; }
+
+  
+  bool operator==(const Element2d & el2) const;
+
+  int HasFace(const Element2d& el) const;
+  ///
+  int meshdocval;
+  ///
+  int hp_elnr;
+
+#ifdef PARALLEL
+  bool IsGhost () const { return isghost; }
+  void SetGhost ( bool aisghost ) { isghost = aisghost; }
+
+  // by JS, only for 2D meshes ????
+  int GetPartition () const { return partitionNumber; }
+  void SetPartition (int nr) { partitionNumber = nr; }; 
+#endif
+
+};
+
+
+
+
+class IntegrationPointData
+{
+public:
+  Point<3> p;
+  double weight;
+  Vector shape;
+  DenseMatrix dshape;
+};
+
+
+
+
+class Element;
+ostream & operator<<(ostream  & s, const Element & el);
+
+
+
+/**
+  Volume element
+ */
+class Element
+{
+private:
+  /// point numbers
+  PointIndex pnum[ELEMENT_MAXPOINTS];
+  ///
+  ELEMENT_TYPE typ:6;
+  /// number of points (4..tet, 5..pyramid, 6..prism, 8..hex, 10..quad tet, 12..quad prism)
+  int np:5;
+  ///
+  class flagstruct { 
+  public:
+    bool marked:1;  // marked for refinement
+    bool badel:1;   // angles worse then limit
+    bool reverse:1; // for refinement a la Bey
+    bool illegal:1; // illegal, will be split or swaped 
+    bool illegal_valid:1; // is illegal-flag valid ?
+    bool badness_valid:1; // is badness valid ?
+    bool refflag:1;     // mark element for refinement
+    bool strongrefflag:1;
+    bool deleted:1;   // element is deleted, will be removed from array
+    bool fixed:1;     // don't change element in optimization
+  };
+
+  /// sub-domain index
+  short int index;
+  /// order for hp-FEM
+  unsigned int orderx:6;
+  unsigned int ordery:6;
+  unsigned int orderz:6;
+  /* unsigned int levelx:6;
+  unsigned int levely:6;
+  unsigned int levelz:6; */ 
+  /// stored shape-badness of element
+  float badness;
+  
+#ifdef PARALLEL
+  /// number of partition for parallel computation 
+  int partitionNumber;
+  bool isghost;
+#endif
+
+public:
+  flagstruct flags;
+
+  ///
+  Element ();
+  ///
+  Element (int anp);
+  ///
+  Element (ELEMENT_TYPE type);
+  ///
+  Element & operator= (const Element & el2);
+  
+  ///
+  void SetNP (int anp);
+  ///
+  void SetType (ELEMENT_TYPE atyp);
+  ///
+  int GetNP () const { return np; }
+  ///
+  int GetNV() const
+  {
+    switch (typ)
+      {
+      case TET: 
+      case TET10: 
+        return 4;
+      case PRISM12: 
+      case PRISM: 
+        return 6; 
+      case PYRAMID:
+        return 5;
+      case HEX:
+        return 8;
+      default:
+#ifdef DEBUG
+	PrintSysError ("Element3d::GetNV not implemented for typ ", typ)
+#endif
+	  ;
+      }
+    return np;
+  }
+
+  bool operator==(const Element & el2) const;
+
+  // old style:
+  int NP () const { return np; }
+
+  ///
+  ELEMENT_TYPE GetType () const { return typ; }
+
+  ///
+  PointIndex & operator[] (int i) { return pnum[i]; }
+  ///
+  const PointIndex & operator[] (int i) const { return pnum[i]; }
+
+  ///
+  PointIndex & PNum (int i) { return pnum[i-1]; }
+  ///
+  const PointIndex & PNum (int i) const { return pnum[i-1]; }
+  ///
+  PointIndex & PNumMod (int i) { return pnum[(i-1) % np]; }
+  ///
+  const PointIndex & PNumMod (int i) const { return pnum[(i-1) % np]; }
+  
+  ///
+  void SetIndex (int si) { index = si; }
+  ///
+  int GetIndex () const { return index; }
+
+  int GetOrder () const { return orderx; }
+  void SetOrder (const int aorder) ; 
+
+  void GetOrder (int & ox, int & oy, int & oz) const { ox = orderx; oy = ordery; oz = orderz; }
+  void SetOrder (const int ox, const int oy, const int oz);
+  // void GetLevel (int & ox, int & oy, int & oz) const { ox = levelx; oy = levely; oz = levelz; }
+  // void SetLevel (int ox, int oy, int oz) { levelx = ox; levely = oy; levelz = oz; }
+
+
+  ///
+  void GetBox (const T_POINTS & points, Box3d & box) const;
+  /// Calculates Volume of elemenet
+  double Volume (const T_POINTS & points) const;
+  ///
+  virtual void Print (ostream & ost) const;
+  ///
+  int GetNFaces () const
+    {
+      switch (typ)
+	{
+	case TET: 
+	case TET10: return 4;
+	case PYRAMID: return 5;
+	case PRISM: 
+	case PRISM12: return 5;
+	default:
+#ifdef DEBUG
+	  PrintSysError ("element3d::GetNFaces not implemented for typ", typ)
+#endif
+	    ;
+	}
+      return 0;
+    }
+  ///
+  inline void GetFace (int i, Element2d & face) const;
+  ///
+  void GetFace2 (int i, Element2d & face) const;
+  ///
+  void Invert ();
+
+  /// split into 4 node tets
+  void GetTets (ARRAY<Element> & locels) const;
+  /// split into 4 node tets, local point nrs
+  void GetTetsLocal (ARRAY<Element> & locels) const;
+  /// returns coordinates of nodes
+  // void GetNodesLocal (ARRAY<Point<3> > & points) const;
+  void GetNodesLocalNew (ARRAY<Point<3> > & points) const;
+
+  /// split surface into 3 node trigs
+  void GetSurfaceTriangles (ARRAY<Element2d> & surftrigs) const;
+
+
+  /// get number of 'integration points'
+  int GetNIP () const;
+  void GetIntegrationPoint (int ip, Point<3> & p, double & weight) const;
+  void GetTransformation (int ip, const T_POINTS & points,
+			  class DenseMatrix & trans) const;
+  void GetTransformation (int ip, class DenseMatrix & pmat,
+			  class DenseMatrix & trans) const;
+
+  void GetShape (const Point<3> & p, class Vector & shape) const;
+  void GetShapeNew (const Point<3> & p, class FlatVector & shape) const;
+  /// matrix 2 * np
+  void GetDShape (const Point<3> & p, class DenseMatrix & dshape) const;
+  void GetDShapeNew (const Point<3> & p, class MatrixFixWidth<3> & dshape) const;
+  /// matrix 3 * np
+  void GetPointMatrix (const T_POINTS & points,
+		       class DenseMatrix & pmat) const; 
+
+  void ComputeIntegrationPointData () const;
+  
+
+  double CalcJacobianBadness (const T_POINTS & points) const;
+  double CalcJacobianBadnessDirDeriv (const T_POINTS & points,
+				      int pi, Vec<3> & dir, double & dd) const;
+  double CalcJacobianBadnessGradient (const T_POINTS & points,
+				      int pi, Vec<3> & grad) const;
+
+  ///
+  friend ostream & operator<<(ostream  & s, const Element & el);
+
+  void SetRefinementFlag (bool rflag = 1) 
+  { flags.refflag = rflag; }
+  int TestRefinementFlag () const
+  { return flags.refflag; }
+
+  void SetStrongRefinementFlag (bool rflag = 1) 
+  { flags.strongrefflag = rflag; }
+  int TestStrongRefinementFlag () const
+  { return flags.strongrefflag; }
+
+  int Illegal () const
+    { return flags.illegal; }
+  int IllegalValid () const
+    { return flags.illegal_valid; }
+  void SetIllegal (int aillegal)
+  {
+    flags.illegal = aillegal ? 1 : 0;
+    flags.illegal_valid = 1;
+  }
+  void SetLegal (int alegal)
+  {
+    flags.illegal = alegal ? 0 : 1;
+    flags.illegal_valid = 1;
+  }
+  
+  void Delete () { flags.deleted = 1; }
+  bool IsDeleted () const 
+  { 
+#ifdef DEBUG
+    if (pnum[0] < PointIndex::BASE && !flags.deleted)
+      cerr << "Volelement has illegal pnum, but not marked as deleted" << endl;
+#endif    
+
+    return flags.deleted; 
+  }
+
+#ifdef PARALLEL
+  int GetPartition () const { return partitionNumber; }
+  void SetPartition (int nr) { partitionNumber = nr; }; 
+#endif
+
+  int hp_elnr;
+
+#ifdef PARALLEL
+  bool IsGhost () const { return isghost; }
+
+  void SetGhost ( const bool aisghost ) { isghost = aisghost; }
+#endif
+
+  friend class Mesh;
+};
+
+
+class Segment;
+ostream & operator<<(ostream  & s, const Segment & seg);
+
+
+/**
+  Edge segment.
+  */
+class Segment
+{
+public:
+  ///
+  Segment();
+  Segment (const Segment& other);
+
+   ~Segment()
+  { ; }
+
+  friend ostream & operator<<(ostream  & s, const Segment & seg);
+
+  /// point index 1
+  PointIndex p1;
+  /// point index 2
+  PointIndex p2;    
+  /// edge nr
+  int edgenr;
+  ///
+  double singedge_left;
+  double singedge_right;
+
+  /// 0.. not first segment of segs, 1..first of class, 2..first of class, inverse
+  unsigned int seginfo:2;
+
+  /// surface decoding index
+  int si;          
+  /// domain number inner side
+  int domin;
+  /// domain number outer side
+  int domout;  
+  /// top-level object number of surface
+  int tlosurf;
+  ///
+  PointGeomInfo geominfo[2];
+
+  /// surfaces describing edge
+  int surfnr1, surfnr2;
+  ///
+  EdgePointGeomInfo epgeominfo[2];
+  ///
+  int pmid; // for second order
+  ///
+  int meshdocval;
+
+private:
+  string* bcname;
+
+public:
+  PointIndex operator[] (int i) const
+  { return (i == 0) ? p1 : p2; }
+
+  PointIndex & operator[] (int i) 
+  { return (i == 0) ? p1 : p2; }
+
+  Segment& operator=(const Segment & other);
+
+  
+  int hp_elnr;
+
+  void SetBCName ( string * abcname )
+  {
+    bcname = abcname;
+  }
+
+  string * BCNamePtr () 
+  { return bcname; }
+
+  const string * BCNamePtr () const 
+  { return bcname; }
+
+  string GetBCName () const
+  {
+    if (! bcname )
+      {
+	return "default";
+      }
+    return *bcname;
+  }
+
+
+};
+
+
+// class Surface;  
+class FaceDescriptor;
+ostream & operator<< (ostream  & s, const FaceDescriptor & fd);
+
+///
+class FaceDescriptor
+{
+  /// which surface, 0 if not available
+  int surfnr;
+  /// domain nr inside
+  int domin;
+  /// domain nr outside
+  int domout;
+  /// top level object number of surface
+  int tlosurf;
+  /// boundary condition property
+  int bcprop;
+
+  ///
+  string * bcname;
+  /// root of linked list 
+  SurfaceElementIndex firstelement;
+  
+public:
+  ///
+  double domin_singular;
+  double domout_singular;
+public:
+  FaceDescriptor();
+  FaceDescriptor(int surfnri, int domini, int domouti, int tlosurfi);
+  FaceDescriptor(const Segment & seg);
+  FaceDescriptor(const FaceDescriptor& other);
+  ~FaceDescriptor()  { ; }
+
+  int SegmentFits (const Segment & seg);
+
+  int SurfNr () const { return surfnr; }
+  int DomainIn () const { return domin; }
+  int DomainOut () const { return domout; }
+  int TLOSurface () const { return tlosurf; }
+  int BCProperty () const { return bcprop; }
+  string GetBCName () const; 
+  // string * BCNamePtr () { return bcname; }
+  // const string * BCNamePtr () const  { return bcname; }
+  void SetSurfNr (int sn) { surfnr = sn; }
+  void SetDomainIn (int di) { domin = di; }
+  void SetDomainOut (int dom) { domout = dom; }
+  void SetBCProperty (int bc) { bcprop = bc; }
+  void SetBCName (string * bcn) { bcname = bcn; }
+
+  friend ostream & operator<<(ostream  & s, const FaceDescriptor & fd);
+  friend class Mesh;
+};
+
+ 
+
+
+
+
+class MeshingParameters
+{
+public:
+  /**
+     3d optimization strategy:
+     // m .. move nodes
+     // M .. move nodes, cheap functional
+     // s .. swap faces
+     // c .. combine elements
+     // d .. divide elements
+     // p .. plot, no pause
+     // P .. plot, Pause
+     // h .. Histogramm, no pause
+     // H .. Histogramm, pause
+  */
+  const char * optimize3d;
+  /// number of 3d optimization steps
+  int optsteps3d;
+  /**
+     2d optimization strategy:
+     // s .. swap, opt 6 lines/node
+     // S .. swap, optimal elements
+     // m .. move nodes
+     // p .. plot, no pause
+     // P .. plot, pause
+     // c .. combine
+  **/
+  const char * optimize2d;
+  /// number of 2d optimization steps
+  int optsteps2d;
+  /// power of error (to approximate max err optimization)
+  double opterrpow;
+  /// do block filling ?  
+  int blockfill;
+  /// block filling up to distance
+  double filldist;
+  /// radius of local environment (times h)
+  double safety;
+  /// radius of active environment (times h)
+  double relinnersafety;
+  /// use local h ?
+  int uselocalh;
+  /// grading for local h
+  double grading;
+  /// use delaunay meshing
+  int delaunay;
+  /// maximal mesh size
+  double maxh;
+  /// minimal mesh size
+  double minh;
+  /// file for meshsize
+  const char * meshsizefilename;
+  /// start surfacemeshing from everywhere in surface
+  int startinsurface;
+  /// check overlapping surfaces (debug)
+  int checkoverlap;
+  /// check overlapping surface mesh before volume meshing
+  int checkoverlappingboundary;
+  /// check chart boundary (sometimes too restrictive)
+  int checkchartboundary;
+  /// safty factor for curvatures (elemetns per radius)
+  double curvaturesafety;
+  /// minimal number of segments per edge
+  double segmentsperedge;
+  /// use parallel threads
+  int parthread;
+  /// weight of element size w.r.t element shape
+  double elsizeweight;
+  /// init with default values
+
+
+  /// from mp3:
+  /// give up quality class, 2d meshing
+  int giveuptol2d;
+  /// give up quality class, 3d meshing
+  int giveuptol;
+  /// maximal outer steps
+  int maxoutersteps;
+  /// class starting star-shape filling
+  int starshapeclass;
+  /// if non-zero, baseelement must have baseelnp points
+  int baseelnp;        
+  /// quality tolerances are handled less careful
+  int sloppy;
+  
+  /// limit for max element angle (150-180)
+  double badellimit;
+
+  bool check_impossible;
+  
+  ///
+  int secondorder;
+  /// high order element curvature
+  int elementorder;
+  /// quad-dominated surface meshing
+  int quad;
+  ///
+  int inverttets;
+  ///
+  int inverttrigs;
+  ///
+  int autozrefine;
+  ///
+  MeshingParameters ();
+  ///
+  void Print (ostream & ost) const;
+
+  void CopyFrom(const MeshingParameters & other);
+};
+
+
+
+class DebugParameters 
+{
+public:
+  ///
+  int debugoutput;
+  /// use slow checks
+  int slowchecks;
+  ///
+  int haltsuccess;
+  ///
+  int haltnosuccess;
+  ///
+  int haltlargequalclass;
+  ///
+  int haltsegment;
+  ///
+  int haltnode;
+  ///
+  int haltsegmentp1;
+  ///
+  int haltsegmentp2;
+  ///
+  int haltexistingline;
+  ///
+  int haltoverlap;
+  ///
+  int haltface;
+  ///
+  int haltfacenr;
+  ///
+  DebugParameters ();
+};
+
+
+
+
+inline void Element2d :: Invert()
+{
+  if (typ == TRIG)
+    Swap (PNum(2), PNum(3));
+  else
+    Invert2();
+}
+
+
+
+
+inline void Element2d :: NormalizeNumbering ()
+{
+  if (GetNP() == 3)
+    {
+      if (PNum(1) < PNum(2) && PNum(1) < PNum(3))
+	return;
+      else
+	{
+	  if (PNum(2) < PNum(3))
+	    {
+	      PointIndex pi1 = PNum(2);
+	      PNum(2) = PNum(3);
+	      PNum(3) = PNum(1);
+	      PNum(1) = pi1;
+	    }
+	  else
+	    {
+	      PointIndex pi1 = PNum(3);
+	      PNum(3) = PNum(2);
+	      PNum(2) = PNum(1);
+	      PNum(1) = pi1;
+	    }
+	}
+    }
+  else
+    NormalizeNumbering2();
+}
+
+
+
+static const int gftetfacesa[4][3] = 
+  { { 1, 2, 3 },
+    { 2, 0, 3 },
+    { 0, 1, 3 },
+    { 1, 0, 2 } };
+
+inline void Element :: GetFace (int i, Element2d & face) const
+{
+  if (typ == TET)
+    {
+      face.SetType(TRIG);
+      face[0] = pnum[gftetfacesa[i-1][0]];
+      face[1] = pnum[gftetfacesa[i-1][1]];
+      face[2] = pnum[gftetfacesa[i-1][2]];
+    }
+  else
+    GetFace2 (i, face);
+}
+
+
+
+
+
+
+
+/**
+   Identification of periodic surfaces, close surfaces, etc. 
+ */
+class Identifications
+{
+public:
+  enum ID_TYPE { UNDEFINED = 1, PERIODIC = 2, CLOSESURFACES = 3, CLOSEEDGES = 4};
+  
+
+private:
+  class Mesh & mesh;
+
+  /// identify points (thin layers, periodic b.c.)  
+  INDEX_2_HASHTABLE<int> * identifiedpoints;
+  
+  /// the same, with info about the id-nr
+  INDEX_3_HASHTABLE<int> * identifiedpoints_nr;
+
+  /// sorted by identification nr
+  TABLE<INDEX_2> idpoints_table;
+
+  ARRAY<ID_TYPE> type;
+
+  /// number of identifications (or, actually used identifications ?)
+  int maxidentnr;
+
+public:
+  ///
+  Identifications (class Mesh & amesh);
+  ///
+  ~Identifications ();
+
+  void Delete ();
+
+  /*
+    Identify points pi1 and pi2, due to
+    identification nr identnr
+  */
+  void Add (PointIndex pi1, PointIndex pi2, int identnr);
+
+
+  int Get (PointIndex pi1, PointIndex pi2) const;
+  int GetSymmetric (PointIndex pi1, PointIndex pi2) const;
+
+  bool Get (PointIndex pi1, PointIndex pi2, int identnr) const;
+  bool GetSymmetric (PointIndex pi1, PointIndex pi2, int identnr) const;
+
+  ///
+  INDEX_2_HASHTABLE<int> & GetIdentifiedPoints () 
+  { 
+    return *identifiedpoints; 
+  }
+
+  bool Used (PointIndex pi1, PointIndex pi2)
+  {
+    return identifiedpoints->Used (INDEX_2 (pi1, pi2));
+  }
+
+  bool UsedSymmetric (PointIndex pi1, PointIndex pi2)
+  {
+    return 
+      identifiedpoints->Used (INDEX_2 (pi1, pi2)) ||
+      identifiedpoints->Used (INDEX_2 (pi2, pi1));
+  }
+
+  ///
+  void GetMap (int identnr, ARRAY<int,PointIndex::BASE> & identmap, bool symmetric = false) const;
+  ///
+  ID_TYPE GetType(int identnr) const
+  {
+    if(identnr <= type.Size())
+      return type[identnr-1];
+    else
+      return UNDEFINED;
+  }
+  void SetType(int identnr, ID_TYPE t)
+  {
+    while(type.Size() < identnr)
+      type.Append(UNDEFINED);
+    type[identnr-1] = t;
+  }
+    
+  ///
+  void GetPairs (int identnr, ARRAY<INDEX_2> & identpairs) const;
+  ///
+  int GetMaxNr () const { return maxidentnr; }  
+
+  /// remove secondorder
+  void SetMaxPointNr (int maxpnum);
+
+  void Print (ostream & ost) const;
+};
+
+
+
+
+
+
+
+#endif
+
diff --git a/contrib/Netgen/libsrc/meshing/msghandler.cpp b/contrib/Netgen/libsrc/meshing/msghandler.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..88e30fb18ab02619299a2e3226945584b3a33fe5
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/msghandler.cpp
@@ -0,0 +1,226 @@
+//File for handling warnings, errors, messages
+#include <meshing.hpp>
+
+namespace netgen
+{
+
+int printmessage_importance = 5;
+int printwarnings = 1;
+int printerrors = 1;
+int printdots = 1;
+int printfnstart = 0;
+
+// extern void Ng_PrintDest(const MyStr& s);
+extern void Ng_PrintDest(const char * s);
+
+//the dots for progression of program
+void PrintDot(char ch)
+{
+  if (printdots)
+    {
+      char st[2];
+      st[0] = ch;
+      st[1] = 0;
+      Ng_PrintDest(st);
+    }
+}
+
+void PrintMessage(int importance, 
+		  const MyStr& s1, const MyStr& s2)
+{
+  if (importance <= printmessage_importance)
+    {
+      Ng_PrintDest(MyStr(" ")+s1+s2+MyStr("\n"));
+    }
+}
+
+void PrintMessage(int importance, 
+		  const MyStr& s1, const MyStr& s2, const MyStr& s3, const MyStr& s4)
+{
+  if (importance <= printmessage_importance)
+    {
+      Ng_PrintDest(MyStr(" ")+s1+s2+s3+s4+MyStr("\n"));
+    }
+}
+
+void PrintMessage(int importance, 
+		  const MyStr& s1, const MyStr& s2, const MyStr& s3, const MyStr& s4, 
+		  const MyStr& s5, const MyStr& s6, const MyStr& s7, const MyStr& s8)
+{
+  if (importance <= printmessage_importance)
+    {
+      Ng_PrintDest(MyStr(" ")+s1+s2+s3+s4+s5+s6+s7+s8+MyStr("\n"));
+    }
+}
+
+void PrintMessageCR(int importance, 
+		    const MyStr& s1, const MyStr& s2, const MyStr& s3, const MyStr& s4, 
+		    const MyStr& s5, const MyStr& s6, const MyStr& s7, const MyStr& s8)
+{
+  if (importance <= printmessage_importance)
+    {
+      Ng_PrintDest(MyStr(" ")+s1+s2+s3+s4+s5+s6+s7+s8+MyStr("\r"));
+    }
+}
+
+void PrintFnStart(const MyStr& s1, const MyStr& s2, const MyStr& s3, const MyStr& s4, 
+		  const MyStr& s5, const MyStr& s6, const MyStr& s7, const MyStr& s8)
+{
+  if (printfnstart)
+    Ng_PrintDest(MyStr(" Start Function: ")+s1+s2+s3+s4+s5+s6+s7+s8+MyStr("\n"));
+}
+
+void PrintWarning(const MyStr& s1, const MyStr& s2, const MyStr& s3, const MyStr& s4, 
+		  const MyStr& s5, const MyStr& s6, const MyStr& s7, const MyStr& s8)
+{
+  if (printwarnings)
+    Ng_PrintDest(MyStr(" WARNING: ")+s1+s2+s3+s4+s5+s6+s7+s8+MyStr("\n"));
+}
+
+void PrintError(const MyStr& s1, const MyStr& s2, const MyStr& s3, const MyStr& s4, 
+		const MyStr& s5, const MyStr& s6, const MyStr& s7, const MyStr& s8)
+{
+  if (printerrors)
+    Ng_PrintDest(MyStr(" ERROR: ")+s1+s2+s3+s4+s5+s6+s7+s8+MyStr("\n"));
+}
+
+void PrintFileError(const MyStr& s1, const MyStr& s2, const MyStr& s3, const MyStr& s4, 
+		    const MyStr& s5, const MyStr& s6, const MyStr& s7, const MyStr& s8)
+{
+  if (printerrors)
+    Ng_PrintDest(MyStr(" FILE ERROR: ")+s1+s2+s3+s4+s5+s6+s7+s8+MyStr("\n"));
+}
+
+void PrintUserError(const MyStr& s1, const MyStr& s2, const MyStr& s3, const MyStr& s4, 
+		const MyStr& s5, const MyStr& s6, const MyStr& s7, const MyStr& s8)
+{
+  Ng_PrintDest(MyStr(" USER ERROR: ")+s1+s2+s3+s4+s5+s6+s7+s8+MyStr("\n"));
+}
+
+void PrintSysError(const MyStr& s1, const MyStr& s2, const MyStr& s3, const MyStr& s4, 
+		const MyStr& s5, const MyStr& s6, const MyStr& s7, const MyStr& s8)
+{
+  if (printerrors)
+    Ng_PrintDest(MyStr(" SYSTEM ERROR: ")+s1+s2+s3+s4+s5+s6+s7+s8+MyStr("\n"));
+}
+
+void PrintTime(const MyStr& s1, const MyStr& s2, const MyStr& s3, const MyStr& s4, 
+	       const MyStr& s5, const MyStr& s6, const MyStr& s7, const MyStr& s8)
+{
+  if (printmessage_importance >= 3)
+    Ng_PrintDest(MyStr(" Time = ")+s1+s2+s3+s4+s5+s6+s7+s8+MyStr("\n"));
+}
+
+
+static ARRAY<MyStr*> msgstatus_stack(0);
+static ARRAY<double> threadpercent_stack(0);
+static MyStr msgstatus = "";
+
+
+
+
+void ResetStatus()
+{
+  SetStatMsg("idle");
+
+  for (int i = 0; i < msgstatus_stack.Size(); i++)
+    delete msgstatus_stack[i];
+  msgstatus_stack.SetSize(0);
+  threadpercent_stack.SetSize(0);
+
+  // multithread.task = "";
+  multithread.percent = 100.;
+}
+
+void PushStatus(const MyStr& s)
+{
+  msgstatus_stack.Append(new MyStr (s));  
+  SetStatMsg(s);
+  threadpercent_stack.Append(0);
+}
+
+void PushStatusF(const MyStr& s)
+{
+  msgstatus_stack.Append(new MyStr (s));
+  SetStatMsg(s);
+  threadpercent_stack.Append(0);
+  PrintFnStart(s);
+}
+
+void PopStatus()
+{
+  if (msgstatus_stack.Size())
+    {
+      if (msgstatus_stack.Size() > 1)
+	SetStatMsg (*msgstatus_stack.Last());
+      else
+	SetStatMsg ("");
+      delete msgstatus_stack.Last();
+      msgstatus_stack.DeleteLast();
+      threadpercent_stack.DeleteLast();
+      if(threadpercent_stack.Size() > 0)
+	multithread.percent = threadpercent_stack.Last();
+      else
+	multithread.percent = 100.;
+    }
+  else
+    {
+      PrintSysError("PopStatus failed");
+    }
+}
+
+
+
+/*
+void SetStatMsgF(const MyStr& s)
+{
+  PrintFnStart(s);
+  SetStatMsg(s);
+}
+*/
+
+void SetStatMsg(const MyStr& s)
+{
+  msgstatus = s;
+  multithread.task = msgstatus.c_str();  
+}
+
+void SetThreadPercent(double percent)
+{
+  multithread.percent = percent;
+  if(threadpercent_stack.Size() > 0)
+    threadpercent_stack.Last() = percent;
+}
+
+
+void GetStatus(MyStr & s, double & percentage)
+{
+  if(threadpercent_stack.Size() > 0)
+    percentage = threadpercent_stack.Last();
+  else
+    percentage = multithread.percent;
+  
+  if ( msgstatus_stack.Size() )
+    s = *msgstatus_stack.Last();
+  else
+    s = "idle";     
+}
+
+
+#ifdef SMALLLIB
+#define SMALLLIBORNOTCL
+#endif
+#ifdef NOTCL
+#define SMALLLIBORNOTCL
+#endif
+
+#ifdef SMALLLIBORNOTCL
+void Ng_PrintDest(const char * s){cout << s <<flush;}
+double GetTime(){return 0;}
+void MyError(const char * ch)
+{
+  cerr << ch << endl;
+}
+#endif
+
+}
diff --git a/contrib/Netgen/libsrc/meshing/msghandler.hpp b/contrib/Netgen/libsrc/meshing/msghandler.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..843cd1864934b75934d66109efb127ccb79bf949
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/msghandler.hpp
@@ -0,0 +1,53 @@
+#ifndef FILE_MSGHANDLER
+#define FILE_MSGHANDLER
+
+/**************************************************************************/
+/* File:   msghandler.hh                                                  */
+/* Author: Johannes Gerstmayr                                             */
+/* Date:   20. Nov. 99                                                    */
+/**************************************************************************/
+
+
+extern void PrintDot(char ch = '.');
+
+
+//Message Pipeline:
+
+//importance: importance of message: 1=very important, 3=middle, 5=low, 7=unimportant
+extern void PrintMessage(int importance, 
+			 const MyStr& s1, const MyStr& s2=MyStr());
+extern void PrintMessage(int importance, 
+			 const MyStr& s1, const MyStr& s2, const MyStr& s3, const MyStr& s4=MyStr());
+extern void PrintMessage(int importance, 
+			 const MyStr& s1, const MyStr& s2, const MyStr& s3, const MyStr& s4, 
+			 const MyStr& s5, const MyStr& s6=MyStr(), const MyStr& s7=MyStr(), const MyStr& s8=MyStr());
+
+// CR without line-feed
+extern void PrintMessageCR(int importance, 
+			   const MyStr& s1, const MyStr& s2="", const MyStr& s3="", const MyStr& s4="", 
+			   const MyStr& s5="", const MyStr& s6="", const MyStr& s7="", const MyStr& s8="");
+extern void PrintFnStart(const MyStr& s1, const MyStr& s2="", const MyStr& s3="", const MyStr& s4="", 
+			 const MyStr& s5="", const MyStr& s6="", const MyStr& s7="", const MyStr& s8="");
+extern void PrintWarning(const MyStr& s1, const MyStr& s2="", const MyStr& s3="", const MyStr& s4="", 
+			 const MyStr& s5="", const MyStr& s6="", const MyStr& s7="", const MyStr& s8="");
+extern void PrintError(const MyStr& s1, const MyStr& s2="", const MyStr& s3="", const MyStr& s4="", 
+		       const MyStr& s5="", const MyStr& s6="", const MyStr& s7="", const MyStr& s8="");
+extern void PrintFileError(const MyStr& s1, const MyStr& s2="", const MyStr& s3="", const MyStr& s4="", 
+		       const MyStr& s5="", const MyStr& s6="", const MyStr& s7="", const MyStr& s8="");
+extern void PrintSysError(const MyStr& s1, const MyStr& s2="", const MyStr& s3="", const MyStr& s4="", 
+		       const MyStr& s5="", const MyStr& s6="", const MyStr& s7="", const MyStr& s8="");
+extern void PrintUserError(const MyStr& s1, const MyStr& s2="", const MyStr& s3="", const MyStr& s4="", 
+		       const MyStr& s5="", const MyStr& s6="", const MyStr& s7="", const MyStr& s8="");
+extern void PrintTime(const MyStr& s1="", const MyStr& s2="", const MyStr& s3="", const MyStr& s4="", 
+		      const MyStr& s5="", const MyStr& s6="", const MyStr& s7="", const MyStr& s8="");
+extern void SetStatMsg(const MyStr& s);
+
+extern void PushStatus(const MyStr& s);
+extern void PushStatusF(const MyStr& s);
+extern void PopStatus();
+extern void SetThreadPercent(double percent);
+extern void GetStatus(MyStr & s, double & percentage);
+
+
+#endif
+
diff --git a/contrib/Netgen/libsrc/meshing/netrule2.cpp b/contrib/Netgen/libsrc/meshing/netrule2.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..42fe341a501e0d1be503eb3b53889a0a5792a819
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/netrule2.cpp
@@ -0,0 +1,229 @@
+#include <mystdlib.h>
+#include "meshing.hpp"
+
+namespace netgen
+{
+
+netrule :: netrule ()
+{
+  name = new char[1];
+  name[0] = char(0);
+  quality = 0;
+}
+
+netrule ::  ~netrule()
+{
+  // if(name != NULL) 
+  delete [] name;
+  for(int i=0; i<oldutofreearea_i.Size(); i++)
+    delete oldutofreearea_i[i];
+}
+
+
+/*
+void netrule :: GetFreeArea (ARRAY<Point2d> & afreearea)
+  {
+  int i;
+
+  afreearea.SetSize (freearea.Size());
+  for (i = 1; i <= freearea.Size(); i++)
+    afreearea[i] = freearea[i];
+  }
+*/
+
+
+void netrule :: SetFreeZoneTransformation (const Vector & devp, int tolclass)
+{
+  double lam1 = 1.0/tolclass;
+  double lam2 = 1.-lam1;
+
+  double mem1[100], mem2[100], mem3[100];
+
+  int vs = oldutofreearea.Height();
+  FlatVector devfree(vs, mem1);
+  FlatVector devfree1(vs, mem2);
+  FlatVector devfree2(vs, mem3);
+
+  if (tolclass <= oldutofreearea_i.Size())
+    {
+      oldutofreearea_i[tolclass-1] -> Mult (devp, devfree);
+    }
+  else
+    {
+      oldutofreearea.Mult (devp, devfree1);
+      oldutofreearealimit.Mult (devp, devfree2);
+      devfree.Set2 (lam1, devfree1, lam2, devfree2);
+    }
+
+  
+  int fzs = freezone.Size();
+  transfreezone.SetSize (fzs);
+
+  if (fzs > 0)
+    {
+      transfreezone[0].X() = lam1 * freezone[0].X() + lam2 * freezonelimit[0].X() + devfree[0];
+      transfreezone[0].Y() = lam1 * freezone[0].Y() + lam2 * freezonelimit[0].Y() + devfree[1];
+      fzmaxx = fzminx = transfreezone[0].X();
+      fzmaxy = fzminy = transfreezone[0].Y();
+    }
+
+  for (int i = 1; i < fzs; i++)
+    {
+      transfreezone[i].X() = lam1 * freezone[i].X() + lam2 * freezonelimit[i].X() + devfree[2*i];
+      transfreezone[i].Y() = lam1 * freezone[i].Y() + lam2 * freezonelimit[i].Y() + devfree[2*i+1];
+
+      if (transfreezone[i].X() > fzmaxx) fzmaxx = transfreezone[i].X();
+      if (transfreezone[i].X() < fzminx) fzminx = transfreezone[i].X();
+      if (transfreezone[i].Y() > fzmaxy) fzmaxy = transfreezone[i].Y();
+      if (transfreezone[i].Y() < fzminy) fzminy = transfreezone[i].Y();
+    }
+
+  for (int i = 0; i < fzs; i++)
+    {
+      Point2d p1 = transfreezone[i];
+      Point2d p2 = transfreezone[(i+1) % fzs];
+
+      Vec2d vn (p2.Y() - p1.Y(), p1.X() - p2.X());
+
+      double len2 = vn.Length2();
+
+      if (len2 < 1e-10)
+	{
+	  freesetinequ(i, 0) = 0;
+	  freesetinequ(i, 1) = 0;
+	  freesetinequ(i, 2) = -1;
+	}
+      else
+	{
+	  vn /= sqrt (len2);    // should not be necessary
+
+	  freesetinequ(i,0) = vn.X(); 
+	  freesetinequ(i,1) = vn.Y(); 
+	  freesetinequ(i,2) = -(p1.X() * vn.X() + p1.Y() * vn.Y());
+	}
+
+      /*
+      freesetinequ(i,0) = vn.X(); 
+      freesetinequ(i,1) = vn.Y(); 
+      freesetinequ(i,2) = -(p1.X() * vn.X() + p1.Y() * vn.Y());
+      */
+    }
+}
+
+
+/*
+int netrule :: IsInFreeZone2 (const Point2d & p) const
+{
+  for (int i = 0; i < transfreezone.Size(); i++)
+    {
+      if (freesetinequ(i, 0) * p.X() + 
+	  freesetinequ(i, 1) * p.Y() +
+	  freesetinequ(i, 2) > 0) return 0;
+    }
+  return 1;
+}
+*/
+
+int netrule :: IsLineInFreeZone2 (const Point2d & p1, const Point2d & p2) const
+{
+  int left, right, allleft, allright;
+
+  if (p1.X() > fzmaxx && p2.X() > fzmaxx ||
+      p1.X() < fzminx && p2.X() < fzminx ||
+      p1.Y() > fzmaxy && p2.Y() > fzmaxy ||
+      p1.Y() < fzminy && p2.Y() < fzminy) return 0;
+
+  for (int i = 1; i <= transfreezone.Size(); i++)
+    {
+      if (freesetinequ.Get(i, 1) * p1.X() + freesetinequ.Get(i, 2) * p1.Y() +
+	  freesetinequ.Get(i, 3) > -1e-8 &&    // -1e-6
+	  freesetinequ.Get(i, 1) * p2.X() + freesetinequ.Get(i, 2) * p2.Y() +
+	  freesetinequ.Get(i, 3) > -1e-8       // -1e-6
+	  ) return 0;
+    }
+
+  double nx =  (p2.Y() - p1.Y());
+  double ny = -(p2.X() - p1.X());
+  double nl = sqrt (nx * nx + ny * ny);
+  if (nl > 1e-8)
+    {
+      nx /= nl;
+      ny /= nl;
+      double c = - (p1.X() * nx + p1.Y() * ny);
+
+      allleft = 1;
+      allright = 1;
+
+      for (int i = 1; i <= transfreezone.Size(); i++)
+	{
+	  left  = transfreezone.Get(i).X() * nx + transfreezone.Get(i).Y() + c <  1e-7;
+	  right = transfreezone.Get(i).X() * nx + transfreezone.Get(i).Y() + c > -1e-7;
+
+	  if (!left) allleft = 0;
+	  if (!right) allright = 0;
+	}
+      if (allleft || allright) return 0;
+    }
+
+  return 1;
+}
+
+int netrule :: ConvexFreeZone () const
+{
+  int n = transfreezone.Size();
+  for (int i = 1; i <= n; i++)
+    {
+      const bool counterclockwise = CCW (transfreezone.Get(i), 
+					 transfreezone.Get(i % n + 1),
+					 transfreezone.Get( (i+1) % n + 1 ),
+					 1e-7);
+      //(*testout) << "ccw " << counterclockwise << endl << " p1 " << transfreezone.Get(i) << " p2 " << transfreezone.Get(i % n + 1)
+      //		 << " p3 " << transfreezone.Get( (i+1) % n + 1 ) << endl;
+      if (!counterclockwise )
+	return 0;
+    }
+  return 1;
+}
+
+
+/*
+float netrule :: CalcPointDist (int pi, const Point2d & p) const
+{
+  float dx = p.X() - points.Get(pi).X();
+  float dy = p.Y() - points.Get(pi).Y();
+  const threefloat * tf = &tolerances.Get(pi);
+
+  return tf->f1 * dx * dx + tf->f2 * dx * dy + tf->f3 * dy * dy;
+}
+*/
+
+float netrule :: CalcLineError (int li, const Vec2d & v) const
+{
+  float dx = v.X() - linevecs.Get(li).X();
+  float dy = v.Y() - linevecs.Get(li).Y();
+
+  const threefloat * ltf = &linetolerances.Get(li);
+  return ltf->f1 * dx * dx + ltf->f2 * dx * dy + ltf->f3 * dy * dy;
+}
+
+
+
+
+/*
+int GetNRules ()
+  {
+  return rules.Size();
+  }
+*/
+
+
+
+
+
+
+
+
+
+
+
+}
diff --git a/contrib/Netgen/libsrc/meshing/netrule3.cpp b/contrib/Netgen/libsrc/meshing/netrule3.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..2b7bdfd9c52110ac961e1f2dd38e5039839b2df3
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/netrule3.cpp
@@ -0,0 +1,1140 @@
+#include <mystdlib.h>
+#include "meshing.hpp"
+
+// #define MARK
+// #include <prof.h>
+
+
+namespace netgen
+{
+
+
+vnetrule :: vnetrule ()
+{
+  name = new char[1];
+  name[0] = char(0);
+  quality = 0;
+}
+
+vnetrule :: ~vnetrule ()
+{
+  // if (strlen(name)) 
+  delete [] name;
+  for (int i = 1; i <= freefaces.Size(); i++)
+    delete freefaces.Elem(i);
+  for (int i = 1; i <= freesets.Size(); i++)
+    delete freesets.Elem(i);
+  for (int i = 1; i <= freeedges.Size(); i++)
+    delete freeedges.Elem(i);
+  for (int i = 1; i <= freefaceinequ.Size(); i++)
+    delete freefaceinequ.Elem(i);
+  delete oldutofreezone;
+  delete oldutofreezonelimit;
+}
+
+int vnetrule :: TestFlag (char flag) const
+{
+  for (int i = 1; i <= flags.Size(); i++)
+    if (flags.Get(i) == flag) return 1;
+  return 0;
+}
+
+
+void vnetrule :: SetFreeZoneTransformation (const Vector & allp, int tolclass)
+{
+  int i, j;
+  // double nx, ny, nz, v1x, v1y, v1z, v2x, v2y, v2z;
+  double nl;
+  const threeint * ti;
+  int fs;
+
+  double lam1 = 1.0/(2 * tolclass - 1);
+  double lam2 = 1-lam1;
+
+  transfreezone.SetSize (freezone.Size());
+  
+  int np = points.Size();
+  int nfp = freezone.Size();
+  Vector vp(np), vfp1(nfp), vfp2(nfp);
+
+
+  for (i = 1; i <= 3; i++)
+    {
+      for (j = 1; j <= np; j++)
+	vp.Elem(j) = allp.Get(i+3*j-3);
+
+      oldutofreezone->Mult (vp, vfp1);
+      oldutofreezonelimit->Mult (vp, vfp2);
+
+      vfp1 *= lam1;
+      vfp1.Add (lam2, vfp2);
+
+      for (j = 1; j <= nfp; j++)
+	transfreezone.Elem(j).X(i) = vfp1.Elem(j);
+    }
+
+  // MARK(setfz2);
+
+
+  fzbox.SetPoint (transfreezone.Elem(1));
+  for (i = 2; i <= freezone.Size(); i++)
+    fzbox.AddPoint (transfreezone.Elem(i));
+  
+  
+  // MARK(setfz3);
+
+
+  for (fs = 1; fs <= freesets.Size(); fs++)
+    {
+      ARRAY<threeint> & freesetfaces = *freefaces.Get(fs);
+      DenseMatrix & freesetinequ = *freefaceinequ.Get(fs);
+      
+      for (i = 1; i <= freesetfaces.Size(); i++)
+	{
+	  ti = &freesetfaces.Get(i);
+	  const Point3d & p1 = transfreezone.Get(ti->i1);
+	  const Point3d & p2 = transfreezone.Get(ti->i2);
+	  const Point3d & p3 = transfreezone.Get(ti->i3);
+
+	  Vec3d v1(p1, p2);   
+	  Vec3d v2(p1, p3);   
+	  Vec3d n;
+	  Cross (v1, v2, n);
+
+	  nl = n.Length();
+
+	  if (nl < 1e-10)
+	    {
+	      freesetinequ.Set(1, 1, 0);
+	      freesetinequ.Set(1, 2, 0);
+	      freesetinequ.Set(1, 3, 0);
+	      freesetinequ.Set(1, 4, -1);
+	    }
+	  else
+	    {
+	      //	      n /= nl;
+	      
+	      freesetinequ.Set(i, 1, n.X()/nl);
+	      freesetinequ.Set(i, 2, n.Y()/nl);
+	      freesetinequ.Set(i, 3, n.Z()/nl);
+	      freesetinequ.Set(i, 4,
+			       -(p1.X() * n.X() + p1.Y() * n.Y() + p1.Z() * n.Z()) / nl);
+	    }
+	}
+    }
+
+  /*
+  (*testout) << "Transformed freezone: " << endl;
+  for (i = 1; i <= transfreezone.Size(); i++)
+    (*testout) << transfreezone.Get(i) << " ";
+  (*testout) << endl;
+  */
+}
+
+int vnetrule :: ConvexFreeZone () const
+{
+  int i, j, k, fs;
+
+  // (*mycout) << "Convex free zone...\n";
+  
+  int ret1=1;
+  // int ret2=1;
+
+  for (fs = 1; fs <= freesets.Size(); fs++)
+    {
+      const DenseMatrix & freesetinequ = *freefaceinequ.Get(fs);
+
+      // const ARRAY<int> & freeset = *freesets.Get(fs);
+      const ARRAY<twoint> & freesetedges = *freeedges.Get(fs);
+      // const ARRAY<threeint> & freesetfaces = *freefaces.Get(fs);
+      
+      for (i = 1; i <= freesetedges.Size(); i++)
+	{
+	  j = freesetedges.Get(i).i1;    //triangle j with opposite point k
+	  k = freesetedges.Get(i).i2;
+	  
+	  if ( freesetinequ.Get(j, 1) * transfreezone.Get(k).X() +
+	       freesetinequ.Get(j, 2) * transfreezone.Get(k).Y() +
+	       freesetinequ.Get(j, 3) * transfreezone.Get(k).Z() +
+	       freesetinequ.Get(j, 4) > 0 )
+	    {
+	      ret1=0;
+	    }
+	}
+      
+    }
+
+  return ret1;
+}
+
+
+int vnetrule :: IsInFreeZone (const Point3d & p) const
+{
+  int i, fs;
+  char inthis;
+  
+  
+  for (fs = 1; fs <= freesets.Size(); fs++)
+    {
+      inthis = 1;
+      ARRAY<threeint> & freesetfaces = *freefaces.Get(fs);
+      DenseMatrix & freesetinequ = *freefaceinequ.Get(fs);
+      
+      for (i = 1; i <= freesetfaces.Size() && inthis; i++)
+	{
+	  if (freesetinequ.Get(i, 1) * p.X() + freesetinequ.Get(i, 2) * p.Y() +
+	      freesetinequ.Get(i, 3) * p.Z() + freesetinequ.Get(i, 4) > 0)
+	    inthis = 0;
+	}
+      
+      if (inthis) return 1;
+    }
+  
+  return 0;
+}
+
+
+int vnetrule :: IsTriangleInFreeZone (const Point3d & p1, 
+				      const Point3d & p2,
+				      const Point3d & p3, 
+				      const ARRAY<int> & pi, int newone)
+{
+  int fs;
+  int infreeset, cannot = 0;
+
+
+  static ARRAY<int> pfi(3), pfi2(3);
+
+  // convert from local index to freeset index
+  int i, j;
+  for (i = 1; i <= 3; i++)
+    {
+      pfi.Elem(i) = 0;
+      if (pi.Get(i))
+	{
+	  for (j = 1; j <= freezonepi.Size(); j++)
+	    if (freezonepi.Get(j) == pi.Get(i))
+	      pfi.Elem(i) = j;
+	}
+    }
+
+  for (fs = 1; fs <= freesets.Size(); fs++)
+    {
+      const ARRAY<int> & freeseti = *freesets.Get(fs);
+      for (i = 1; i <= 3; i++)
+	{
+	  pfi2.Elem(i) = 0;
+	  for (j = 1; j <= freeseti.Size(); j++)
+	    if (pfi.Get(i) == freeseti.Get(j))
+	      pfi2.Elem(i) = pfi.Get(i);
+	}
+
+      infreeset = IsTriangleInFreeSet(p1, p2, p3, fs, pfi2, newone);
+      if (infreeset == 1) return 1;
+      if (infreeset == -1) cannot = -1;
+    }
+  
+  return cannot;
+}
+
+
+
+int vnetrule :: IsTriangleInFreeSet (const Point3d & p1, const Point3d & p2,
+                                     const Point3d & p3, int fs,
+				     const ARRAY<int> & pi, int newone)
+{
+  int i, ii;
+  Vec3d n;
+  int allleft, allright;
+  int hos1, hos2, hos3, os1, os2, os3;
+  double hf, lam1, lam2, f, c1, c2, alpha;
+  double v1n, v2n, h11, h12, h22, dflam1, dflam2;
+  double lam1old, lam2old, fold;
+  double hpx, hpy, hpz, v1x, v1y, v1z, v2x, v2y, v2z;
+  int act1, act2, act3, it;
+  int cntout;
+  static ARRAY<int> activefaces;
+  int isin;
+  
+
+  // MARK(triinfz);
+  
+  ARRAY<threeint> & freesetfaces = *freefaces.Get(fs);
+  DenseMatrix & freesetinequ = *freefaceinequ.Get(fs);
+  
+
+  int cnt = 0;
+  for (i = 1; i <= 3; i++)
+    if (pi.Get(i)) cnt++;
+
+  /*
+  (*testout) << "trig in free set : " << p1 << " - " << p2 << " - " << p3 << endl;
+  (*testout) << "common points: " << cnt << endl;
+  */
+  if (!newone)
+    cnt = 0;
+
+  if (cnt == 1)
+    {
+      // MARK(triinfz1);
+
+      int upi = 0, lpiu = 0;
+      for (i = 1; i <= 3; i++)
+	if (pi.Get(i))
+	  {
+	    upi = i;
+	    lpiu = pi.Get(i);
+	  }
+
+      Vec3d v1, v2;
+      switch (upi)
+	{
+	case 1:
+	  {
+	    v1 = p2 - p1;
+	    v2 = p3 - p1;
+	    break;
+	  }
+	case 2:
+	  {
+	    v1 = p3 - p2;
+	    v2 = p1 - p2;
+	    break;
+	  }
+	case 3:
+	  {
+	    v1 = p1 - p3;
+	    v2 = p2 - p3;
+	    break;
+	  }
+	}
+
+      v1 /= v1.Length();
+      v2 /= v2.Length();
+      Cross (v1, v2, n);
+      n /= n.Length();
+
+      //      (*testout) << "Test new: " << endl;
+      for (i = 1; i <= freesetfaces.Size(); i++)
+	{
+	  if ( (freesetfaces.Get(i).i1 == lpiu) || 
+	       (freesetfaces.Get(i).i2 == lpiu) ||
+	       (freesetfaces.Get(i).i3 == lpiu) )
+	    {
+	      // freeface has point
+
+
+	      Vec3d a (freesetinequ.Get(i, 1),
+		       freesetinequ.Get(i, 2),
+		       freesetinequ.Get(i, 3));
+	      
+	      //	      if (1 - fabs (a * n) < 1e-8 ) 
+	      //		continue;
+
+	      Vec3d an;
+	      Cross (a, n, an);
+	      double lan = an.Length();
+	      if (lan < 1e-10)
+		continue;
+
+	      an /= lan;
+	      
+	      int out1 = (a * v1) > 0;
+	      int out2 = (a * v2) > 0;
+	      //	      (*testout) << "out1, out2 = " << out1 << ", " << out2 << endl;
+	      if (out1 && out2)
+		return 0;
+
+	      if (!out1 && !out2) 
+		continue;
+
+
+	      //	      if ( ( (an * v1) < 0) &&  ( (an * v2) < 0) )   // falsch !!!!
+	      //		an *= -1;
+
+	      // solve  an = lam1 v1 + lam2 v2
+	      double vii11 = v1 * v1;
+	      double vii12 = v1 * v2;
+	      double vii22 = v2 * v2;
+	      double det = vii11 * vii22 - vii12 * vii12;
+	      if ( fabs (det) < 1e-10 )
+		continue;
+	      double rs1 = an * v1;
+	      double rs2 = an * v2;
+	      
+	      double lambda1 = rs1 * vii22 - rs2 * vii12;
+	      double lambda2 = rs2 * vii11 - rs1 * vii12;
+
+	      if (fabs (lambda1) > fabs (lambda2))
+		{
+		  if (lambda1 < 0)
+		    an *= -1;
+		}
+	      else
+		{
+		  if (lambda2 < 0)
+		    an *= -1;
+		}
+
+
+	      if (lambda1 * lambda2 < 0 && 0)
+		{
+		  if (fabs (lambda1) > 1e-14 && fabs (lambda2) > 1e-14)
+		    {
+		      //		      (*mycout) << "lambda1 lambda2 < 0" << endl;
+		      (*testout) << "lambdai different" << endl;
+		      (*testout) << "v1 = " << v1 << endl;
+		      (*testout) << "v2 = " << v2 << endl;
+		      (*testout) << "n = " << n << endl;
+		      (*testout) << "a = " << a << endl;
+		      (*testout) << "an = " << an << endl;
+		      (*testout) << "a * v1 = " << (a * v1) << endl;
+		      (*testout) << "a * v2 = " << (a * v2) << endl;
+		      (*testout) << "an * v1 = " << (an * v1) << endl;
+		      (*testout) << "an * v2 = " << (an * v2) << endl;
+		      
+		      (*testout) << "vii = " << vii11 << ", " << vii12 << ", " << vii22 << endl;
+		      (*testout) << "lambdai = " << lambda1 << ", " << lambda2 << endl;
+		      (*testout) << "rs = " << rs1 << ", " << rs2 << endl;
+		      continue;
+		    }
+		}
+
+	      if (out1)
+		v1 = an;
+	      else
+		v2 = an;
+	    }
+	}
+      
+      return 1;
+
+      /*
+      (*testout) << "overlap trig " << p1 << p2 << p3 << endl;
+      (*testout) << "upi = " << upi << endl;
+      (*testout) << "v1 = " << v1 << " v2 = " << v2 << endl;
+      */
+
+      switch (upi)
+	{
+	case 1:
+	  {
+	    v1 = p2 - p1;
+	    v2 = p3 - p1;
+	    break;
+	  }
+	case 2:
+	  {
+	    v1 = p3 - p2;
+	    v2 = p1 - p2;
+	    break;
+	  }
+	case 3:
+	  {
+	    v1 = p1 - p3;
+	    v2 = p2 - p3;
+	    break;
+	  }
+	}
+
+      v1 /= v1.Length();
+      v2 /= v2.Length();
+      Cross (v1, v2, n);
+      n /= n.Length();
+
+      //      (*testout) << "orig v1, v2 = " << v1 << ", " << v2 << endl;
+
+      
+      for (i = 1; i <= freesetfaces.Size(); i++)
+	{
+	  if ( (freesetfaces.Get(i).i1 == lpiu) || 
+	       (freesetfaces.Get(i).i2 == lpiu) ||
+	       (freesetfaces.Get(i).i3 == lpiu) )
+	    {
+	      /*
+	      (*testout) << "v1, v2, now = " << v1 << ", " << v2 << endl;
+
+	      // freeface has point
+	      (*testout) << "freesetface: "
+			 << freesetfaces.Get(i).i1 << " "
+			 << freesetfaces.Get(i).i2 << " "
+			 << freesetfaces.Get(i).i3 << " ";
+	      */
+
+	      Vec3d a (freesetinequ.Get(i, 1),
+		       freesetinequ.Get(i, 2),
+		       freesetinequ.Get(i, 3));
+	      //	      (*testout) << "a = " <<  a << endl;
+
+
+	      Vec3d an;
+	      Cross (a, n, an);
+	      double lan = an.Length();
+	      
+	      //	      (*testout) << "an = " << an << endl;
+
+	      if (lan < 1e-10)
+		continue;
+
+	      an /= lan;
+
+	      //	      (*testout) << "a*v1 = " << (a*v1) << " a*v2 = " << (a*v2) << endl;
+	      
+	      int out1 = (a * v1) > 0;
+	      // int out2 = (a * v2) > 0;
+
+
+	      //	      (*testout) << "out1, 2 = " << out1 << ", " << out2 << endl;
+
+	      
+	      double vii11 = v1 * v1;
+	      double vii12 = v1 * v2;
+	      double vii22 = v2 * v2;
+	      double det = vii11 * vii22 - vii12 * vii12;
+	      if ( fabs (det) < 1e-10 )
+		continue;
+	      double rs1 = an * v1;
+	      double rs2 = an * v2;
+	      
+	      double lambda1 = rs1 * vii22 - rs2 * vii12;
+	      double lambda2 = rs2 * vii11 - rs1 * vii12;
+
+	      //	      (*testout) << "lambda1, lambda2 = " << lambda1 << ", " << lambda2 << endl;
+
+
+	      if (fabs (lambda1) > fabs (lambda2))
+		{
+		  if (lambda1 < 0)
+		    an *= -1;
+		}
+	      else
+		{
+		  if (lambda2 < 0)
+		    an *= -1;
+		}
+
+
+	      if (lambda1 * lambda2 < 0)
+		{
+		  if (fabs (lambda1) > 1e-14 && fabs (lambda2) > 1e-14)
+		    {
+		      //		      (*mycout) << "lambda1 lambda2 < 0" << endl;
+		      (*testout) << "lambdai different" << endl;
+		      (*testout) << "v1 = " << v1 << endl;
+		      (*testout) << "v2 = " << v2 << endl;
+		      (*testout) << "n = " << n << endl;
+		      (*testout) << "a = " << a << endl;
+		      (*testout) << "an = " << an << endl;
+		      (*testout) << "a * v1 = " << (a * v1) << endl;
+		      (*testout) << "a * v2 = " << (a * v2) << endl;
+		      (*testout) << "an * v1 = " << (an * v1) << endl;
+		      (*testout) << "an * v2 = " << (an * v2) << endl;
+		      
+		      (*testout) << "vii = " << vii11 << ", " << vii12 << ", " << vii22 << endl;
+		      (*testout) << "lambdai = " << lambda1 << ", " << lambda2 << endl;
+		      (*testout) << "rs = " << rs1 << ", " << rs2 << endl;
+		      continue;
+		    }
+		}
+
+	      if (out1)
+		v1 = an;
+	      else
+		v2 = an;
+
+
+
+	    }
+	}
+
+      return 1;
+    }
+
+
+
+  if (cnt == 2)
+    {
+      //      (*testout) << "tripoitns: " << p1 << " " << p2 << " " << p3 << endl;
+
+      // MARK(triinfz2);
+
+      int pi1 = 0, pi2 = 0, pi3 = 0;
+      Vec3d a1, a2;  // outer normals
+      Vec3d trivec;  // vector from common edge to third point of triangle
+      for (i = 1; i <= 3; i++)
+	if (pi.Get(i))
+	  {
+	    pi2 = pi1;
+	    pi1 = pi.Get(i);
+	  }
+	else
+	  pi3 = i;
+
+      switch (pi3)
+	{
+	case 1: trivec = (p1 - p2); break;
+	case 2: trivec = (p2 - p3); break;
+	case 3: trivec = (p3 - p2); break;
+	}
+
+      ARRAY<int> lpi(freezonepi.Size());
+      for (i = 1; i <= lpi.Size(); i++)
+	lpi.Elem(i) = 0;
+      lpi.Elem(pi1) = 1;
+      lpi.Elem(pi2) = 1;
+      
+      int ff1 = 0, ff2 = 0;
+      for (i = 1; i <= freesetfaces.Size(); i++)
+	{
+	  if (lpi.Get(freesetfaces.Get(i).i1) + 
+	      lpi.Get(freesetfaces.Get(i).i2) + 
+	      lpi.Get(freesetfaces.Get(i).i3) == 2)
+	    {
+	      ff2 = ff1;
+	      ff1 = i;
+	    }
+	}
+
+      if (ff2 == 0)
+	return 1;
+
+      a1 = Vec3d (freesetinequ.Get(ff1, 1),
+		  freesetinequ.Get(ff1, 2),
+		  freesetinequ.Get(ff1, 3));
+      a2 = Vec3d (freesetinequ.Get(ff2, 1),
+		  freesetinequ.Get(ff2, 2),
+		  freesetinequ.Get(ff2, 3));
+
+      if ( ( (a1 * trivec) > 0) || ( (a2 * trivec) > 0))
+	return 0;
+
+      return 1;
+    }
+
+
+  if (cnt == 3)
+    {
+      // MARK(triinfz3);  
+
+      ARRAY<int> lpi(freezonepi.Size());
+      for (i = 1; i <= lpi.Size(); i++)
+	lpi.Elem(i) = 0;
+
+      for (i = 1; i <= 3; i++)
+	lpi.Elem(pi.Get(i)) = 1;
+      
+      for (i = 1; i <= freesetfaces.Size(); i++)
+	{
+	  if (lpi.Get(freesetfaces.Get(i).i1) + 
+	      lpi.Get(freesetfaces.Get(i).i2) + 
+	      lpi.Get(freesetfaces.Get(i).i3) == 3)
+	    {
+	      return 0;
+	    }
+	}
+      return 1;
+    }
+
+  // MARK(triinfz0);  
+
+  
+  os1 = os2 = os3 = 0;
+  activefaces.SetSize(0);
+
+  // is point inside ?
+
+  for (i = 1; i <= freesetfaces.Size(); i++)
+    {
+      hos1 = freesetinequ.Get(i, 1) * p1.X() +
+	freesetinequ.Get(i, 2) * p1.Y() +
+	freesetinequ.Get(i, 3) * p1.Z() +
+	freesetinequ.Get(i, 4) > -1E-5;
+      
+      hos2 = freesetinequ.Get(i, 1) * p2.X() +
+	freesetinequ.Get(i, 2) * p2.Y() +
+	freesetinequ.Get(i, 3) * p2.Z() +
+	freesetinequ.Get(i, 4) > -1E-5;
+      
+      hos3 = freesetinequ.Get(i, 1) * p3.X() +
+	freesetinequ.Get(i, 2) * p3.Y() +
+	freesetinequ.Get(i, 3) * p3.Z() +
+	freesetinequ.Get(i, 4) > -1E-5;
+      
+      if (hos1 && hos2 && hos3) return 0;
+      
+      if (hos1) os1 = 1;
+      if (hos2) os2 = 1;
+      if (hos3) os3 = 1;
+      
+      if (hos1 || hos2 || hos3) activefaces.Append (i);
+    }
+  
+  if (!os1 || !os2 || !os3) return 1;
+
+  v1x = p2.X() - p1.X();
+  v1y = p2.Y() - p1.Y();
+  v1z = p2.Z() - p1.Z();
+
+  v2x = p3.X() - p1.X();
+  v2y = p3.Y() - p1.Y();
+  v2z = p3.Z() - p1.Z();
+
+  n.X() = v1y * v2z - v1z * v2y;
+  n.Y() = v1z * v2x - v1x * v2z;
+  n.Z() = v1x * v2y - v1y * v2x;
+  n /= n.Length();
+
+  allleft = allright = 1;
+  for (i = 1; i <= transfreezone.Size() && (allleft || allright); i++)
+    {
+      const Point3d & p = transfreezone.Get(i);
+      float scal = (p.X() - p1.X()) * n.X() +
+	(p.Y() - p1.Y()) * n.Y() +
+	(p.Z() - p1.Z()) * n.Z();
+
+      if ( scal >  1E-8 ) allleft = 0;
+      if ( scal < -1E-8 ) allright = 0;
+    }
+
+  if (allleft || allright) return 0;
+
+
+  lam1old = lam2old = lam1 = lam2 = 1.0 / 3.0;
+
+
+  //  testout << endl << endl << "Start minimizing" << endl;
+
+  it = 0;
+  int minit;
+  minit = 1000;
+  fold = 1E10;
+
+
+
+  while (1)
+    {
+      it++;
+
+      if (it > 1000) return -1;
+
+      if (lam1 < 0) lam1 = 0;
+      if (lam2 < 0) lam2 = 0;
+      if (lam1 + lam2 > 1) lam1 = 1 - lam2;
+
+      if (it > minit)
+	{
+	  (*testout) << "it = " << it << endl;
+	  (*testout) << "lam1/2 = " << lam1 << "  " << lam2 << endl;
+	}
+
+      hpx = p1.X() + lam1 * v1x + lam2 * v2x;
+      hpy = p1.Y() + lam1 * v1y + lam2 * v2y;
+      hpz = p1.Z() + lam1 * v1z + lam2 * v2z;
+
+      f = 0;
+
+      h11 = h12 = h22 = dflam1 = dflam2 = 0;
+      cntout = 0;
+
+      isin = 1;
+
+      for (i = 1; i <= activefaces.Size(); i++)
+	{
+	  ii = activefaces.Get(i);
+
+	  hf = freesetinequ.Get(ii, 1) * hpx +
+	    freesetinequ.Get(ii, 2) * hpy +
+	    freesetinequ.Get(ii, 3) * hpz +
+	    freesetinequ.Get(ii, 4);
+
+	  if (hf > -1E-7) isin = 0;
+
+	  hf += 1E-4;
+	  if (hf > 0)
+	    {
+	      f += hf * hf;
+
+	      v1n = freesetinequ.Get(ii, 1) * v1x +
+		freesetinequ.Get(ii, 2) * v1y +
+		freesetinequ.Get(ii, 3) * v1z;
+	      v2n = freesetinequ.Get(ii, 1) * v2x +
+		freesetinequ.Get(ii, 2) * v2y +
+		freesetinequ.Get(ii, 3) * v2z;
+
+	      h11 += 2 * v1n * v1n;
+	      h12 += 2 * v1n * v2n;
+	      h22 += 2 * v2n * v2n;
+	      dflam1 += 2 * hf * v1n;
+	      dflam2 += 2 * hf * v2n;
+	      cntout++;
+	    }
+	}
+
+      if (isin) return 1;
+
+      if (it > minit)
+	{
+	  (*testout) << "f = " << f
+		     << "  dfdlam = " << dflam1 << "  " << dflam2 << endl;
+	  (*testout) << "h = " << h11 << "  " << h12 << "  " << h22 << endl;
+	  (*testout) << "active: " << cntout << endl;
+	  (*testout) << "lam1-lam1old = " << (lam1 - lam1old) << endl;
+	  (*testout) << "lam2-lam2old = " << (lam2 - lam2old) << endl;
+	}
+
+
+      if (f >= fold)
+	{
+	  lam1 = 0.100000000000000 * lam1 + 0.9000000000000000 * lam1old;
+	  lam2 = 0.100000000000000 * lam2 + 0.9000000000000000 * lam2old;
+	}
+      else
+	{
+	  lam1old = lam1;
+	  lam2old = lam2;
+	  fold = f;
+
+
+	  if (f < 1E-9) return 1;
+
+	  h11 += 1E-10;
+	  h22 += 1E-10;
+	  c1 = - ( h22 * dflam1 - h12 * dflam2) / (h11 * h22 - h12 * h12);
+	  c2 = - (-h12 * dflam1 + h11 * dflam2) / (h11 * h22 - h12 * h12);
+	  alpha = 1;
+
+
+	  if (it > minit)
+	    (*testout) << "c1/2 = " << c1 << "  " << c2 << endl;
+
+	  act1 = lam1 <= 1E-6 && c1 <= 0;
+	  act2 = lam2 <= 1E-6 && c2 <= 0;
+	  act3 = lam1 + lam2 >= 1 - 1E-6 && c1 + c2 >= 0;
+
+	  if (it > minit)
+	    (*testout) << "act1,2,3 = " << act1 << act2 << act3 << endl;
+
+	  if (act1 && act2 || act1 && act3 || act2 && act3) return 0;
+
+	  if (act1)
+	    {
+	      c1 = 0;
+	      c2 = - dflam2 / h22;
+	    }
+
+	  if (act2)
+	    {
+	      c1 = - dflam1 / h11;
+	      c2 = 0;
+	    }
+
+	  if (act3)
+	    {
+	      c1 = - (dflam1 - dflam2) / (h11 + h22 - 2 * h12);
+	      c2 = -c1;
+	    }
+
+	  if (it > minit)
+	    (*testout) << "c1/2 now = " << c1 << "  " << c2 << endl;
+
+
+	  if (f > 100 * sqrt (sqr (c1) + sqr (c2))) return 0;
+
+
+	  if (lam1 + alpha * c1 < 0 && !act1)
+	    alpha = -lam1 / c1;
+	  if (lam2 + alpha * c2 < 0 && !act2)
+	    alpha = -lam2 / c2;
+	  if (lam1 + lam2 + alpha * (c1 + c2) > 1 && !act3)
+	    alpha = (1 - lam1 - lam2) / (c1 + c2);
+
+	  if (it > minit)
+	    (*testout) << "alpha = " << alpha << endl;
+
+	  lam1 += alpha * c1;
+	  lam2 += alpha * c2;
+	}
+    }
+}
+
+
+
+
+int vnetrule :: IsQuadInFreeZone (const Point3d & p1, 
+				  const Point3d & p2,
+				  const Point3d & p3, 
+				  const Point3d & p4, 
+				  const ARRAY<int> & pi, int newone)
+{
+  int fs;
+  int infreeset, cannot = 0;
+
+
+  static ARRAY<int> pfi(4), pfi2(4);
+
+  // convert from local index to freeset index
+  int i, j;
+  for (i = 1; i <= 4; i++)
+    {
+      pfi.Elem(i) = 0;
+      if (pi.Get(i))
+	{
+	  for (j = 1; j <= freezonepi.Size(); j++)
+	    if (freezonepi.Get(j) == pi.Get(i))
+	      pfi.Elem(i) = j;
+	}
+    }
+
+  for (fs = 1; fs <= freesets.Size(); fs++)
+    {
+      const ARRAY<int> & freeseti = *freesets.Get(fs);
+      for (i = 1; i <= 4; i++)
+	{
+	  pfi2.Elem(i) = 0;
+	  for (j = 1; j <= freeseti.Size(); j++)
+	    if (pfi.Get(i) == freeseti.Get(j))
+	      pfi2.Elem(i) = pfi.Get(i);
+	}
+
+      infreeset = IsQuadInFreeSet(p1, p2, p3, p4, fs, pfi2, newone);
+      if (infreeset == 1) return 1;
+      if (infreeset == -1) cannot = -1;
+    }
+  
+  return cannot;
+}
+
+
+int vnetrule :: IsQuadInFreeSet (const Point3d & p1, const Point3d & p2,
+				 const Point3d & p3, const Point3d & p4, 
+				 int fs, const ARRAY<int> & pi, int newone)
+{
+  int i;
+  
+  int cnt = 0;
+  for (i = 1; i <= 4; i++)
+    if (pi.Get(i)) cnt++;
+  
+  /*
+  (*testout) << "test quad in freeset: " << p1 << " - " << p2 << " - " << p3 << " - " << p4 << endl;
+  (*testout) << "pi = ";
+  for (i = 1; i <= pi.Size(); i++)
+    (*testout) << pi.Get(i) << " ";
+  (*testout) << endl;
+  (*testout) << "cnt = " << cnt  << endl;
+  */
+  if (cnt == 4)
+    {
+      return 1;
+    }
+
+  if (cnt == 3)
+    {
+      return 1;
+    }
+
+  static ARRAY<int> pi3(3);
+  int res;
+
+  pi3.Elem(1) = pi.Get(1);
+  pi3.Elem(2) = pi.Get(2);
+  pi3.Elem(3) = pi.Get(3);
+  res = IsTriangleInFreeSet (p1, p2, p3, fs, pi3, newone);
+  if (res) return res;
+
+
+  pi3.Elem(1) = pi.Get(2);
+  pi3.Elem(2) = pi.Get(3);
+  pi3.Elem(3) = pi.Get(4);
+  res = IsTriangleInFreeSet (p2, p3, p4, fs, pi3, newone);
+  if (res) return res;
+
+  pi3.Elem(1) = pi.Get(3);
+  pi3.Elem(2) = pi.Get(4);
+  pi3.Elem(3) = pi.Get(1);
+  res = IsTriangleInFreeSet (p3, p4, p1, fs, pi3, newone);
+  if (res) return res;
+
+  pi3.Elem(1) = pi.Get(4);
+  pi3.Elem(2) = pi.Get(1);
+  pi3.Elem(3) = pi.Get(2);
+  res = IsTriangleInFreeSet (p4, p1, p2, fs, pi3, newone);
+  return res;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+float vnetrule :: CalcPointDist (int pi, const Point3d & p) const
+{
+  float dx = p.X() - points.Get(pi).X();
+  float dy = p.Y() - points.Get(pi).Y();
+  float dz = p.Z() - points.Get(pi).Z();
+  
+  //  const threefloat * tf = &tolerances.Get(pi);
+  //  return tf->f1 * dx * dx + tf->f2 * dx * dy + tf->f3 * dy * dy;
+  return tolerances.Get(pi) * (dx * dx + dy * dy + dz * dz);
+}
+
+
+int vnetrule :: TestOk () const
+{
+  ARRAY<int> cntpused(points.Size());
+  ARRAY<int> edge1, edge2;
+  ARRAY<int> delf(faces.Size());
+  int i, j, k;
+  int pi1, pi2;
+  int found;
+
+  for (i = 1; i <= cntpused.Size(); i++)
+    cntpused.Elem(i) = 0;
+  for (i = 1; i <= faces.Size(); i++)
+    delf.Elem(i) = 0;
+  for (i = 1; i <= delfaces.Size(); i++)
+    delf.Elem(delfaces.Get(i)) = 1;
+
+
+  for (i = 1; i <= faces.Size(); i++)
+    if (delf.Get(i) || i > noldf)
+      for (j = 1; j <= faces.Get(i).GetNP(); j++)
+        cntpused.Elem(faces.Get(i).PNum(j))++;
+
+  for (i = 1; i <= cntpused.Size(); i++)
+    if (cntpused.Get(i) > 0 && cntpused.Get(i) < 2)
+      {
+	return 0;
+      }
+
+
+  //  (*testout) << endl;
+  for (i = 1; i <= faces.Size(); i++)
+    {
+      //      (*testout) << "face " << i << endl;
+      for (j = 1; j <= faces.Get(i).GetNP(); j++)
+	{
+	  pi1 = 0; pi2 = 0;
+	  if (delf.Get(i))
+	    {
+	      pi1 = faces.Get(i).PNumMod(j);
+	      pi2 = faces.Get(i).PNumMod(j+1);
+	    }
+	  if (i > noldf)
+	    {
+	      pi1 = faces.Get(i).PNumMod(j+1);
+	      pi2 = faces.Get(i).PNumMod(j);
+	    }
+
+	  found = 0;
+	  if (pi1)
+	    {
+	      for (k = 1; k <= edge1.Size(); k++)
+		if (edge1.Get(k) == pi1 && edge2.Get(k) == pi2)
+		  {
+		    found = 1;
+		    edge1.DeleteElement(k);
+		    edge2.DeleteElement(k);
+		    k--;
+		    //		    (*testout) << "Del edge " << pi1 << "-" << pi2 << endl;
+		  }
+	      if (!found)
+		{
+		  edge1.Append (pi2);
+		  edge2.Append (pi1);
+		  //		  (*testout) << "Add edge " << pi1 << "-" << pi2 << endl;
+		}
+	    }
+	}
+    }
+
+
+  if (edge1.Size() > 0)
+    {
+      return 0;
+    }
+
+  /*
+    cntpused.SetSize(freezone.Size());
+    for (i = 1; i <= cntpused.Size(); i++)
+    cntpused[i] = 0;
+
+    for (i = 1; i <= freefaces.Size(); i++)
+    {
+    cntpused[freefaces[i].i1]++;
+    cntpused[freefaces[i].i2]++;
+    cntpused[freefaces[i].i3]++;
+    }
+
+    for (i = 1; i <= cntpused.Size(); i++)
+    if (cntpused[i] < 3)
+    {
+    (*mycout) << "Fall 3" << endl;
+    return 0;
+    }
+
+
+
+    for (i = 1; i <= freefaces.Size(); i++)
+    {
+    for (j = 1; j <= 3; j++)
+    {
+    if (j == 1)
+    {
+    pi1 = freefaces[i].i1;
+    pi2 = freefaces[i].i2;
+    }
+    if (j == 2)
+    {
+    pi1 = freefaces[i].i2;
+    pi2 = freefaces[i].i3;
+    }
+    if (j == 3)
+    {
+    pi1 = freefaces[i].i3;
+    pi2 = freefaces[i].i1;
+    }
+
+    found = 0;
+    for (k = 1; k <= edge1.Size(); k++)
+    if (edge1[k] == pi1 && edge2[k] == pi2)
+    {
+    found = 1;
+    edge1.DeleteElement(k);
+    edge2.DeleteElement(k);
+    k--;
+    }
+
+    if (!found)
+    {
+    edge1.Append (pi2);
+    edge2.Append (pi1);
+    }
+    }
+    }
+
+    if (edge1.Size() > 0)
+    {
+    (*mycout) << "Fall 4" << endl;
+    return 0;
+    }
+    */
+  return 1;
+}
+
+
+int vnetrule :: IsDelFace (int fn) const
+{
+  int i;
+  for (i = 1; i <= GetNDelF(); i++)
+    if (GetDelFace(i) == fn) return 1;
+  return 0;
+}
+
+}
diff --git a/contrib/Netgen/libsrc/meshing/parser2.cpp b/contrib/Netgen/libsrc/meshing/parser2.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..eb502cfee3a88f063fe0cf7169d26a400afd4b3a
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/parser2.cpp
@@ -0,0 +1,603 @@
+#include <mystdlib.h>
+#include "meshing.hpp"
+
+#ifdef WIN32
+#define COMMASIGN ':'
+#else
+#define COMMASIGN ','
+#endif
+
+
+namespace netgen
+{
+
+
+void LoadMatrixLine (istream & ist, DenseMatrix & m, int line)
+{
+  char ch;
+  int pnum;
+  float f;
+
+  ist >> ch;
+  while (ch != '}')
+    {
+      ist.putback (ch);
+      ist >> f;
+      ist >> ch;
+      ist >> pnum;
+
+      if (ch == 'x' || ch == 'X')
+	m.Elem(line, 2 * pnum - 1) = f;
+      if (ch == 'y' || ch == 'Y')
+	m.Elem(line, 2 * pnum) = f;
+
+      ist >> ch;
+      if (ch == COMMASIGN)
+	ist >> ch;
+    }
+}
+
+
+void netrule :: LoadRule (istream & ist)
+{
+  char buf[256];
+  char ch;
+  Point2d p;
+  INDEX_2 lin;
+  int i, j;
+  DenseMatrix tempoldutonewu(20, 20), tempoldutofreearea(20, 20),
+    tempoldutofreearealimit(20, 20);
+
+  tempoldutonewu = 0;
+  tempoldutofreearea = 0;
+  tempoldutofreearealimit = 0;
+
+  noldp = 0;
+  noldl = 0;
+
+  ist.get (buf, sizeof(buf), '"');
+  ist.get (ch);
+  ist.get (buf, sizeof(buf), '"');
+  ist.get (ch);
+
+  // if(name != NULL) 
+  delete [] name;
+  name = new char[strlen (buf) + 1];
+  strcpy (name, buf);
+  //(*testout) << "name " << name << endl;
+  //  (*mycout) << "Rule " << name << " found." << endl;
+
+  do
+    {
+      ist >> buf;
+
+      //(*testout) << "buf " << buf << endl;
+
+      if (strcmp (buf, "quality") == 0)
+
+	{
+	  ist >> quality;
+	}
+
+      else if (strcmp (buf, "mappoints") == 0)
+	{
+	  ist >> ch;
+
+	  while (ch == '(')
+	    {
+	      ist >> p.X();
+	      ist >> ch;    // ','
+	      ist >> p.Y();
+	      ist >> ch;    // ')'
+
+	      points.Append (p);
+	      noldp++;
+
+	      tolerances.SetSize (noldp);
+	      tolerances.Elem(noldp).f1 = 1.0;
+	      tolerances.Elem(noldp).f2 = 0;
+	      tolerances.Elem(noldp).f3 = 1.0;
+
+	      ist >> ch;
+	      while (ch != ';')
+		{
+		  if (ch == '{')
+		    {
+		      ist >> tolerances.Elem(noldp).f1;
+		      ist >> ch;  // ','
+		      ist >> tolerances.Elem(noldp).f2;
+		      ist >> ch;  // ','
+		      ist >> tolerances.Elem(noldp).f3;
+		      ist >> ch;  // '}'
+		    }
+		  else if (ch == 'd')
+		    {
+		      //            delpoints.Append (noldp);
+		      ist >> ch; // 'e'
+		      ist >> ch; // 'l'
+		    }
+
+		  ist >> ch;
+		}
+
+	      ist >> ch;
+	    }
+
+	  ist.putback (ch);
+	}
+
+
+      else if (strcmp (buf, "maplines") == 0)
+	{
+	  ist >> ch;
+
+	  while (ch == '(')
+	    {
+	      ist >> lin.I1();
+	      ist >> ch;    // ','
+	      ist >> lin.I2();
+	      ist >> ch;    // ')'
+
+
+	      //(*testout) << "read line " << lin.I1() << " " << lin.I2() << endl;
+	      lines.Append (lin);
+	      linevecs.Append (points.Get(lin.I2()) - points.Get(lin.I1()));
+	      noldl++;
+	      linetolerances.SetSize (noldl);
+	      linetolerances.Elem(noldl).f1 = 0;
+	      linetolerances.Elem(noldl).f2 = 0;
+	      linetolerances.Elem(noldl).f3 = 0;
+
+	      //(*testout) << "mapl1" << endl; 
+	      ist >> ch;
+	      while (ch != ';')
+		{
+		  //(*testout) << "working on character \""<<ch<<"\""<< endl;
+		  if (ch == '{')
+		    {
+		      ist >> linetolerances.Elem(noldl).f1;
+		      ist >> ch;  // ','
+		      ist >> linetolerances.Elem(noldl).f2;
+		      ist >> ch;  // ','
+		      ist >> linetolerances.Elem(noldl).f3;
+		      ist >> ch;  // '}'
+		    }
+		  else if (ch == 'd')
+		    {
+		      dellines.Append (noldl);
+		      ist >> ch; // 'e'
+		      ist >> ch; // 'l'
+		      //(*testout) << "read del" << endl;
+		    }
+
+		  ist >> ch;
+		  //(*testout) << "read character \""<<ch<<"\""<< endl;
+		}
+
+	      ist >> ch;
+	      //(*testout) << "read next character \""<<ch<<"\""<< endl;
+	    }
+	  
+
+	  ist.putback (ch);
+	}
+
+      else if (strcmp (buf, "newpoints") == 0)
+	{
+	  ist >> ch;
+
+	  while (ch == '(')
+	    {
+	      ist >> p.X();
+	      ist >> ch;    // ','
+	      ist >> p.Y();
+	      ist >> ch;    // ')'
+
+	      points.Append (p);
+
+	      ist >> ch;
+	      while (ch != ';')
+		{
+		  if (ch == '{')
+		    {
+		      LoadMatrixLine (ist, tempoldutonewu,
+				      2 * (points.Size()-noldp) - 1);
+
+		      ist >> ch; // '{'
+		      LoadMatrixLine (ist, tempoldutonewu,
+				      2 * (points.Size()-noldp));
+		    }
+
+		  ist >> ch;
+		}
+
+	      ist >> ch;
+	    }
+
+	  ist.putback (ch);
+	}
+
+      else if (strcmp (buf, "newlines") == 0)
+	{
+	  ist >> ch;
+
+	  while (ch == '(')
+	    {
+	      ist >> lin.I1();
+	      ist >> ch;    // ','
+	      ist >> lin.I2();
+	      ist >> ch;    // ')'
+
+	      lines.Append (lin);
+	      linevecs.Append (points.Get(lin.I2()) - points.Get(lin.I1()));
+
+	      ist >> ch;
+	      while (ch != ';')
+		{
+		  ist >> ch;
+		}
+
+	      ist >> ch;
+	    }
+
+	  ist.putback (ch);
+	}
+
+      else if (strcmp (buf, "freearea") == 0)
+	{
+	  ist >> ch;
+
+	  while (ch == '(')
+	    {
+	      ist >> p.X();
+	      ist >> ch;    // ','
+	      ist >> p.Y();
+	      ist >> ch;    // ')'
+
+	      freezone.Append (p);
+	      freezonelimit.Append (p);
+
+	      ist >> ch;
+	      while (ch != ';')
+		{
+		  if (ch == '{')
+		    {
+		      LoadMatrixLine (ist, tempoldutofreearea,
+				      2 * freezone.Size() - 1);
+
+		      ist >> ch; // '{'
+		      LoadMatrixLine (ist, tempoldutofreearea,
+				      2 * freezone.Size());
+		    }
+
+		  ist >> ch;
+		}
+
+	      ist >> ch;
+	    }
+
+	  for (i = 1; i <= tempoldutofreearealimit.Height(); i++)
+	    for (j = 1; j <= tempoldutofreearealimit.Width(); j++)
+	      tempoldutofreearealimit.Elem(i,j) =
+		tempoldutofreearea.Elem(i,j);
+
+
+	  ist.putback (ch);
+	}    
+      else if (strcmp (buf, "freearea2") == 0)
+	{
+	  ist >> ch;
+	  int freepi = 0;
+	  tempoldutofreearealimit = 0;
+
+	  while (ch == '(')
+	    {
+	      freepi++;
+
+	      ist >> p.X();
+	      ist >> ch;    // ','
+	      ist >> p.Y();
+	      ist >> ch;    // ')'
+
+	      freezonelimit.Elem(freepi) = p;
+	  
+	      ist >> ch;
+	      while (ch != ';')
+		{
+		  if (ch == '{')
+		    {
+		      LoadMatrixLine (ist, tempoldutofreearealimit,
+				      2 * freepi - 1);
+
+		      ist >> ch; // '{'
+		      LoadMatrixLine (ist, tempoldutofreearealimit,
+				      2 * freepi);
+		    }
+
+		  ist >> ch;
+		}
+	  
+	      ist >> ch;
+	    }
+
+	  ist.putback (ch);
+	}
+
+      else if (strcmp (buf, "elements") == 0)
+	{
+	  ist >> ch;
+
+	  while (ch == '(')
+	    {
+	      elements.Append (Element2d());
+
+	      ist >> elements.Last().PNum(1);
+	      ist >> ch;    // ','
+	  
+	      if (ch == COMMASIGN)
+		{
+		  ist >> elements.Last().PNum(2);
+		  ist >> ch;    // ','
+		}
+	      if (ch == COMMASIGN)
+		{
+		  ist >> elements.Last().PNum(3);
+		  ist >> ch;    // ','
+		}
+	      if (ch == COMMASIGN)
+		{
+		  elements.Last().SetType (QUAD);
+		  ist >> elements.Last().PNum(4);
+		  ist >> ch;    // ','
+		  
+		  // const Element2d & el = elements.Last();
+		  /*
+		  orientations.Append (threeint(el.PNum(1), el.PNum(2), el.PNum(3)));
+		  orientations.Append (threeint(el.PNum(2), el.PNum(3), el.PNum(4)));
+		  orientations.Append (threeint(el.PNum(3), el.PNum(4), el.PNum(1)));
+		  orientations.Append (threeint(el.PNum(4), el.PNum(1), el.PNum(2)));
+		  */
+		}
+
+	      ist >> ch;
+	      while (ch != ';')
+		{
+		  ist >> ch;
+		}
+
+	      ist >> ch;
+	    }
+
+	  ist.putback (ch);
+	}
+
+      else if (strcmp (buf, "orientations") == 0)
+
+	{
+	  ist >> ch;
+
+	  while (ch == '(')
+	    {
+	      //        threeint a = threeint();
+	      orientations.Append (threeint());
+
+	      ist >> orientations.Last().i1;
+	      ist >> ch;    // ','
+	      ist >> orientations.Last().i2;
+	      ist >> ch;    // ','
+	      ist >> orientations.Last().i3;
+	      ist >> ch;    // ','
+
+	      ist >> ch;
+	      while (ch != ';')
+		{
+		  ist >> ch;
+		}
+
+	      ist >> ch;
+	    }
+
+	  ist.putback (ch);
+	}
+
+      else if (strcmp (buf, "endrule") != 0)
+	{
+	  PrintSysError ("Parser error, unknown token ", buf);
+	}
+    }
+  while (!ist.eof() && strcmp (buf, "endrule") != 0);
+
+  //(*testout) << "loadr1" << endl;
+
+  oldutonewu.SetSize (2 * (points.Size() - noldp), 2 * noldp);
+  oldutofreearea.SetSize (2 * freezone.Size(), 2 * noldp);
+  oldutofreearealimit.SetSize (2 * freezone.Size(), 2 * noldp);
+
+  for (i = 1; i <= oldutonewu.Height(); i++)
+    for (j = 1; j <= oldutonewu.Width(); j++)
+      oldutonewu.Elem(i, j) = tempoldutonewu.Elem(i, j);
+
+  for (i = 1; i <= oldutofreearea.Height(); i++)
+    for (j = 1; j <= oldutofreearea.Width(); j++)
+      oldutofreearea.Elem(i, j) = tempoldutofreearea.Elem(i, j);
+
+  for (i = 1; i <= oldutofreearea.Height(); i++)
+    for (j = 1; j <= oldutofreearea.Width(); j++)
+      oldutofreearealimit.Elem(i, j) = tempoldutofreearealimit.Elem(i, j);
+
+  freesetinequ.SetSize (freezone.Size());
+
+
+  //(*testout) << "loadr2" << endl;
+
+  {
+    char ok;
+    int minn;
+    ARRAY<int> pnearness (noldp);
+
+    for (i = 1; i <= pnearness.Size(); i++)
+      pnearness.Elem(i) = 1000;
+
+    for (j = 1; j <= 2; j++)
+      pnearness.Elem(GetPointNr (1, j)) = 0;
+
+    //(*testout) << "loadr3" << endl;
+    do
+      {
+	ok = 1;
+
+	for (i = 1; i <= noldl; i++)
+	  {
+	    minn = 1000;
+	    for (j = 1; j <= 2; j++)
+	      minn = min2 (minn, pnearness.Get(GetPointNr (i, j)));
+
+	    for (j = 1; j <= 2; j++)
+	      if (pnearness.Get(GetPointNr (i, j)) > minn+1)
+		{
+		  ok = 0;
+		  pnearness.Elem(GetPointNr (i, j)) = minn+1;
+		}
+	  }
+      }
+    while (!ok);
+    //(*testout) << "loadr4" << endl;
+
+    lnearness.SetSize (noldl);
+
+    for (i = 1; i <= noldl; i++)
+      {
+	lnearness.Elem(i) = 0;
+	for (j = 1; j <= 2; j++)
+	  lnearness.Elem(i) += pnearness.Get(GetPointNr (i, j));
+      }
+  }
+  //(*testout) << "loadr5" << endl;
+
+  oldutofreearea_i.SetSize (10);
+  for (i = 0; i < oldutofreearea_i.Size(); i++)
+    {
+      oldutofreearea_i[i] = new DenseMatrix (oldutofreearea.Height(), oldutofreearea.Width());
+      DenseMatrix & mati = *oldutofreearea_i[i];
+      for (j = 0; j < oldutofreearea.Height(); j++)
+	for (int k = 0; k < oldutofreearea.Width(); k++)
+	  mati(j,k) = 1.0 / (i+1) * oldutofreearea(j,k) + (1 - 1.0/(i+1)) * oldutofreearealimit(j,k);
+    }
+
+  //(*testout) << "loadr6" << endl;
+}
+
+
+
+
+extern const char * triarules[];
+extern const char * quadrules[];
+
+void Meshing2 :: LoadRules (const char * filename)
+{
+  char buf[256];
+  istream * ist;
+  //char *tr1 = NULL;
+  string tr1;
+
+  /*
+  ifstream ist (filename);
+  if (!ist.good())
+    {
+      cerr << "Rule description file " << filename << " not found" << endl;
+      exit (1);
+    }
+  */
+
+
+  if (filename)
+    {
+      //      (*mycout) << "rule-filename = " << filename << endl;
+      ist = new ifstream (filename);
+    }
+  else 
+    {
+      /* connect tetrules to one string */
+      const char ** hcp;
+
+      if (!mparam.quad)
+	{
+	  hcp = triarules;
+	  PrintMessage (3, "load internal triangle rules");
+	}
+      else
+	{
+	  hcp = quadrules;
+	  PrintMessage (3, "load internal quad rules");
+	  // LoadRules ("rules/quad.rls");
+	}
+
+      size_t len = 0;
+      while (*hcp)
+	{
+	  //	  (*testout) << "POS2 *hcp " << *hcp << endl;
+	  len += strlen (*hcp);
+	  hcp++;
+	}
+      //tr1 = new char[len+1];
+      //tr1[0] = 0;
+      tr1.reserve(len+1);
+
+
+      if (!mparam.quad)
+	hcp = triarules;
+      else
+	hcp = quadrules;
+
+
+      //char * tt1 = tr1;
+      while (*hcp)
+	{
+	  //strcat (tt1, *hcp);
+	  //tt1 += strlen (*hcp);
+	  tr1.append(*hcp);
+	  hcp++;
+	}
+      
+#ifdef WIN32
+      // VC++ 2005 workaround
+	  for(string::size_type i=0; i<tr1.size(); i++)
+	if(tr1[i] == ',')
+	  tr1[i] = ':';
+#endif
+
+      ist = new istringstream (tr1);
+    }
+
+
+  if (!ist->good())
+    {
+      cerr << "Rule description file " << filename << " not found" << endl;
+      delete ist;
+      exit (1);
+    }
+    
+  while (!ist->eof())
+    {
+      buf[0] = 0;
+      (*ist) >> buf;
+
+      if (strcmp (buf, "rule") == 0)
+	{
+	  //(*testout) << "found rule" << endl;
+	  netrule * rule = new netrule;
+	  //(*testout) << "fr1" << endl;
+	  rule -> LoadRule(*ist);
+	  //(*testout) << "fr2" << endl;
+	  
+	  rules.Append (rule);
+	}
+      //(*testout) << "loop" << endl;
+    }
+  //(*testout) << "POS3" << endl;
+
+  delete ist;
+  //delete [] tr1;
+}
+
+}
diff --git a/contrib/Netgen/libsrc/meshing/parser3.cpp b/contrib/Netgen/libsrc/meshing/parser3.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..382ae9dfc145a3d2aa6d0e5a6c9ab44092a3022c
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/parser3.cpp
@@ -0,0 +1,1019 @@
+#include <mystdlib.h>
+#include "meshing.hpp"
+
+#ifdef WIN32
+#define COMMASIGN ':'
+#else
+#define COMMASIGN ','
+#endif
+
+
+namespace netgen
+{
+
+extern const char * tetrules[];
+
+void LoadVMatrixLine (istream & ist, DenseMatrix & m, int line)
+{
+  char ch;
+  int pnum;
+  float f;
+  
+  ist >> ch;
+  while (ch != '}')
+    {
+      ist.putback (ch);
+      ist >> f;
+      ist >> ch;
+      ist >> pnum;
+      
+      if (ch == 'x' || ch == 'X')
+	m.Elem(line, 3 * pnum - 2) = f;
+      if (ch == 'y' || ch == 'Y')
+	m.Elem(line, 3 * pnum - 1) = f;
+      if (ch == 'z' || ch == 'Z')
+	m.Elem(line, 3 * pnum    ) = f;
+
+      if (ch == 'p' || ch == 'P')
+	{
+	  m.Elem(line  , 3 * pnum-2) = f;
+	  m.Elem(line+1, 3 * pnum-1) = f;
+	  m.Elem(line+2, 3 * pnum  ) = f;
+	}
+
+      ist >> ch;
+      if (ch == COMMASIGN)
+	ist >> ch;
+    }
+}
+
+
+
+
+
+int vnetrule :: NeighbourTrianglePoint (const threeint & t1, const threeint & t2) const
+{
+  ARRAY<int> tr1(3);
+  ARRAY<int> tr2(3);
+  tr1.Elem(1)=t1.i1;
+  tr1.Elem(2)=t1.i2;
+  tr1.Elem(3)=t1.i3;
+  tr2.Elem(1)=t2.i1;
+  tr2.Elem(2)=t2.i2;
+  tr2.Elem(3)=t2.i3;
+
+
+  int ret=0;
+
+  for (int i=1; i<=3; i++)
+    {
+      for (int j=1; j<=3; j++)
+	{
+	  if ((tr1.Get(i)==tr2.Get(j) && tr1.Get((i%3)+1)==tr2.Get((j%3)+1)) ||
+              (tr1.Get(i)==tr2.Get((j%3)+1) && tr1.Get((i%3)+1)==tr2.Get(j)))
+	    {ret = tr2.Get((j+1)%3+1);}
+	}      
+    }
+
+  return ret;
+
+}
+
+void vnetrule :: LoadRule (istream & ist)
+{
+  char buf[256];
+  char ch, ok;
+  Point3d p;
+  Element2d face;
+  int i, j, i1, i2, i3, fs, ii, ii1, ii2, ii3;
+  twoint edge;
+  DenseMatrix tempoldutonewu(30, 20), 
+    tempoldutofreezone(30, 20),
+    tempoldutofreezonelimit(30, 20),
+    tfz(20, 20),
+    tfzl(20, 20);
+
+  tempoldutonewu = 0;
+  tempoldutofreezone = 0;
+  tfz = 0;
+  tfzl = 0;
+
+
+  noldp = 0;
+  noldf = 0;
+
+  ist.get (buf, sizeof(buf), '"');
+  ist.get (ch);
+  ist.get (buf, sizeof(buf), '"');
+  ist.get (ch);
+
+  delete [] name;
+  name = new char[strlen (buf) + 1];
+  strcpy (name, buf);
+  //  (*mycout) << "Rule " << name << " found." << endl;
+
+  do
+    {
+      ist >> buf;
+
+      if (strcmp (buf, "quality") == 0)
+
+	{
+	  ist >> quality;
+	}
+
+      else if (strcmp (buf, "flags") == 0)
+	{
+	  ist >> ch;
+	  while (ch != ';')
+	    {
+	      flags.Append (ch);
+	      ist >> ch;
+	    }
+	}
+
+      else if (strcmp (buf, "mappoints") == 0)
+	{
+	  ist >> ch;
+
+	  while (ch == '(')
+	    {
+	      ist >> p.X();
+	      ist >> ch;    // ','
+	      ist >> p.Y();
+	      ist >> ch;    // ','
+	      ist >> p.Z();
+	      ist >> ch;    // ')'
+
+	      points.Append (p);
+	      noldp++;
+
+	      tolerances.SetSize (noldp);
+	      tolerances.Elem(noldp) = 1;
+
+	      ist >> ch;
+	      while (ch != ';')
+		{
+		  if (ch == '{')
+		    {
+		      ist >> tolerances.Elem(noldp);
+		      ist >> ch;  // '}'
+		    }
+
+		  ist >> ch;
+		}
+
+	      ist >> ch;
+	    }
+
+	  ist.putback (ch);
+	}
+
+
+      else if (strcmp (buf, "mapfaces") == 0)
+	{
+	  ist >> ch;
+
+	  while (ch == '(')
+	    {
+	      face.SetType(TRIG);
+	      ist >> face.PNum(1);
+	      ist >> ch;    // ','
+	      ist >> face.PNum(2);
+	      ist >> ch;    // ','
+	      ist >> face.PNum(3);
+	      ist >> ch;    // ')' or ','
+	      if (ch == COMMASIGN)
+		{
+		  face.SetType(QUAD);
+		  ist >> face.PNum(4);
+		  ist >> ch;    // ')' 
+		}
+	      faces.Append (face);
+	      noldf++;
+
+	      ist >> ch;
+	      while (ch != ';')
+		{
+		  if (ch == 'd')
+		    {
+		      delfaces.Append (noldf);
+		      ist >> ch; // 'e'
+		      ist >> ch; // 'l'
+		    }
+
+		  ist >> ch;
+		}
+
+	      ist >> ch;
+	    }
+
+	  ist.putback (ch);
+	}
+
+      else if (strcmp (buf, "mapedges") == 0)
+	{
+	  ist >> ch;
+
+	  while (ch == '(')
+	    {
+	      ist >> edge.i1;
+	      ist >> ch;    // ','
+	      ist >> edge.i2;
+	      ist >> ch;    // ')'
+
+	      edges.Append (edge);
+
+	      ist >> ch;
+	      while (ch != ';')
+		{
+		  ist >> ch;
+		}
+
+	      ist >> ch;
+	    }
+
+	  ist.putback (ch);
+	}
+
+
+      else if (strcmp (buf, "newpoints") == 0)
+	{
+	  ist >> ch;
+
+	  while (ch == '(')
+	    {
+	      ist >> p.X();
+	      ist >> ch;    // ','
+	      ist >> p.Y();
+	      ist >> ch;    // ','
+	      ist >> p.Z();
+	      ist >> ch;    // ')'
+
+	      points.Append (p);
+
+	      ist >> ch;
+	      while (ch != ';')
+		{
+		  if (ch == '{')
+		    {
+		      LoadVMatrixLine (ist, tempoldutonewu,
+				       3 * (points.Size()-noldp) - 2);
+
+		      ist >> ch; // '{'
+		      LoadVMatrixLine (ist, tempoldutonewu,
+				       3 * (points.Size()-noldp) - 1);
+
+		      ist >> ch; // '{'
+		      LoadVMatrixLine (ist, tempoldutonewu,
+				       3 * (points.Size()-noldp)    );
+		    }
+
+		  ist >> ch;
+		}
+
+	      ist >> ch;
+	    }
+
+	  ist.putback (ch);
+	}
+
+      else if (strcmp (buf, "newfaces") == 0)
+	{
+	  ist >> ch;
+
+	  while (ch == '(')
+	    {
+	      face.SetType(TRIG);
+	      ist >> face.PNum(1);
+	      ist >> ch;    // ','
+	      ist >> face.PNum(2);
+	      ist >> ch;    // ','
+	      ist >> face.PNum(3);
+	      ist >> ch;    // ')' or ','
+	      if (ch == COMMASIGN)
+		{
+		  face.SetType(QUAD);
+		  ist >> face.PNum(4);
+		  ist >> ch;    // ')' 
+		}
+	      faces.Append (face);
+
+	      ist >> ch;
+	      while (ch != ';')
+		{
+		  ist >> ch;
+		}
+
+	      ist >> ch;
+	    }
+
+	  ist.putback (ch);
+	}
+
+      else if (strcmp (buf, "freezone") == 0)
+	{
+	  ist >> ch;
+	
+	  while (ch == '(')
+	    {
+	      ist >> p.X();
+	      ist >> ch;    // ','
+	      ist >> p.Y();
+	      ist >> ch;    // ','
+	      ist >> p.Z();
+	      ist >> ch;    // ')'
+	    
+	      freezone.Append (p);
+	    
+	      ist >> ch;
+	      while (ch != ';')
+		{
+		  if (ch == '{')
+		    {
+		      LoadVMatrixLine (ist, tempoldutofreezone,
+				       3 * freezone.Size() - 2);
+		    
+		      ist >> ch; // '{'
+		      LoadVMatrixLine (ist, tempoldutofreezone,
+				       3 * freezone.Size() - 1);
+		    
+		      ist >> ch; // '{'
+		      LoadVMatrixLine (ist, tempoldutofreezone,
+				       3 * freezone.Size()    );
+		    }
+		
+		  ist >> ch;
+		}
+	    
+	      ist >> ch;
+	    }
+	
+	  ist.putback (ch);
+	}
+      else if (strcmp (buf, "freezone2") == 0)
+	{
+	  int k, nfp;
+
+	  nfp = 0;
+	  ist >> ch;
+
+	  DenseMatrix hm1(3, 50), hm2(50, 50), hm3(50, 50);
+	  hm3 = 0;
+
+	  while (ch == '{')
+	    {
+	      hm1 = 0;
+	      nfp++;
+	      LoadVMatrixLine (ist, hm1, 1);
+
+	      for (i = 1; i <= points.Size(); i++)
+		tfz.Elem(nfp, i) = hm1.Get(1, 3*i-2);
+
+
+	      p.X() = p.Y() = p.Z() = 0;
+	      for (i = 1; i <= points.Size(); i++)
+		{
+		  p.X() += hm1.Get(1, 3*i-2) * points.Get(i).X();
+		  p.Y() += hm1.Get(1, 3*i-2) * points.Get(i).Y();
+		  p.Z() += hm1.Get(1, 3*i-2) * points.Get(i).Z();
+		}
+	      freezone.Append (p);
+	      freezonelimit.Append (p);
+	    
+	      hm2 = 0;
+	      for (i = 1; i <= 3 * noldp; i++)
+		hm2.Elem(i, i) = 1;
+	      for (i = 1; i <= 3 * noldp; i++)
+		for (j = 1; j <= 3 * (points.Size() - noldp); j++)
+		  hm2.Elem(j + 3 * noldp, i) = tempoldutonewu.Get(j, i);
+		  
+	      for (i = 1; i <= 3; i++)
+		for (j = 1; j <= 3 * noldp; j++)
+		  {
+		    double sum = 0;
+		    for (k = 1; k <= 3 * points.Size(); k++)
+		      sum += hm1.Get(i, k) * hm2.Get(k, j);
+		  
+		    hm3.Elem(i + 3 * (nfp-1), j) = sum;
+		  }
+
+	      //	    (*testout) << "freepoint: " << p << endl;
+
+	      while (ch != ';')
+		ist >> ch; 
+
+	      ist >> ch;
+	    }
+
+	  tfzl = tfz;
+
+	  tempoldutofreezone = hm3;
+	  tempoldutofreezonelimit = hm3;
+	  ist.putback(ch);
+	}
+
+      else if (strcmp (buf, "freezonelimit") == 0)
+	{
+	  int k, nfp;
+	  nfp = 0;
+	  ist >> ch;
+
+	  DenseMatrix hm1(3, 50), hm2(50, 50), hm3(50, 50);
+	  hm3 = 0;
+
+	  while (ch == '{')
+	    {
+	      hm1 = 0;
+	      nfp++;
+	      LoadVMatrixLine (ist, hm1, 1);
+
+	      for (i = 1; i <= points.Size(); i++)
+		tfzl.Elem(nfp, i) = hm1.Get(1, 3*i-2);
+
+
+	      p.X() = p.Y() = p.Z() = 0;
+	      for (i = 1; i <= points.Size(); i++)
+		{
+		  p.X() += hm1.Get(1, 3*i-2) * points.Get(i).X();
+		  p.Y() += hm1.Get(1, 3*i-2) * points.Get(i).Y();
+		  p.Z() += hm1.Get(1, 3*i-2) * points.Get(i).Z();
+		}
+	      freezonelimit.Elem(nfp) = p;
+	    
+	      hm2 = 0;
+	      for (i = 1; i <= 3 * noldp; i++)
+		hm2.Elem(i, i) = 1;
+	      for (i = 1; i <= 3 * noldp; i++)
+		for (j = 1; j <= 3 * (points.Size() - noldp); j++)
+		  hm2.Elem(j + 3 * noldp, i) = tempoldutonewu.Get(j, i);
+		  
+	      for (i = 1; i <= 3; i++)
+		for (j = 1; j <= 3 * noldp; j++)
+		  {
+		    double sum = 0;
+		    for (k = 1; k <= 3 * points.Size(); k++)
+		      sum += hm1.Get(i, k) * hm2.Get(k, j);
+		  
+		    hm3.Elem(i + 3 * (nfp-1), j) = sum;
+		  }
+
+	      //	    (*testout) << "freepoint: " << p << endl;
+
+	      while (ch != ';')
+		ist >> ch; 
+
+	      ist >> ch;
+	    }
+
+	  tempoldutofreezonelimit = hm3;
+	  ist.putback(ch);
+	}
+
+      else if (strcmp (buf, "freeset") == 0)
+	{
+	  freesets.Append (new ARRAY<int>);
+
+	  ist >> ch;
+
+	  while (ch != ';')
+	    {
+	      ist.putback (ch);
+	      ist >> i;
+	      freesets.Last()->Append(i);
+	      ist >> ch;
+	    }
+	}
+
+      else if (strcmp (buf, "elements") == 0)
+	{
+	  ist >> ch;
+
+	  while (ch == '(')
+	    {
+	      elements.Append (Element(TET));
+
+	      //	      elements.Last().SetNP(1);
+	      ist >> elements.Last().PNum(1);
+	      ist >> ch;    // ','
+
+	      if (ch == COMMASIGN)
+		{
+		  //		  elements.Last().SetNP(2);
+		  ist >> elements.Last().PNum(2);
+		  ist >> ch;    // ','
+		}
+	      if (ch == COMMASIGN)
+		{
+		  //		  elements.Last().SetNP(3);
+		  ist >> elements.Last().PNum(3);
+		  ist >> ch;    // ','
+		}
+	      if (ch == COMMASIGN)
+		{
+		  //		  elements.Last().SetNP(4);
+		  elements.Last().SetType(TET);
+		  ist >> elements.Last().PNum(4);
+		  ist >> ch;    // ','
+		}
+	      if (ch == COMMASIGN)
+		{
+		  //		  elements.Last().SetNP(5);
+		  elements.Last().SetType(PYRAMID);
+		  ist >> elements.Last().PNum(5);
+		  ist >> ch;    // ','
+		}
+	      if (ch == COMMASIGN)
+		{
+		  //		  elements.Last().SetNP(6);
+		  elements.Last().SetType(PRISM);
+		  ist >> elements.Last().PNum(6);
+		  ist >> ch;    // ','
+		}
+
+	      /*
+	      orientations.Append (fourint());
+	      orientations.Last().i1 = elements.Last().PNum(1);
+	      orientations.Last().i2 = elements.Last().PNum(2);
+	      orientations.Last().i3 = elements.Last().PNum(3);
+	      orientations.Last().i4 = elements.Last().PNum(4);
+	      */
+
+	      ist >> ch;
+	      while (ch != ';')
+		{
+		  ist >> ch;
+		}
+
+	      ist >> ch;
+	    }
+
+	  ist.putback (ch);
+	}
+
+      else if (strcmp (buf, "orientations") == 0)
+
+	{
+	  ist >> ch;
+
+	  while (ch == '(')
+	    {
+	      //        fourint a = fourint();
+	      orientations.Append (fourint());
+
+	      ist >> orientations.Last().i1;
+	      ist >> ch;    // ','
+	      ist >> orientations.Last().i2;
+	      ist >> ch;    // ','
+	      ist >> orientations.Last().i3;
+	      ist >> ch;    // ','
+	      ist >> orientations.Last().i4;
+	      ist >> ch;    // ','
+
+
+	      ist >> ch;
+	      while (ch != ';')
+		{
+		  ist >> ch;
+		}
+
+	      ist >> ch;
+	    }
+
+	  ist.putback (ch);
+	}
+
+
+      else if (strcmp (buf, "endrule") != 0)
+	{
+	  PrintSysError ("Parser3d, unknown token " , buf);
+	}
+    }
+  while (!ist.eof() && strcmp (buf, "endrule") != 0);
+
+
+  //  (*testout) << endl;
+  //  (*testout) << Name() << endl;
+  //  (*testout) << "no1 = " << GetNO() << endl;
+
+  oldutonewu.SetSize (3 * (points.Size() - noldp), 3 * noldp);
+  oldutonewu = 0;
+
+  for (i = 1; i <= oldutonewu.Height(); i++)
+    for (j = 1; j <= oldutonewu.Width(); j++)
+      oldutonewu.Elem(i, j) = tempoldutonewu.Elem(i, j);
+
+
+  /*
+    oldutofreezone = new SparseMatrixFlex (3 * freezone.Size(), 3 * noldp);
+    oldutofreezonelimit = new SparseMatrixFlex (3 * freezone.Size(), 3 * noldp);
+
+    oldutofreezone -> SetSymmetric(0);
+    oldutofreezonelimit -> SetSymmetric(0);
+    */
+
+  /*
+    oldutofreezone = new DenseMatrix (3 * freezone.Size(), 3 * noldp);
+    oldutofreezonelimit = new DenseMatrix (3 * freezone.Size(), 3 * noldp);
+  
+    for (i = 1; i <= oldutofreezone->Height(); i++)
+    for (j = 1; j <= oldutofreezone->Width(); j++)
+    //      if (j == 4 || j >= 7)
+    {
+    if (tempoldutofreezone.Elem(i, j))
+    (*oldutofreezone)(i, j) = tempoldutofreezone(i, j);
+    if (tempoldutofreezonelimit.Elem(i, j))
+    (*oldutofreezonelimit)(i, j) = tempoldutofreezonelimit(i, j);
+    }
+    */
+
+
+
+
+  oldutofreezone = new DenseMatrix (freezone.Size(), points.Size());
+  oldutofreezonelimit = new DenseMatrix (freezone.Size(), points.Size());
+  //  oldutofreezone = new SparseMatrixFlex (freezone.Size(), points.Size());
+  //  oldutofreezonelimit = new SparseMatrixFlex (freezone.Size(), points.Size());
+
+  for (i = 1; i <= freezone.Size(); i++)
+    for (j = 1; j <= points.Size(); j++)
+      {
+	if (tfz.Elem(i, j))
+	  (*oldutofreezone).Elem(i, j) = tfz.Elem(i, j);
+	if (tfzl.Elem(i, j))
+	  (*oldutofreezonelimit).Elem(i, j) = tfzl.Elem(i, j);
+      }
+  
+  /*
+  (*testout) << "Rule " << Name() << endl;
+  (*testout) << "oldutofreezone = " << (*oldutofreezone) << endl;
+  (*testout) << "oldutofreezonelimit = " << (*oldutofreezonelimit) << endl;
+  */
+
+  freezonepi.SetSize (freezone.Size());
+  for (i = 1; i <= freezonepi.Size(); i++)
+    freezonepi.Elem(i) = 0;
+  for (i = 1; i <= freezone.Size(); i++)
+    for (j = 1; j <= noldp; j++)
+      if (Dist (freezone.Get(i), points.Get(j)) < 1e-8)
+	freezonepi.Elem(i) = j;
+
+
+
+  
+  for (i = 1; i <= elements.Size(); i++)
+    {
+      if (elements.Elem(i).GetNP() == 4)
+	{
+	  orientations.Append (fourint());
+	  orientations.Last().i1 = elements.Get(i).PNum(1);
+	  orientations.Last().i2 = elements.Get(i).PNum(2);
+	  orientations.Last().i3 = elements.Get(i).PNum(3);
+	  orientations.Last().i4 = elements.Get(i).PNum(4);
+	}
+      if (elements.Elem(i).GetNP() == 5)
+	{
+	  orientations.Append (fourint());
+	  orientations.Last().i1 = elements.Get(i).PNum(1);
+	  orientations.Last().i2 = elements.Get(i).PNum(2);
+	  orientations.Last().i3 = elements.Get(i).PNum(3);
+	  orientations.Last().i4 = elements.Get(i).PNum(5);
+
+	  orientations.Append (fourint());
+	  orientations.Last().i1 = elements.Get(i).PNum(1);
+	  orientations.Last().i2 = elements.Get(i).PNum(3);
+	  orientations.Last().i3 = elements.Get(i).PNum(4);
+	  orientations.Last().i4 = elements.Get(i).PNum(5);
+	}
+    }
+
+
+
+  if (freesets.Size() == 0)
+    {
+      freesets.Append (new ARRAY<int>);
+      for (i = 1; i <= freezone.Size(); i++)
+	freesets.Elem(1)->Append(i);
+    }
+
+
+  //  testout << "Freezone: " << endl;
+
+  //  for (i = 1; i <= freezone.Size(); i++)
+  //    (*testout) << "freepoint: " << freezone.Get(i) << endl;
+  Vector vp(points.Size()), vfp(freezone.Size());
+
+
+  if (quality < 100)
+    {
+      for (i = 1; i <= 3; i++)
+	{
+	  for (j = 1; j <= points.Size(); j++)
+	    vp.Elem(j) = points.Get(j).X(i);
+	  oldutofreezone->Mult(vp, vfp);
+	  for (j = 1; j <= freezone.Size(); j++)
+	    freezone.Elem(j).X(i) = vfp.Get(j);
+	}
+      //      for (i = 1; i <= freezone.Size(); i++)
+      //	(*testout) << "freepoint: " << freezone.Get(i) << endl;
+    }
+
+
+  for (fs = 1; fs <= freesets.Size(); fs++)
+    {
+      freefaces.Append (new ARRAY<threeint>);
+
+      ARRAY<int> & freeset = *freesets.Elem(fs);
+      ARRAY<threeint> & freesetfaces = *freefaces.Last();
+
+      for (ii1 = 1; ii1 <= freeset.Size(); ii1++)
+	for (ii2 = 1; ii2 <= freeset.Size(); ii2++)
+	  for (ii3 = 1; ii3 <= freeset.Size(); ii3++)
+	    if (ii1 < ii2 && ii1 < ii3 && ii2 != ii3)
+	      {
+		i1 = freeset.Get(ii1);
+		i2 = freeset.Get(ii2);
+		i3 = freeset.Get(ii3);
+
+		Vec3d v1, v2, n;
+
+		v1 = freezone.Get(i3) - freezone.Get(i1);
+		v2 = freezone.Get(i2) - freezone.Get(i1);
+		n = Cross (v1, v2);
+		n /= n.Length();
+		//		(*testout) << "i1,2,3 = " << i1 << ", " << i2 << ", " << i3 << endl;
+		//		(*testout) << "v1 = " << v1 << " v2 = " << v2 << " n = " << n << endl;
+		ok = 1;
+		for (ii = 1; ii <= freeset.Size(); ii++)
+		  {
+		    i = freeset.Get(ii);
+		    //		    (*testout) << "i = " << i << endl;
+		    if (i != i1 && i != i2 && i != i3)
+		      if ( (freezone.Get(i) - freezone.Get(i1)) * n < 0 ) ok = 0;
+		  }
+
+		if (ok)
+		  {
+		    freesetfaces.Append (threeint());
+		    freesetfaces.Last().i1 = i1;
+		    freesetfaces.Last().i2 = i2;
+		    freesetfaces.Last().i3 = i3;
+		  }
+	      }
+    }
+
+  for (fs = 1; fs <= freesets.Size(); fs++)
+    {
+      freefaceinequ.Append (new DenseMatrix (freefaces.Get(fs)->Size(), 4));
+    }
+
+
+  {
+    int minn;
+    //    ARRAY<int> pnearness (noldp);
+    pnearness.SetSize (noldp);
+
+    for (i = 1; i <= pnearness.Size(); i++)
+      pnearness.Elem(i) = INT_MAX/10;
+
+    for (j = 1; j <= GetNP(1); j++)
+      pnearness.Elem(GetPointNr (1, j)) = 0;
+
+    do
+      {
+	ok = 1;
+
+	for (i = 1; i <= noldf; i++)
+	  {
+	    minn = INT_MAX/10;
+	    for (j = 1; j <= GetNP(i); j++)
+	      minn = min2 (minn, pnearness.Get(GetPointNr (i, j)));
+
+	    for (j = 1; j <= GetNP(i); j++)
+	      if (pnearness.Get(GetPointNr (i, j)) > minn+1)
+		{
+		  ok = 0;
+		  pnearness.Elem(GetPointNr (i, j)) = minn+1;
+		}
+	  }
+
+	for (i = 1; i <= edges.Size(); i++)
+	  {
+	    int pi1 = edges.Get(i).i1;
+	    int pi2 = edges.Get(i).i2;
+
+	    if (pnearness.Get(pi1) > pnearness.Get(pi2)+1)
+	      {
+		ok = 0;
+		pnearness.Elem(pi1) = pnearness.Get(pi2)+1;
+	      }
+	    if (pnearness.Get(pi2) > pnearness.Get(pi1)+1)
+	      {
+		ok = 0;
+		pnearness.Elem(pi2) = pnearness.Get(pi1)+1;
+	      }
+	  }
+	
+
+	for (i = 1; i <= elements.Size(); i++)
+	  if (elements.Get(i).GetNP() == 6)  // prism rule
+	    {
+	      for (j = 1; j <= 3; j++)
+		{
+		  int pi1 = elements.Get(i).PNum(j);
+		  int pi2 = elements.Get(i).PNum(j+3);
+
+		  if (pnearness.Get(pi1) > pnearness.Get(pi2)+1)
+		    {
+		      ok = 0;
+		      pnearness.Elem(pi1) = pnearness.Get(pi2)+1;
+		    }
+		  if (pnearness.Get(pi2) > pnearness.Get(pi1)+1)
+		    {
+		      ok = 0;
+		      pnearness.Elem(pi2) = pnearness.Get(pi1)+1;
+		    }
+		}
+	    }
+      }
+    while (!ok);
+
+    maxpnearness = 0;
+    for (i = 1; i <= pnearness.Size(); i++)
+      maxpnearness = max2 (maxpnearness, pnearness.Get(i));
+
+
+    fnearness.SetSize (noldf);
+
+    for (i = 1; i <= noldf; i++)
+      {
+	fnearness.Elem(i) = 0;
+	for (j = 1; j <= GetNP(i); j++)
+	  fnearness.Elem(i) += pnearness.Get(GetPointNr (i, j));
+      }
+
+    // (*testout) << "rule " << name << ", pnear = " << pnearness << endl;
+  }
+
+  
+  //Table of edges:
+  for (fs = 1; fs <= freesets.Size(); fs++)
+    {
+      freeedges.Append (new ARRAY<twoint>);
+      
+      //      ARRAY<int> & freeset = *freesets.Get(fs);
+      ARRAY<twoint> & freesetedges = *freeedges.Last();
+      ARRAY<threeint> & freesetfaces = *freefaces.Get(fs);
+      int k,l;
+      INDEX ind;
+      
+      for (k = 1; k <= freesetfaces.Size(); k++)
+	{
+          threeint tr = freesetfaces.Get(k);
+
+	  for (l = k+1; l <= freesetfaces.Size(); l++)
+	    {
+	      ind = NeighbourTrianglePoint(freesetfaces.Get(k), freesetfaces.Get(l));
+	      if (!ind) continue;
+
+	      INDEX_3 f1(freesetfaces.Get(k).i1, 
+			 freesetfaces.Get(k).i2, 
+			 freesetfaces.Get(k).i3);
+	      INDEX_3 f2(freesetfaces.Get(l).i1, 
+			 freesetfaces.Get(l).i2, 
+			 freesetfaces.Get(l).i3);
+	      INDEX_2 ed(0, 0);
+	      for (int f11 = 1; f11 <= 3; f11++)
+		for (int f12 = 1; f12 <= 3; f12++)
+		  if (f11 != f12)
+		    for (int f21 = 1; f21 <= 3; f21++)
+		      for (int f22 = 1; f22 <= 3; f22++)		    
+			if (f1.I(f11) == f2.I(f21) && f1.I(f12) == f2.I(f22))
+			{
+			  ed.I(1) = f1.I(f11);
+			  ed.I(2) = f1.I(f12);
+			}
+	      //	      (*testout) << "ed = " << ed.I(1) << "-" << ed.I(2) << endl;
+	      //	      (*testout) << "ind = " << ind << " ed = " << ed << endl;
+	      for (int eli = 1; eli <= GetNOldF(); eli++)
+		{
+		  if (GetNP(eli) == 4)
+		    {
+		      for (int elr = 1; elr <= 4; elr++)
+			{
+			  if (GetPointNrMod (eli, elr) == ed.I(1) &&
+			      GetPointNrMod (eli, elr+2) == ed.I(2))
+			    {
+			      /*
+			      (*testout) << "ed is diagonal of rectangle" << endl;
+			      (*testout) << "ed = " << ed.I(1) << "-" << ed.I(2) << endl;
+			      (*testout) << "ind = " << ind << endl;
+			      */
+			      ind = 0;
+			    }
+
+			}
+		    }
+		}
+
+	      if (ind)
+		{
+		  /*
+		  (*testout) << "new edge from face " << k 
+			     << " = (" << freesetfaces.Get(k).i1 
+			     << ", " << freesetfaces.Get(k).i2 
+			     << ", " << freesetfaces.Get(k).i3
+			     << "), point " << ind << endl;
+			     */
+		  freesetedges.Append(twoint(k,ind));
+		}
+	    }	
+	}
+    }
+    
+}
+
+
+
+
+
+void Meshing3 :: LoadRules (const char * filename, const char ** prules)
+{
+  char buf[256];
+  istream * ist;
+  char *tr1 = NULL;
+
+  if (filename)
+    {
+      PrintMessage (3, "rule-filename = ", filename);
+      ist = new ifstream (filename);
+    }
+  else 
+    {
+      /* connect tetrules to one string */
+      PrintMessage (3, "Use internal rules");
+      if (!prules) prules = tetrules;
+
+      const char ** hcp = prules; 
+      size_t len = 0;
+      while (*hcp)
+	{
+	  len += strlen (*hcp);
+	  hcp++;
+	}
+      tr1 = new char[len+1];
+      tr1[0] = 0;
+      hcp = prules; //  tetrules;
+
+
+      char * tt1 = tr1;
+      while (*hcp)
+	{
+	  strcat (tt1, *hcp);
+	  tt1 += strlen (*hcp);	  
+	  hcp++;
+	}
+
+
+#ifdef WIN32
+      // VC++ 2005 workaround
+      for(size_t i=0; i<len; i++)
+	if(tr1[i] == ',')
+	  tr1[i] = ':';
+#endif
+
+      ist = new istringstream (tr1);
+    }
+  
+  if (!ist->good())
+    {
+      cerr << "Rule description file " << filename << " not found" << endl;
+      delete ist;
+      exit (1);
+    }
+    
+  while (!ist->eof())
+    {
+      buf[0] = 0;
+      (*ist) >> buf;
+	
+      if (strcmp (buf, "rule") == 0)
+	{
+	  vnetrule * rule = new vnetrule;
+	  rule -> LoadRule(*ist);
+	  rules.Append (rule);
+	  if (!rule->TestOk())
+	    {
+	      PrintSysError ("Parser3d: Rule ", rules.Size(), " not ok");
+	      exit (1);
+	    }
+	}
+      else if (strcmp (buf, "tolfak") == 0)
+	{
+	  (*ist) >> tolfak;
+	}
+    }
+  delete ist;
+  delete [] tr1;
+}
+}
diff --git a/contrib/Netgen/libsrc/meshing/prism2rls.cpp b/contrib/Netgen/libsrc/meshing/prism2rls.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..7e696554c0fef82fbafcb0633917eddcaaf5de27
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/prism2rls.cpp
@@ -0,0 +1,457 @@
+namespace netgen
+{
+const char * prismrules2[] = {
+"tolfak 0.5\n",\
+"\n",\
+"rule \"prism on quad\"\n",\
+"\n",\
+"quality 1\n",\
+"\n",\
+"mappoints\n",\
+"(0, 0, 0);\n",\
+"(1, 0, 0);\n",\
+"(1, 1, 0);\n",\
+"(0, 1, 0);\n",\
+"(0.5, 0, -0.86);\n",\
+"(0.5, 1, -0.86);\n",\
+"\n",\
+"mapfaces\n",\
+"(1, 2, 3, 4) del;\n",\
+"(1, 5, 2) del;\n",\
+"(4, 3, 6) del;\n",\
+"\n",\
+"newpoints\n",\
+"\n",\
+"newfaces\n",\
+"(5, 2, 3, 6);\n",\
+"(1, 5, 6, 4);\n",\
+"\n",\
+"elements\n",\
+"(1, 5, 2, 4, 6, 3);\n",\
+"\n",\
+"orientations\n",\
+"(1, 2, 3, 5);\n",\
+"(1, 3, 4, 6);\n",\
+"\n",\
+"freezone2\n",\
+"{ 1 P1 };\n",\
+"{ 1 P2 };\n",\
+"{ 1 P3 };\n",\
+"{ 1 P4 };\n",\
+"{ 1 P5 };\n",\
+"{ 1 P6 };\n",\
+"{ 0.3 P1, -0.1 P2, -0.1 P3, 0.3 P4, 0.3 P5, 0.3 P6 };\n",\
+"{ -0.1 P1, 0.3 P2, 0.3 P3, -0.1 P4, 0.3 P5, 0.3 P6 };\n",\
+"\n",\
+"freezonelimit\n",\
+"{ 1 P1 };\n",\
+"{ 1 P2 };\n",\
+"{ 1 P3 };\n",\
+"{ 1 P4 };\n",\
+"{ 1 P5 };\n",\
+"{ 1 P6 };\n",\
+"{ 0.25 P1, 0 P2, 0 P3, 0.25 P4, 0.25 P5, 0.25 P6 };\n",\
+"{ 0 P1, 0.25 P2, 0.25 P3, 0 P4, 0.25 P5, 0.25 P6 };\n",\
+"\n",\
+"freeset\n",\
+"1 2 4 5 6 7;\n",\
+"\n",\
+"freeset\n",\
+"2 3 4 5 6 8;\n",\
+"\n",\
+"endrule\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"rule \"prism on quad, one trig\"\n",\
+"\n",\
+"quality 2\n",\
+"\n",\
+"mappoints\n",\
+"(0, 0, 0);\n",\
+"(1, 0, 0);\n",\
+"(1, 1, 0);\n",\
+"(0, 1, 0);\n",\
+"(0.5, 0, -0.86);\n",\
+"(0.5, 1, -0.86);\n",\
+"\n",\
+"mapfaces\n",\
+"(1, 2, 3, 4) del;\n",\
+"(1, 5, 2) del;\n",\
+"\n",\
+"newpoints\n",\
+"\n",\
+"newfaces\n",\
+"(5, 2, 3, 6);\n",\
+"(1, 5, 6, 4);\n",\
+"(4, 6, 3);\n",\
+"\n",\
+"elements\n",\
+"(1, 5, 2, 4, 6, 3);\n",\
+"\n",\
+"orientations\n",\
+"(1, 2, 3, 5);\n",\
+"(1, 3, 4, 6);\n",\
+"\n",\
+"freezone2\n",\
+"{ 1 P1 };\n",\
+"{ 1 P2 };\n",\
+"{ 1 P3 };\n",\
+"{ 1 P4 };\n",\
+"{ 1 P5 };\n",\
+"{ 1 P6 };\n",\
+"{ 0.3 P1, -0.1 P2, -0.1 P3, 0.3 P4, 0.3 P5, 0.3 P6 };\n",\
+"{ -0.1 P1, 0.3 P2, 0.3 P3, -0.1 P4, 0.3 P5, 0.3 P6 };\n",\
+"\n",\
+"freezonelimit\n",\
+"{ 1 P1 };\n",\
+"{ 1 P2 };\n",\
+"{ 1 P3 };\n",\
+"{ 1 P4 };\n",\
+"{ 1 P5 };\n",\
+"{ 1 P6 };\n",\
+"{ 0.25 P1, 0 P2, 0 P3, 0.25 P4, 0.25 P5, 0.25 P6 };\n",\
+"{ 0 P1, 0.25 P2, 0.25 P3, 0 P4, 0.25 P5, 0.25 P6 };\n",\
+"\n",\
+"freeset\n",\
+"1 2 4 5 6 7;\n",\
+"\n",\
+"freeset\n",\
+"2 3 4 5 6 8;\n",\
+"\n",\
+"\n",\
+"endrule\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"rule \"prism on 2 quad\"\n",\
+"\n",\
+"quality 1\n",\
+"\n",\
+"mappoints\n",\
+"(0, 0, 0);\n",\
+"(1, 0, 0);\n",\
+"(1, 1, 0);\n",\
+"(0, 1, 0);\n",\
+"(0.5, 0, -0.86);\n",\
+"(0.5, 1, -0.86);\n",\
+"\n",\
+"mapfaces\n",\
+"(1, 2, 3, 4) del;\n",\
+"(2, 5, 6, 3) del;\n",\
+"(1, 5, 2) del;\n",\
+"(4, 3, 6) del;\n",\
+"\n",\
+"newpoints\n",\
+"\n",\
+"newfaces\n",\
+"(1, 5, 6, 4);\n",\
+"\n",\
+"elements\n",\
+"(1, 5, 2, 4, 6, 3);\n",\
+"\n",\
+"freezone2\n",\
+"{ 1 P1 };\n",\
+"{ 1 P2 };\n",\
+"{ 1 P3 };\n",\
+"{ 1 P4 };\n",\
+"{ 1 P5 };\n",\
+"{ 1 P6 };\n",\
+"{ 0.3 P1, -0.1 P2, -0.1 P3, 0.3 P4, 0.3 P5, 0.3 P6 };\n",\
+"\n",\
+"freezonelimit\n",\
+"{ 1 P1 };\n",\
+"{ 1 P2 };\n",\
+"{ 1 P3 };\n",\
+"{ 1 P4 };\n",\
+"{ 1 P5 };\n",\
+"{ 1 P6 };\n",\
+"{ 0.25 P1, 0 P2, 0 P3, 0.25 P4, 0.25 P5, 0.25 P6 };\n",\
+"\n",\
+"freeset\n",\
+"1 2 4 5 6 7;\n",\
+"\n",\
+"freeset\n",\
+"2 3 4 6;\n",\
+"\n",\
+"\n",\
+"endrule\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"rule \"prism on 2 quad, one trig\"\n",\
+"\n",\
+"quality 2\n",\
+"\n",\
+"mappoints\n",\
+"(0, 0, 0);\n",\
+"(1, 0, 0);\n",\
+"(1, 1, 0);\n",\
+"(0, 1, 0);\n",\
+"(0.5, 0, -0.86);\n",\
+"(0.5, 1, -0.86);\n",\
+"\n",\
+"mapfaces\n",\
+"(1, 2, 3, 4) del;\n",\
+"(2, 5, 6, 3) del;\n",\
+"(1, 5, 2) del;\n",\
+"\n",\
+"newpoints\n",\
+"\n",\
+"newfaces\n",\
+"(1, 5, 6, 4);\n",\
+"(4, 6, 3);\n",\
+"\n",\
+"elements\n",\
+"(1, 5, 2, 4, 6, 3);\n",\
+"\n",\
+"freezone2\n",\
+"{ 1 P1 };\n",\
+"{ 1 P2 };\n",\
+"{ 1 P3 };\n",\
+"{ 1 P4 };\n",\
+"{ 1 P5 };\n",\
+"{ 1 P6 };\n",\
+"{ 0.3 P1, -0.1 P2, -0.1 P3, 0.3 P4, 0.3 P5, 0.3 P6 };\n",\
+"\n",\
+"freezonelimit\n",\
+"{ 1 P1 };\n",\
+"{ 1 P2 };\n",\
+"{ 1 P3 };\n",\
+"{ 1 P4 };\n",\
+"{ 1 P5 };\n",\
+"{ 1 P6 };\n",\
+"{ 0.25 P1, 0 P2, 0 P3, 0.25 P4, 0.25 P5, 0.25 P6 };\n",\
+"\n",\
+"freeset\n",\
+"1 2 4 5 6 7;\n",\
+"\n",\
+"freeset\n",\
+"2 3 4 6;\n",\
+"\n",\
+"\n",\
+"endrule\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"rule \"prism on 2 quada\"\n",\
+"\n",\
+"quality 1\n",\
+"\n",\
+"mappoints\n",\
+"(0, 0, 0);\n",\
+"(1, 0, 0);\n",\
+"(1, 1, 0);\n",\
+"(0, 1, 0);\n",\
+"(0.5, 0, -0.86);\n",\
+"(0.5, 1, -0.86);\n",\
+"\n",\
+"mapfaces\n",\
+"(1, 2, 3, 4) del;\n",\
+"(5, 1, 4, 6) del;\n",\
+"(1, 5, 2) del;\n",\
+"(4, 3, 6) del;\n",\
+"\n",\
+"newpoints\n",\
+"\n",\
+"newfaces\n",\
+"(5, 2, 3, 6);\n",\
+"\n",\
+"elements\n",\
+"(1, 5, 2, 4, 6, 3);\n",\
+"\n",\
+"freezone2\n",\
+"{ 1 P1 };\n",\
+"{ 1 P2 };\n",\
+"{ 1 P3 };\n",\
+"{ 1 P4 };\n",\
+"{ 1 P5 };\n",\
+"{ 1 P6 };\n",\
+"{ -0.1 P1, 0.3 P2, 0.3 P3, -0.1 P4, 0.3 P5, 0.3 P6 };\n",\
+"\n",\
+"freezonelimit\n",\
+"{ 1 P1 };\n",\
+"{ 1 P2 };\n",\
+"{ 1 P3 };\n",\
+"{ 1 P4 };\n",\
+"{ 1 P5 };\n",\
+"{ 1 P6 };\n",\
+"{ 0 P1, 0.25 P2, 0.25 P3, 0 P4, 0.25 P5, 0.25 P6 };\n",\
+"\n",\
+"freeset\n",\
+"1 2 3 5 6 7;\n",\
+"\n",\
+"freeset\n",\
+"1 3 4 6;\n",\
+"\n",\
+"\n",\
+"endrule\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"rule \"fill prism\"\n",\
+"\n",\
+"quality 1\n",\
+"\n",\
+"mappoints\n",\
+"(0, 0, 0);\n",\
+"(1, 0, 0);\n",\
+"(1, 1, 0);\n",\
+"(0, 1, 0);\n",\
+"(0.5, 0, -0.86);\n",\
+"(0.5, 1, -0.86);\n",\
+"\n",\
+"mapfaces\n",\
+"(1, 2, 3, 4) del;\n",\
+"(2, 5, 6, 3) del;\n",\
+"(5, 1, 4, 6) del;\n",\
+"(1, 5, 2) del;\n",\
+"(4, 3, 6) del;\n",\
+"\n",\
+"newpoints\n",\
+"\n",\
+"newfaces\n",\
+"\n",\
+"\n",\
+"elements\n",\
+"(1, 5, 2, 4, 6, 3);\n",\
+"\n",\
+"freezone2\n",\
+"{ 1 P1 };\n",\
+"{ 1 P2 };\n",\
+"{ 1 P3 };\n",\
+"{ 1 P4 };\n",\
+"{ 1 P5 };\n",\
+"{ 1 P6 };\n",\
+"\n",\
+"freeset\n",\
+"1 2 4 5;\n",\
+"\n",\
+"freeset\n",\
+"2 3 4 6;\n",\
+"\n",\
+"endrule\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"rule \"prism on 3 quad, one trig\"\n",\
+"\n",\
+"quality 2\n",\
+"\n",\
+"mappoints\n",\
+"(0, 0, 0);\n",\
+"(1, 0, 0);\n",\
+"(1, 1, 0);\n",\
+"(0, 1, 0);\n",\
+"(0.5, 0, -0.86);\n",\
+"(0.5, 1, -0.86);\n",\
+"\n",\
+"mapfaces\n",\
+"(1, 2, 3, 4) del;\n",\
+"(2, 5, 6, 3) del;\n",\
+"(5, 1, 4, 6) del;\n",\
+"(1, 5, 2) del;\n",\
+"\n",\
+"newpoints\n",\
+"\n",\
+"newfaces\n",\
+"(4, 6, 3);\n",\
+"\n",\
+"\n",\
+"elements\n",\
+"(1, 5, 2, 4, 6, 3);\n",\
+"\n",\
+"freezone2\n",\
+"{ 1 P1 };\n",\
+"{ 1 P2 };\n",\
+"{ 1 P3 };\n",\
+"{ 1 P4 };\n",\
+"{ 1 P5 };\n",\
+"{ 1 P6 };\n",\
+"\n",\
+"freeset\n",\
+"1 2 4 5;\n",\
+"\n",\
+"freeset\n",\
+"2 3 4 6;\n",\
+"\n",\
+"endrule\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"rule \"flat prism\"\n",\
+"\n",\
+"quality 100\n",\
+"\n",\
+"mappoints\n",\
+"(0, 0, 0);\n",\
+"(1, 0, 0);\n",\
+"(0.5, 0.866, 0);\n",\
+"(0, 0, -1);\n",\
+"(1, 0, -1);\n",\
+"(0.5, 0.866, -1);\n",\
+"\n",\
+"\n",\
+"mapfaces\n",\
+"(1, 2, 3) del;\n",\
+"(5, 4, 6) del;\n",\
+"\n",\
+"newpoints\n",\
+"\n",\
+"newfaces\n",\
+"(1, 2, 4);\n",\
+"(4, 2, 5);\n",\
+"(2, 3, 5);\n",\
+"(5, 3, 6);\n",\
+"(3, 1, 6);\n",\
+"(6, 1, 4);\n",\
+"\n",\
+"\n",\
+"\n",\
+"elements\n",\
+"(1, 2, 3, 5, 4, 6);\n",\
+"\n",\
+"freezone2\n",\
+"{ 1 P1 };\n",\
+"{ 1 P2 };\n",\
+"{ 1 P5 };\n",\
+"{ 1 P6 };\n",\
+"endrule\n",\
+"\n",\
+0};
+}
diff --git a/contrib/Netgen/libsrc/meshing/pyramid2rls.cpp b/contrib/Netgen/libsrc/meshing/pyramid2rls.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..a97e7f13e594ee25b0a2308233b15132331d989c
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/pyramid2rls.cpp
@@ -0,0 +1,309 @@
+namespace netgen
+{
+const char * pyramidrules2[] = {
+"tolfak 0.5\n",\
+"\n",\
+"rule \"Pyramid on quad\"\n",\
+"\n",\
+"quality 100\n",\
+"\n",\
+"mappoints\n",\
+"(0, 0, 0);\n",\
+"(1, 0, 0);\n",\
+"(1, 1, 0);\n",\
+"(0, 1, 0);\n",\
+"\n",\
+"mapfaces\n",\
+"(1, 2, 3, 4) del;\n",\
+"\n",\
+"newpoints\n",\
+"(0.5, 0.5, -0.5) \n",\
+"	{ 0.25 X1, 0.25 X2, 0.25 X3, 0.25 X4 } 	\n",\
+"	{ 0.25 Y1, 0.25 Y2, 0.25 Y3, 0.25 Y4 } { };\n",\
+"\n",\
+"newfaces\n",\
+"(1, 2, 5);\n",\
+"(2, 3, 5);\n",\
+"(3, 4, 5);\n",\
+"(4, 1, 5);\n",\
+"\n",\
+"elements\n",\
+"(1, 2, 3, 4, 5);\n",\
+"\n",\
+"freezone2\n",\
+"{ 1 P1 };\n",\
+"{ 1 P2 };\n",\
+"{ 1 P3 };\n",\
+"{ 1 P4 };\n",\
+"{ 1.4 P5, -0.1 P1, -0.1 P2, -0.1 P3, -0.1 P4 };\n",\
+"\n",\
+"freezonelimit\n",\
+"{ 1 P1 };\n",\
+"{ 1 P2 };\n",\
+"{ 1 P3 };\n",\
+"{ 1 P4 };\n",\
+"{ 1 P5 };\n",\
+"\n",\
+"freeset\n",\
+"1 2 3 5;\n",\
+"\n",\
+"freeset\n",\
+"1 3 4 5;\n",\
+"\n",\
+"endrule\n",\
+"\n",\
+"\n",\
+"rule \"small Pyramid on quad\"\n",\
+"\n",\
+"quality 100\n",\
+"\n",\
+"mappoints\n",\
+"(0, 0, 0);\n",\
+"(1, 0, 0);\n",\
+"(1, 1, 0);\n",\
+"(0, 1, 0);\n",\
+"\n",\
+"mapfaces\n",\
+"(1, 2, 3, 4) del;\n",\
+"\n",\
+"newpoints\n",\
+"(0.5, 0.5, -0.1 )\n",\
+"	{ 0.25 X1, 0.25 X2, 0.25 X3, 0.25 X4 } \n",\
+"	{ 0.25 Y1, 0.25 Y2, 0.25 Y3, 0.25 Y4 } { };\n",\
+"\n",\
+"newfaces\n",\
+"(1, 2, 5);\n",\
+"(2, 3, 5);\n",\
+"(3, 4, 5);\n",\
+"(4, 1, 5);\n",\
+"\n",\
+"elements\n",\
+"(1, 2, 3, 4, 5);\n",\
+"\n",\
+"freezone2\n",\
+"{ 1 P1 };\n",\
+"{ 1 P2 };\n",\
+"{ 1 P3 };\n",\
+"{ 1 P4 };\n",\
+"{ 1.4 P5, -0.1 P1, -0.1 P2, -0.1 P3, -0.1 P4 };\n",\
+"\n",\
+"freezonelimit\n",\
+"{ 1 P1 };\n",\
+"{ 1 P2 };\n",\
+"{ 1 P3 };\n",\
+"{ 1 P4 };\n",\
+"{ 1 P5 };\n",\
+"\n",\
+"freeset\n",\
+"1 2 3 5;\n",\
+"\n",\
+"freeset\n",\
+"1 3 4 5;\n",\
+"\n",\
+"endrule\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"rule \"connect pyramid\"\n",\
+"\n",\
+"quality 100\n",\
+"\n",\
+"mappoints\n",\
+"(0, 0, 0);\n",\
+"(1, 0, 0);\n",\
+"(1, 1, 0);\n",\
+"(0, 1, 0);\n",\
+"(0.5, 0.5, -0.5);\n",\
+"\n",\
+"mapfaces\n",\
+"(1, 2, 3, 4) del;\n",\
+"\n",\
+"newpoints\n",\
+"\n",\
+"newfaces\n",\
+"(1, 2, 5);\n",\
+"(2, 3, 5);\n",\
+"(3, 4, 5);\n",\
+"(4, 1, 5);\n",\
+"\n",\
+"elements\n",\
+"(1, 2, 3, 4, 5);\n",\
+"\n",\
+"freezone2\n",\
+"{ 1 P1 };\n",\
+"{ 1 P2 };\n",\
+"{ 1 P3 };\n",\
+"{ 1 P4 };\n",\
+"{ 1 P5 };\n",\
+"\n",\
+"freeset\n",\
+"1 2 3 5;\n",\
+"\n",\
+"freeset\n",\
+"1 3 4 5;\n",\
+"\n",\
+"endrule\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"rule \"pyramid with one trig\"\n",\
+"\n",\
+"quality 1\n",\
+"\n",\
+"mappoints\n",\
+"(0, 0, 0);\n",\
+"(1, 0, 0);\n",\
+"(1, 1, 0);\n",\
+"(0, 1, 0);\n",\
+"(0.5, 0.5, -0.5);\n",\
+"\n",\
+"mapfaces\n",\
+"(1, 2, 3, 4) del;\n",\
+"(2, 1, 5) del;\n",\
+"\n",\
+"newpoints\n",\
+"\n",\
+"newfaces\n",\
+"(2, 3, 5);\n",\
+"(3, 4, 5);\n",\
+"(4, 1, 5);\n",\
+"\n",\
+"elements\n",\
+"(1, 2, 3, 4, 5);\n",\
+"\n",\
+"freezone2\n",\
+"{ 1 P1 };\n",\
+"{ 1 P2 };\n",\
+"{ 1 P3 };\n",\
+"{ 1 P4 };\n",\
+"{ 1 P5 };\n",\
+"{ 0.34 P2, 0.34 P3, 0.34 P5, -0.02 P1 };\n",\
+"{ 0.34 P3, 0.34 P4, 0.34 P5, -0.02 P1 };\n",\
+"{ 0.34 P1, 0.34 P4, 0.34 P5, -0.02 P2 };\n",\
+"\n",\
+"freezonelimit\n",\
+"{ 1 P1 };\n",\
+"{ 1 P2 };\n",\
+"{ 1 P3 };\n",\
+"{ 1 P4 };\n",\
+"{ 1 P5 };\n",\
+"{ 0.333 P2, 0.333 P3, 0.334 P5, 0 P1 };\n",\
+"{ 0.333 P3, 0.333 P4, 0.334 P5, 0 P1 };\n",\
+"{ 0.333 P1, 0.333 P4, 0.334 P5, 0 P2 };\n",\
+"\n",\
+"orientations\n",\
+"(1, 2, 3, 5);\n",\
+"(1, 3, 4, 5);\n",\
+"\n",\
+"\n",\
+"freeset\n",\
+"1 2 3 5;\n",\
+"freeset\n",\
+"1 3 4 5;\n",\
+"freeset\n",\
+"2 3 5 6;\n",\
+"freeset\n",\
+"3 4 5 7;\n",\
+"freeset \n",\
+"1 4 5 8;\n",\
+"endrule\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"rule \"pyramid with two trig\"\n",\
+"\n",\
+"quality 1\n",\
+"\n",\
+"mappoints\n",\
+"(0, 0, 0);\n",\
+"(1, 0, 0);\n",\
+"(1, 1, 0);\n",\
+"(0, 1, 0);\n",\
+"(0.5, 0.5, -0.5);\n",\
+"\n",\
+"mapfaces\n",\
+"(1, 2, 3, 4) del;\n",\
+"(2, 1, 5) del;\n",\
+"(3, 2, 5) del;\n",\
+"newpoints\n",\
+"\n",\
+"newfaces\n",\
+"(3, 4, 5);\n",\
+"(4, 1, 5);\n",\
+"\n",\
+"elements\n",\
+"(1, 2, 3, 4, 5);\n",\
+"\n",\
+"freezone2\n",\
+"{ 1 P1 };\n",\
+"{ 1 P2 };\n",\
+"{ 1 P3 };\n",\
+"{ 1 P4 };\n",\
+"{ 1 P5 };\n",\
+"\n",\
+"freeset\n",\
+"1 2 3 5;\n",\
+"\n",\
+"freeset\n",\
+"1 3 4 5;\n",\
+"\n",\
+"endrule\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"rule \"pyramid with two trig, left\"\n",\
+"\n",\
+"quality 1\n",\
+"\n",\
+"mappoints\n",\
+"(0, 0, 0);\n",\
+"(1, 0, 0);\n",\
+"(1, 1, 0);\n",\
+"(0, 1, 0);\n",\
+"(0.5, 0.5, -0.5);\n",\
+"\n",\
+"mapfaces\n",\
+"(1, 2, 3, 4) del;\n",\
+"(2, 1, 5) del;\n",\
+"(1, 4, 5) del;\n",\
+"newpoints\n",\
+"\n",\
+"newfaces\n",\
+"(3, 4, 5);\n",\
+"(2, 3, 5);\n",\
+"\n",\
+"elements\n",\
+"(1, 2, 3, 4, 5);\n",\
+"\n",\
+"freezone2\n",\
+"{ 1 P1 };\n",\
+"{ 1 P2 };\n",\
+"{ 1 P3 };\n",\
+"{ 1 P4 };\n",\
+"{ 1 P5 };\n",\
+"\n",\
+"freeset\n",\
+"1 2 3 5;\n",\
+"\n",\
+"freeset\n",\
+"1 3 4 5;\n",\
+"\n",\
+"endrule\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+0};
+}
diff --git a/contrib/Netgen/libsrc/meshing/pyramidrls.cpp b/contrib/Netgen/libsrc/meshing/pyramidrls.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..d4e997c1fea470d99cebb3d21bf815b33d02b745
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/pyramidrls.cpp
@@ -0,0 +1,263 @@
+namespace netgen
+{
+const char * pyramidrules[] = {
+"tolfak 0.5\n",\
+"\n",\
+"rule \"Pyramid on quad\"\n",\
+"\n",\
+"quality 100\n",\
+"\n",\
+"mappoints\n",\
+"(0, 0, 0);\n",\
+"(1, 0, 0);\n",\
+"(1, 1, 0);\n",\
+"(0, 1, 0);\n",\
+"\n",\
+"mapfaces\n",\
+"(1, 2, 3, 4) del;\n",\
+"\n",\
+"newpoints\n",\
+"(0.5, 0.5, -0.5) \n",\
+"	{ 0.25 X1, 0.25 X2, 0.25 X3, 0.25 X4 } 	\n",\
+"	{ 0.25 Y1, 0.25 Y2, 0.25 Y3, 0.25 Y4 } { };\n",\
+"\n",\
+"newfaces\n",\
+"(1, 2, 5);\n",\
+"(2, 3, 5);\n",\
+"(3, 4, 5);\n",\
+"(4, 1, 5);\n",\
+"\n",\
+"elements\n",\
+"(1, 2, 3, 4, 5);\n",\
+"\n",\
+"freezone2\n",\
+"{ 1 P1 };\n",\
+"{ 1 P2 };\n",\
+"{ 1 P3 };\n",\
+"{ 1 P4 };\n",\
+"{ 1.4 P5, -0.1 P1, -0.1 P2, -0.1 P3, -0.1 P4 };\n",\
+"\n",\
+"freezonelimit\n",\
+"{ 1 P1 };\n",\
+"{ 1 P2 };\n",\
+"{ 1 P3 };\n",\
+"{ 1 P4 };\n",\
+"{ 1 P5 };\n",\
+"\n",\
+"freeset\n",\
+"1 2 3 5;\n",\
+"\n",\
+"freeset\n",\
+"1 3 4 5;\n",\
+"\n",\
+"endrule\n",\
+"\n",\
+"\n",\
+"rule \"small Pyramid on quad\"\n",\
+"\n",\
+"quality 100\n",\
+"\n",\
+"mappoints\n",\
+"(0, 0, 0);\n",\
+"(1, 0, 0);\n",\
+"(1, 1, 0);\n",\
+"(0, 1, 0);\n",\
+"\n",\
+"mapfaces\n",\
+"(1, 2, 3, 4) del;\n",\
+"\n",\
+"newpoints\n",\
+"(0.5, 0.5, -0.1 )\n",\
+"	{ 0.25 X1, 0.25 X2, 0.25 X3, 0.25 X4 } \n",\
+"	{ 0.25 Y1, 0.25 Y2, 0.25 Y3, 0.25 Y4 } { };\n",\
+"\n",\
+"newfaces\n",\
+"(1, 2, 5);\n",\
+"(2, 3, 5);\n",\
+"(3, 4, 5);\n",\
+"(4, 1, 5);\n",\
+"\n",\
+"elements\n",\
+"(1, 2, 3, 4, 5);\n",\
+"\n",\
+"freezone2\n",\
+"{ 1 P1 };\n",\
+"{ 1 P2 };\n",\
+"{ 1 P3 };\n",\
+"{ 1 P4 };\n",\
+"{ 1.4 P5, -0.1 P1, -0.1 P2, -0.1 P3, -0.1 P4 };\n",\
+"\n",\
+"freezonelimit\n",\
+"{ 1 P1 };\n",\
+"{ 1 P2 };\n",\
+"{ 1 P3 };\n",\
+"{ 1 P4 };\n",\
+"{ 1 P5 };\n",\
+"\n",\
+"freeset\n",\
+"1 2 3 5;\n",\
+"\n",\
+"freeset\n",\
+"1 3 4 5;\n",\
+"\n",\
+"endrule\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"rule \"connect pyramid\"\n",\
+"\n",\
+"quality 1\n",\
+"\n",\
+"mappoints\n",\
+"(0, 0, 0);\n",\
+"(1, 0, 0);\n",\
+"(1, 1, 0);\n",\
+"(0, 1, 0);\n",\
+"(0.5, 0.5, -0.5);\n",\
+"\n",\
+"mapfaces\n",\
+"(1, 2, 3, 4) del;\n",\
+"\n",\
+"newpoints\n",\
+"\n",\
+"newfaces\n",\
+"(1, 2, 5);\n",\
+"(2, 3, 5);\n",\
+"(3, 4, 5);\n",\
+"(4, 1, 5);\n",\
+"\n",\
+"elements\n",\
+"(1, 2, 3, 4, 5);\n",\
+"\n",\
+"freezone2\n",\
+"{ 1 P1 };\n",\
+"{ 1 P2 };\n",\
+"{ 1 P3 };\n",\
+"{ 1 P4 };\n",\
+"{ 1 P5 };\n",\
+"\n",\
+"freeset\n",\
+"1 2 3 5;\n",\
+"\n",\
+"freeset\n",\
+"1 3 4 5;\n",\
+"\n",\
+"endrule\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"rule \"pyramid with one trig\"\n",\
+"\n",\
+"quality 1\n",\
+"\n",\
+"mappoints\n",\
+"(0, 0, 0);\n",\
+"(1, 0, 0);\n",\
+"(1, 1, 0);\n",\
+"(0, 1, 0);\n",\
+"(0.5, 0.5, -0.5);\n",\
+"\n",\
+"mapfaces\n",\
+"(1, 2, 3, 4) del;\n",\
+"(2, 1, 5) del;\n",\
+"\n",\
+"newpoints\n",\
+"\n",\
+"newfaces\n",\
+"(2, 3, 5);\n",\
+"(3, 4, 5);\n",\
+"(4, 1, 5);\n",\
+"\n",\
+"elements\n",\
+"(1, 2, 3, 4, 5);\n",\
+"\n",\
+"freezone2\n",\
+"{ 1 P1 };\n",\
+"{ 1 P2 };\n",\
+"{ 1 P3 };\n",\
+"{ 1 P4 };\n",\
+"{ 1 P5 };\n",\
+"{ 0.34 P2, 0.34 P3, 0.34 P5, -0.02 P1 };\n",\
+"{ 0.34 P3, 0.34 P4, 0.34 P5, -0.02 P1 };\n",\
+"{ 0.34 P1, 0.34 P4, 0.34 P5, -0.02 P3 };\n",\
+"\n",\
+"freezonelimit\n",\
+"{ 1 P1 };\n",\
+"{ 1 P2 };\n",\
+"{ 1 P3 };\n",\
+"{ 1 P4 };\n",\
+"{ 1 P5 };\n",\
+"{ 0.333 P2, 0.333 P3, 0.334 P5, 0 P1 };\n",\
+"{ 0.333 P3, 0.333 P4, 0.334 P5, 0 P1 };\n",\
+"{ 0.333 P1, 0.333 P4, 0.334 P5, 0 P3 };\n",\
+"\n",\
+"orientations\n",\
+"(1, 2, 3, 5);\n",\
+"(1, 3, 4, 5);\n",\
+"\n",\
+"\n",\
+"freeset\n",\
+"1 2 3 5;\n",\
+"freeset\n",\
+"1 3 4 5;\n",\
+"freeset\n",\
+"2 3 5 6;\n",\
+"freeset\n",\
+"3 4 5 7;\n",\
+"freeset \n",\
+"1 4 5 8;\n",\
+"endrule\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"rule \"pyramid with two trig\"\n",\
+"\n",\
+"quality 1\n",\
+"\n",\
+"mappoints\n",\
+"(0, 0, 0);\n",\
+"(1, 0, 0);\n",\
+"(1, 1, 0);\n",\
+"(0, 1, 0);\n",\
+"(0.5, 0.5, -0.5);\n",\
+"\n",\
+"mapfaces\n",\
+"(1, 2, 3, 4) del;\n",\
+"(2, 1, 5) del;\n",\
+"(3, 2, 5) del;\n",\
+"newpoints\n",\
+"\n",\
+"newfaces\n",\
+"(3, 4, 5);\n",\
+"(4, 1, 5);\n",\
+"\n",\
+"elements\n",\
+"(1, 2, 3, 4, 5);\n",\
+"\n",\
+"freezone2\n",\
+"{ 1 P1 };\n",\
+"{ 1 P2 };\n",\
+"{ 1 P3 };\n",\
+"{ 1 P4 };\n",\
+"{ 1 P5 };\n",\
+"\n",\
+"freeset\n",\
+"1 2 3 5;\n",\
+"\n",\
+"freeset\n",\
+"1 3 4 5;\n",\
+"\n",\
+"endrule\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+0};
+}
diff --git a/contrib/Netgen/libsrc/meshing/quadrls.cpp b/contrib/Netgen/libsrc/meshing/quadrls.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..1c2cd23b778abf62d7f8dcc6a9bf23d53dd14a93
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/quadrls.cpp
@@ -0,0 +1,887 @@
+namespace netgen
+{
+const char * quadrules[] = {
+"rule \"Free Quad (1)\"\n",\
+"\n",\
+"quality 1\n",\
+"\n",\
+"mappoints\n",\
+"(0, 0);\n",\
+"(1, 0);\n",\
+"\n",\
+"maplines\n",\
+"(1, 2) del;\n",\
+"\n",\
+"newpoints\n",\
+"(1, 1) { 1 X2 } { };\n",\
+"(0, 1) { } { };\n",\
+"\n",\
+"newlines\n",\
+"(3, 2);\n",\
+"(4, 3);\n",\
+"(1, 4);\n",\
+"\n",\
+"freearea\n",\
+"(0, 0);\n",\
+"(1, 0) { 1 X2 } { };\n",\
+"(1.5, 1.5) { 1.5 X2 } { };\n",\
+"(-0.5, 1.5) { -0.5 X2 } { };\n",\
+"\n",\
+"elements\n",\
+"(1, 2, 3, 4);\n",\
+"\n",\
+"endrule\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"rule \"Free Quad (5)\"\n",\
+"\n",\
+"quality 5\n",\
+"\n",\
+"mappoints\n",\
+"(0, 0);\n",\
+"(1, 0);\n",\
+"\n",\
+"maplines\n",\
+"(1, 2) del;\n",\
+"\n",\
+"newpoints\n",\
+"(1, 1) { 1 X2 } { };\n",\
+"(0, 1) { } { };\n",\
+"\n",\
+"newlines\n",\
+"(3, 2);\n",\
+"(4, 3);\n",\
+"(1, 4);\n",\
+"\n",\
+"freearea\n",\
+"(0, 0);\n",\
+"(1, 0) { 1 X2 } { };\n",\
+"(1.5, 1.5) { 1.5 X2 } { };\n",\
+"(-0.5, 1.5) { -0.5 X2 } { };\n",\
+"\n",\
+"freearea2\n",\
+"(0, 0);\n",\
+"(1, 0) { 1 X2 } { };\n",\
+"(1, 1) { 1 X2 } { };\n",\
+"(0, 1) { } { };\n",\
+"\n",\
+"elements\n",\
+"(1, 2, 3, 4);\n",\
+"\n",\
+"endrule\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"rule \"Quad Right (1)\"\n",\
+"\n",\
+"quality 1\n",\
+"\n",\
+"mappoints\n",\
+"(0, 0);\n",\
+"(1, 0);\n",\
+"(1, 1);\n",\
+"\n",\
+"maplines\n",\
+"(1, 2) del;\n",\
+"(2, 3) del;\n",\
+"\n",\
+"newpoints\n",\
+"(0, 1) { } { 1 y3 };\n",\
+"\n",\
+"newlines\n",\
+"(1, 4);\n",\
+"(4, 3);\n",\
+"\n",\
+"freearea\n",\
+"(0, 0);\n",\
+"(1, 0) { 1 X2 } { };\n",\
+"(1, 1) { 1 X3 } { 1 Y3 };\n",\
+"(-0.5, 1.5) { } { 1.5 Y3 };\n",\
+"\n",\
+"freearea2\n",\
+"(0, 0);\n",\
+"(1, 0) { 1 X2 } { };\n",\
+"(1, 1) { 1 X3 } { 1 Y3 };\n",\
+"(0, 1) { } { 1 Y3 };\n",\
+"\n",\
+"elements\n",\
+"(1, 2, 3, 4);\n",\
+"\n",\
+"endrule\n",\
+"\n",\
+"\n",\
+"\n",\
+"rule \"Quad P Right (2)\"\n",\
+"\n",\
+"quality 2\n",\
+"\n",\
+"mappoints\n",\
+"(0, 0);\n",\
+"(1, 0);\n",\
+"(1, 1);\n",\
+"\n",\
+"maplines\n",\
+"(1, 2) del;\n",\
+"\n",\
+"newpoints\n",\
+"(0, 1) { -1 X2, 1 X3 } { 1 Y3 };\n",\
+"\n",\
+"newlines\n",\
+"(1, 4);\n",\
+"(4, 3);\n",\
+"(3, 2);\n",\
+"\n",\
+"freearea\n",\
+"(0, 0);\n",\
+"(1, 0) { 1 X2 } { };\n",\
+"(1.2, 0.5) { 0.7 X2, 0.5 X3 } { 0.5 Y3 };\n",\
+"(1, 1) { 1 X3 } { 1 Y3 };\n",\
+"(-0.5, 1.5) { -2 X2, 1.5 X3 } { 1.5 Y3 };\n",\
+"\n",\
+"freearea2\n",\
+"(0, 0);\n",\
+"(1, 0) { 1 X2 } { };\n",\
+"(1, 0.5) { 0.5 X2, 0.5 X3 } { 0.5 Y3 };\n",\
+"(1, 1) { 1 X3 } { 1 Y3 };\n",\
+"(0, 1) { -1 X2, 1 X3 } { 1 Y3 };\n",\
+"\n",\
+"elements\n",\
+"(1, 2, 3, 4);\n",\
+"\n",\
+"\n",\
+"orientations\n",\
+"(1, 2, 3);\n",\
+"\n",\
+"\n",\
+"endrule\n",\
+"\n",\
+"\n",\
+"rule \"Quad P Right (150)\"\n",\
+"\n",\
+"quality 150\n",\
+"\n",\
+"mappoints\n",\
+"(0, 0);\n",\
+"(1, 0);\n",\
+"(1, 1);\n",\
+"\n",\
+"maplines\n",\
+"(1, 2) del;\n",\
+"\n",\
+"newpoints\n",\
+"(0, 1) { 1 X2, -1 X3 } { 1 Y3 };\n",\
+"\n",\
+"newlines\n",\
+"(1, 4)\n;",\
+"(4, 3)\n;",\
+"(3, 2)\n;",\
+"\n",\
+"freearea\n",\
+"(0, 0);\n",\
+"(1, 0) { 1 X2 } { };\n",\
+"(1.2, 0.5) { 0.7 X2, 0.5 X3 } { 0.5 Y3 };\n",\
+"(1, 1) { 1 X3 } { 1 Y3 };\n",\
+"(-0.5, 1.5) { -2 X2, 1.5 X3 } { 1.5 Y3 };\n",\
+"\n",\
+"freearea2\n",\
+"(0, 0);\n",\
+"(1, 0) { 1 X2 } { };\n",\
+"(1, 0.5) { 0.5 X2, 0.5 X3 } { 0.5 Y3 };\n",\
+"(1, 1) { 1 X3 } { 1 Y3 };\n",\
+"(0, 1) { 1 X2, -1 X3 } { 1 Y3 };\n",\
+"\n",\
+"elements\n",\
+"(1, 2, 3, 4);\n",\
+"\n",\
+"orientations\n",\
+"(1, 2, 3);\n",\
+"\n",\
+"endrule\n",\
+"\n",\
+"\n",\
+"rule \"Quad Right PL (2)\"\n",\
+"\n",\
+"quality 2\n",\
+"\n",\
+"mappoints\n",\
+"(0, 0);\n",\
+"(1, 0);\n",\
+"(1, 1);\n",\
+"(0, 1);\n",\
+"\n",\
+"maplines\n",\
+"(1, 2) del;\n",\
+"(2, 3) del;\n",\
+"\n",\
+"newpoints\n",\
+"\n",\
+"newlines\n",\
+"(1, 4);\n",\
+"(4, 3);\n",\
+"\n",\
+"freearea\n",\
+"(0, 0);\n",\
+"(1, 0) { 1 X2 } { };\n",\
+"(1, 1) { 1 X3 } { 1 Y3 };\n",\
+"(0.5, 1.2) { -0.1 X2, 0.6 X3, 0.6 X4 } { -0.1 Y2, 0.6 Y3, 0.6 Y4 };\n",\
+"(0, 1) { 1 X4 } { 1 Y4 };\n",\
+"(-0.2, 0.5) { -0.1 X2, -0.1 X3, 0.6 X4 } { -0.1 Y2, -0.1 Y3, 0.6 Y4 };\n",\
+"\n",\
+"freearea2\n",\
+"(0, 0);\n",\
+"(1, 0) { 1 X2 } { };\n",\
+"(1, 1) { 1 X3 } { 1 Y3 };\n",\
+"(0.5, 1) { 0.5 X3, 0.5 X4 } { 0.5 Y3, 0.5 Y4 };\n",\
+"(0, 1) { 1 X4 } { 1 Y4 };\n",\
+"(0, 0.5) { 0.5 X4 } { 0.5 Y4 };\n",\
+"\n",\
+"elements\n",\
+"(1, 2, 3, 4);\n",\
+"\n",\
+"orientations\n",\
+"(1, 2, 3);\n",\
+"(1, 3, 4);\n",\
+"(1, 2, 4);\n",\
+"(4, 2, 3);\n",\
+"\n",\
+"\n",\
+"endrule\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"rule \"Left Quad (1)\"\n",\
+"\n",\
+"quality 1\n",\
+"\n",\
+"mappoints\n",\
+"(0, 0);\n",\
+"(1, 0);\n",\
+"(0, 1);\n",\
+"\n",\
+"maplines\n",\
+"(1, 2) del;\n",\
+"(3, 1) del;\n",\
+"\n",\
+"newpoints\n",\
+"(1, 1) { 1 X2, 1 X3 } { 1 Y3 };\n",\
+"\n",\
+"newlines\n",\
+"(3, 4);\n",\
+"(4, 2);\n",\
+"\n",\
+"freearea\n",\
+"(0, 0);\n",\
+"(1, 0) { 1 X2 } { };\n",\
+"(1.5, 1.5) { 1.5 X2, 1.5 X3 } { 1.5 Y3 };\n",\
+"(0, 1) { 1 X3 } { 1 Y3 };\n",\
+"\n",\
+"freearea2\n",\
+"(0, 0);\n",\
+"(1, 0) { 1 X2 } { };\n",\
+"(1, 1) { 1 X2, 1 X3 } { 1 Y3 };\n",\
+"(0, 1) { 1 X3 } { 1 Y3 };\n",\
+"\n",\
+"elements\n",\
+"(1, 2, 4, 3);\n",\
+"\n",\
+"endrule\n",\
+"\n",\
+"\n",\
+"\n",\
+"rule \"Left P Quad (2)\"\n",\
+"\n",\
+"quality 2\n",\
+"\n",\
+"mappoints\n",\
+"(0, 0);\n",\
+"(1, 0);\n",\
+"(0, 1);\n",\
+"\n",\
+"maplines\n",\
+"(1, 2) del;\n",\
+"\n",\
+"newpoints\n",\
+"(1, 1) { 1 X2, 1 X3 } { 1 Y3 };\n",\
+"\n",\
+"newlines\n",\
+"(1, 3);\n",\
+"(3, 4);\n",\
+"(4, 2);\n",\
+"\n",\
+"freearea\n",\
+"(0, 0);\n",\
+"(1, 0) { 1 X2 } { };\n",\
+"(1.5, 1.5) { 1.5 X2, 1.5 X3 } { 1.5 Y3 };\n",\
+"(0, 1) { 1 X3 } { 1 Y3 };\n",\
+"(-0.2, 0.6) { -0.2 X2, 0.6 X3 } { 0.6 Y3 };\n",\
+"\n",\
+"freearea2\n",\
+"(0, 0);\n",\
+"(1, 0) { 1 X2 } { };\n",\
+"(1, 1) { 1 X2, 1 X3 } { 1 Y3 };\n",\
+"(0, 1) { 1 X3 } { 1 Y3 };\n",\
+"(0, 0.5) { 0.5 X3 } { 0.5 Y3 };\n",\
+"\n",\
+"elements\n",\
+"(1, 2, 4, 3);\n",\
+"\n",\
+"endrule\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"rule \"Left P Quad (150)\"\n",\
+"\n",\
+"quality 150\n",\
+"\n",\
+"mappoints\n",\
+"(0, 0);\n",\
+"(1, 0);\n",\
+"(0, 1);\n",\
+"\n",\
+"maplines\n",\
+"(1, 2) del;\n",\
+"\n",\
+"newpoints\n",\
+"(1, 1) { 1 X2, -1 X3 } { 1 Y3 };\n",\
+"\n",\
+"newlines\n",\
+"(1, 3);\n",\
+"(3, 4);\n",\
+"(4, 2);\n",\
+"\n",\
+"freearea\n",\
+"(0, 0);\n",\
+"(1, 0) { 1 X2 } { };\n",\
+"(1.5, 1.5) { 1.5 X2, 1.5 X3 } { 1.5 Y3 };\n",\
+"(0, 1) { 1 X3 } { 1 Y3 };\n",\
+"(-0.2, 0.6) { -0.2 X2, 0.6 X3 } { 0.6 Y3 };\n",\
+"\n",\
+"freearea2\n",\
+"(0, 0);\n",\
+"(1, 0) { 1 X2 } { };\n",\
+"(1, 1) { 1 X2, -1 X3 } { 1 Y3 };\n",\
+"(0, 1) { 1 X3 } { 1 Y3 };\n",\
+"(0, 0.5) { 0.5 X3 } { 0.5 Y3 };\n",\
+"\n",\
+"elements\n",\
+"(1, 2, 4, 3);\n",\
+"\n",\
+"endrule\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"rule \"Left Quad RP (2)\"\n",\
+"\n",\
+"quality 2\n",\
+"\n",\
+"mappoints\n",\
+"(0, 0);\n",\
+"(1, 0);\n",\
+"(0, 1);\n",\
+"(1, 1);\n",\
+"\n",\
+"maplines\n",\
+"(1, 2) del;\n",\
+"(3, 1) del;\n",\
+"\n",\
+"newpoints\n",\
+"\n",\
+"newlines\n",\
+"(3, 4);\n",\
+"(4, 2);\n",\
+"\n",\
+"freearea\n",\
+"(0, 0);\n",\
+"(1, 0) { 1 X2 } { };\n",\
+"(1.2, 0.5) { 0.6 X2, 0.6 X4, -0.1 X3 } { 0.6 Y2, 0.6 Y4, -0.1 Y3 };\n",\
+"(1, 1) { 1 X4 } { 1 Y4 };\n",\
+"(0.5, 1.2) { -0.1 X2, 0.6 X3, 0.6 X4 } { -0.1 Y2, 0.6 Y3, 0.6 Y4 };\n",\
+"(0, 1) { 1 X3 } { 1 Y3 };\n",\
+"\n",\
+"freearea2\n",\
+"(0, 0);\n",\
+"(1, 0) { 1 X2 } { };\n",\
+"(1, 0.5) { 0.5 X2, 0.5 X4 } { 0.5 Y2, 0.5 Y4 };\n",\
+"(1, 1) { 1 X4 } { 1 Y4 };\n",\
+"(0.5, 1) { 0.5 X3, 0.5 X4 } { 0.5 Y3, 0.5 Y4 };\n",\
+"(0, 1) { 1 X3 } { 1 Y3 };\n",\
+"\n",\
+"elements\n",\
+"(1, 2, 4, 3);\n",\
+"\n",\
+"orientations\n",\
+"(1, 2, 4);\n",\
+"(1, 4, 3);\n",\
+"\n",\
+"endrule\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"rule \"Two left (1)\"\n",\
+"\n",\
+"quality 1\n",\
+"\n",\
+"mappoints\n",\
+"(0, 0);\n",\
+"(1, 0);\n",\
+"(1, 1);\n",\
+"(0, 1);\n",\
+"\n",\
+"maplines\n",\
+"(1, 2) del;\n",\
+"(3, 4) del;\n",\
+"(4, 1) del;\n",\
+"\n",\
+"newpoints\n",\
+"\n",\
+"newlines\n",\
+"(3, 2);\n",\
+"\n",\
+"freearea\n",\
+"(0, 0);\n",\
+"(1, 0) { 1 X2 } { };\n",\
+"(1.5, 0.5) { 0.75 X2, 0.75 X3, -0.25 X4 } { 0.75 Y3, -0.25 Y4 };\n",\
+"(1, 1) { 1 X3 } { 1 Y3 };\n",\
+"(0, 1) { 1 X4 } { 1 Y4 };\n",\
+"\n",\
+"\n",\
+"freearea2\n",\
+"(0, 0);\n",\
+"(1, 0) { 1 X2 } { };\n",\
+"(1, 0.5) { 0.5 X2, 0.5 X3 } { 0.5 Y3 };\n",\
+"(1, 1) { 1 X3 } { 1 Y3 };\n",\
+"(0, 1) { 1 X4 } { 1 Y4 };\n",\
+"\n",\
+"elements\n",\
+"(1, 2, 3, 4);\n",\
+"\n",\
+"endrule\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"rule \"Two Right (1)\"\n",\
+"\n",\
+"quality 1\n",\
+"\n",\
+"mappoints\n",\
+"(0, 0);\n",\
+"(1, 0);\n",\
+"(1, 1);\n",\
+"(0, 1);\n",\
+"\n",\
+"maplines\n",\
+"(1, 2) del;\n",\
+"(2, 3) del;\n",\
+"(3, 4) del;\n",\
+"\n",\
+"newpoints\n",\
+"\n",\
+"newlines\n",\
+"(1, 4);\n",\
+"\n",\
+"freearea\n",\
+"(0, 0);\n",\
+"(1, 0) { 1 X2 } { };\n",\
+"(1, 1) { 1 X3 } { 1 Y3 };\n",\
+"(0, 1) { 1 X4 } { 1 Y4 };\n",\
+"(-0.5, 0.5) { -0.25 X2, -0.25 X3, 0.75 X4 } { -0.25 Y3, 0.75 Y4 };\n",\
+"\n",\
+"freearea2\n",\
+"(0, 0);\n",\
+"(1, 0) { 1 X2 } { };\n",\
+"(1, 1) { 1 X3 } { 1 Y3 };\n",\
+"(0, 1) { 1 X4 } { 1 Y4 };\n",\
+"(0, 0.5) { 0.5 X4 } { 0.5 Y4 };\n",\
+"\n",\
+"elements\n",\
+"(1, 2, 3, 4);\n",\
+"\n",\
+"endrule\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"rule \"Right 120 (1)\"\n",\
+"\n",\
+"quality 1000\n",\
+"\n",\
+"mappoints\n",\
+"(0, 0);\n",\
+"(1, 0);\n",\
+"(1.5, 0.866);\n",\
+"\n",\
+"maplines\n",\
+"(1, 2) del;\n",\
+"(2, 3) del;\n",\
+"\n",\
+"newpoints\n",\
+"(0.5, 0.866) { 1 X3, -1 X2 } { 1 Y3 };\n",\
+"\n",\
+"newlines\n",\
+"(1, 4);\n",\
+"(4, 3);\n",\
+"\n",\
+"freearea\n",\
+"(0, 0);\n",\
+"(1, 0) { 1 X2 } { };\n",\
+"(1.5, 0.866) { 1 X3 } { 1 Y3 };\n",\
+"(1, 1.732) { -2 X2, 2 X3 } { 2 Y3 };\n",\
+"(0, 1.732) { -3 X2, 2 X3 } { 2 Y3 };\n",\
+"(-0.5, 0.866) { -2 X2, 1 X3 } {1 Y3 };\n",\
+"\n",\
+"elements\n",\
+"(1, 2, 4);\n",\
+"(2, 3, 4);\n",\
+"\n",\
+"endrule\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"rule \"Left 120 (1)\"\n",\
+"\n",\
+"quality 1000\n",\
+"\n",\
+"mappoints\n",\
+"(0, 0);\n",\
+"(1, 0);\n",\
+"(-0.5, 0.866);\n",\
+"\n",\
+"maplines\n",\
+"(1, 2) del;\n",\
+"(3, 1) del;\n",\
+"\n",\
+"newpoints\n",\
+"(0.5, 0.866) { 1 X3, 1 X2 } { 1 Y3 };\n",\
+"\n",\
+"newlines\n",\
+"(3, 4);\n",\
+"(4, 2);\n",\
+"\n",\
+"freearea\n",\
+"(0, 0);\n",\
+"(1, 0) { 1 X2 } { };\n",\
+"(1.5, 0.866) { 2 X2, 1 X3 } { 1 Y3 };\n",\
+"(1, 1.732) { 2 X2, 2 X3 } { 2 Y3 };\n",\
+"(0, 1.732) { -1 X2, 2 X3 } { 2 Y3 };\n",\
+"(-0.5, 0.866) { 1 X3 } {1 Y3 };\n",\
+"\n",\
+"elements\n",\
+"(1, 2, 4);\n",\
+"(2, 3, 4);\n",\
+"\n",\
+"endrule\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"rule \"Left Right (1)\"\n",\
+"\n",\
+"quality 1\n",\
+"\n",\
+"mappoints\n",\
+"(0, 0);\n",\
+"(1, 0);\n",\
+"(1, 1);\n",\
+"(0, 1);\n",\
+"\n",\
+"maplines\n",\
+"(1, 2) del;\n",\
+"(2, 3) del;\n",\
+"(4, 1) del;\n",\
+"\n",\
+"\n",\
+"newlines\n",\
+"(4, 3);\n",\
+"\n",\
+"freearea\n",\
+"(0, 0);\n",\
+"(1, 0) { 1 X2 } { };\n",\
+"(1, 1) { 1 X3 } { 1 Y3 };\n",\
+"(0.5, 1.5) { -0.25 X2, 0.75 X3, 0.75 X4 } { 0.75 Y3, 0.75 Y4 };\n",\
+"(0, 1) { 1 X4 } { 1 Y4 };\n",\
+"\n",\
+"freearea2\n",\
+"(0, 0);\n",\
+"(1, 0) { 1 X2 } { };\n",\
+"(1, 1) { 1 X3 } { 1 Y3 };\n",\
+"(0.5, 1) { 0.5 X3, 0.5 X4 } { 0.5 Y3, 0.5 Y4 };\n",\
+"(0, 1) { 1 X4 } { 1 Y4 };\n",\
+"\n",\
+"\n",\
+"elements\n",\
+"(1, 2, 3, 4);\n",\
+"\n",\
+"endrule\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"rule \"Fill Quad\"\n",\
+"\n",\
+"quality 1\n",\
+"\n",\
+"mappoints\n",\
+"(0, 0);\n",\
+"(1, 0);\n",\
+"(1, 1);\n",\
+"(0, 1);\n",\
+"\n",\
+"maplines\n",\
+"(1, 2) del;\n",\
+"(2, 3) del;\n",\
+"(3, 4) del;\n",\
+"(4, 1) del;\n",\
+"\n",\
+"newpoints\n",\
+"\n",\
+"newlines\n",\
+"\n",\
+"freearea\n",\
+"(0, 0);\n",\
+"(1, 0) { 1 X2 } { 1 Y2 };\n",\
+"(1, 1) { 1 X3 } { 1 Y3 };\n",\
+"(0, 1) { 1 X4 } { 1 Y4 };\n",\
+"\n",\
+"elements\n",\
+"(1, 2, 3, 4);\n",\
+"\n",\
+"endrule\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"rule \"Fill Triangle\"\n",\
+"\n",\
+"quality 10\n",\
+"\n",\
+"mappoints\n",\
+"(0, 0);\n",\
+"(1, 0);\n",\
+"(0.5, 0.86);\n",\
+"\n",\
+"maplines\n",\
+"(1, 2) del;\n",\
+"(2, 3) del;\n",\
+"(3, 1) del;\n",\
+"\n",\
+"newpoints\n",\
+"\n",\
+"newlines\n",\
+"\n",\
+"freearea\n",\
+"(0, 0);\n",\
+"(1, 0) { 1 X2 } { 1 Y2 };\n",\
+"(0.5, 0.86) { 1 X3 } { 1 Y3 };\n",\
+"\n",\
+"elements\n",\
+"(1, 2, 3);\n",\
+"\n",\
+"endrule\n",\
+"\n",\
+"\n",\
+"\n",\
+"rule \"Right 60 (1)\"\n",\
+"\n",\
+"quality 10\n",\
+"\n",\
+"mappoints\n",\
+"(0, 0);\n",\
+"(1, 0) { 0.5, 0, 1.0 };\n",\
+"(0.5, 0.866) { 0.6, 0, 0.8 };\n",\
+"\n",\
+"maplines\n",\
+"(1, 2) del;\n",\
+"(2, 3) del;\n",\
+"\n",\
+"newpoints\n",\
+"\n",\
+"newlines\n",\
+"(1, 3);\n",\
+"\n",\
+"freearea\n",\
+"(0, 0);\n",\
+"(1, 0) { 1 X2 } { };\n",\
+"(0.5, 0.866) { 1 X3 } { 1 Y3 };\n",\
+"(-0.125, 0.6495) { -0.5 X2, 0.75 X3 } { -0.5 Y2, 0.75 Y3 };\n",\
+"\n",\
+"freearea2\n",\
+"(0, 0);\n",\
+"(1, 0) { 1 X2 } { };\n",\
+"(0.5, 0.866) { 1 X3 } { 1 Y3 };\n",\
+"(0.25, 0.433) { 0.5 X3 } { 0.5 Y3 };\n",\
+"\n",\
+"elements\n",\
+"(1, 2, 3);\n",\
+"\n",\
+"endrule\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"rule \"Vis A Vis (2)\"\n",\
+"\n",\
+"quality 2\n",\
+"\n",\
+"mappoints\n",\
+"(0, 0);\n",\
+"(1, 0);\n",\
+"(1, 1);\n",\
+"(0, 1);\n",\
+"\n",\
+"maplines\n",\
+"(1, 2) del;\n",\
+"(3, 4) del;\n",\
+"\n",\
+"newpoints\n",\
+"\n",\
+"newlines\n",\
+"(1, 4);\n",\
+"(3, 2);\n",\
+"\n",\
+"freearea\n",\
+"(0, 0);\n",\
+"(1, 0) { 1 X2 } { };\n",\
+"(1.5, 0.5) { 0.75 X2, 0.75 X3, -0.25 X4 } { 0.75 Y3, -0.25 Y4 };\n",\
+"(1, 1) { 1 X3 } { 1 Y3 };\n",\
+"(0, 1) { 1 X4 } { 1 Y4 };\n",\
+"(-0.5, 0.5) { -0.25 X2, -0.25 X3, 0.75 X4 } { -0.25 Y3, 0.75 Y4 };\n",\
+"\n",\
+"freearea2\n",\
+"(0, 0);\n",\
+"(1, 0) { 1 X2 } { };\n",\
+"(1, 0.5) { 0.5 X2, 0.5 X3 } { 0.5 Y3 };\n",\
+"(1, 1) { 1 X3 } { 1 Y3 };\n",\
+"(0, 1) { 1 X4 } { 1 Y4 };\n",\
+"(0, 0.5) { 0.5 X4 } { 0.5 Y4 };\n",\
+"\n",\
+"elements\n",\
+"(1, 2, 3, 4);\n",\
+"\n",\
+"orientations\n",\
+"(1, 3, 4);\n",\
+"(2, 3, 4);\n",\
+"(1, 2, 3);\n",\
+"(1, 2, 4);\n",\
+"\n",\
+"endrule\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"rule \"Triangle Vis A Vis (200)\"\n",\
+"\n",\
+"quality 200\n",\
+"\n",\
+"mappoints\n",\
+"(0, 0);\n",\
+"(1, 0);\n",\
+"(0.5, 0.866);\n",\
+"\n",\
+"maplines\n",\
+"(1, 2) del;\n",\
+"\n",\
+"newpoints\n",\
+"\n",\
+"newlines\n",\
+"(1, 3);\n",\
+"(3, 2);\n",\
+"\n",\
+"freearea\n",\
+"(0, 0);\n",\
+"(1, 0) { 1 X2 } { };\n",\
+"(1.2, 0.693) { 0.8 X2, 0.8 X3 } { 0.8 Y2, 0.8 Y3 };\n",\
+"(0.5, 0.866) { 1 X3 } { 1 Y3 };\n",\
+"(-0.2, 0.693) { -0.6 X2, 0.8 X3 } { -0.6 Y2, 0.8 Y3 };\n",\
+"\n",\
+"freearea2\n",\
+"(0, 0);\n",\
+"(1, 0) { 1 X2 } { };\n",\
+"(0.75, 0.433) { 0.5 X2, 0.5 X3 } { 0.5 Y2, 0.5 Y3 };\n",\
+"(0.5, 0.866) { 1 X3 } { 1 Y3 };\n",\
+"(0.25, 0.433) { 0.5 X3 } { 0.5 Y3 };\n",\
+"\n",\
+"elements\n",\
+"(1, 2, 3);\n",\
+"\n",\
+"endrule\n",\
+"\n",\
+"\n",\
+"\n",\
+"rule \"2 h Vis A Vis (1)\"\n",\
+"\n",\
+"quality 3000\n",\
+"\n",\
+"mappoints\n",\
+"(0, 0);\n",\
+"(1, 0);\n",\
+"(1, 1.732);\n",\
+"(0, 1.732);\n",\
+"\n",\
+"maplines\n",\
+"(1, 2) del;\n",\
+"(3, 4) del;\n",\
+"\n",\
+"newpoints\n",\
+"(0.5, 0.866) { 0.25 X3, 0.25 X4 } { 0.25 Y2, 0.25 Y3, 0.25 Y4 };\n",\
+"\n",\
+"newlines\n",\
+"(1, 5);\n",\
+"(5, 4);\n",\
+"(3, 5);\n",\
+"(5, 2);\n",\
+"\n",\
+"freearea\n",\
+"(0, 0);\n",\
+"(1, 0) { 1 X2 } { 1 Y2 };\n",\
+"(1.5, 0.866) { 0.75 X2, 0.75 X3, -0.25 X4 } { 0.75 Y2, 0.75 Y3, -0.25 Y4 };\n",\
+"(1, 1.732) { 1 X3 } { 1 Y3 };\n",\
+"(0, 1.732) { 1 X4 } { 1 Y4 };\n",\
+"(-0.5, 0.866) { 0.75 X4, -0.25 X2, -0.25 X3 } { 0.75 Y4, -0.25 Y3 };\n",\
+"\n",\
+"elements\n",\
+"(1, 2, 5);\n",\
+"(3, 4, 5);\n",\
+"\n",\
+"endrule\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+0};
+}
diff --git a/contrib/Netgen/libsrc/meshing/refine.cpp b/contrib/Netgen/libsrc/meshing/refine.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..3ed792cb262c0a1ec4b420ae26c0215eaf30db2d
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/refine.cpp
@@ -0,0 +1,732 @@
+#include <mystdlib.h>
+#include "meshing.hpp"
+
+
+namespace netgen
+{
+  void Refinement :: Refine (Mesh & mesh)
+  {
+    // reduce 2nd order
+    mesh.ComputeNVertices();
+    mesh.SetNP(mesh.GetNV());
+
+
+    INDEX_2_HASHTABLE<int> between(mesh.GetNP() + 5);
+      
+    int oldne, oldns, oldnf;
+
+    // refine edges
+
+    ARRAY<EdgePointGeomInfo,PointIndex::BASE> epgi;
+
+    oldns = mesh.GetNSeg();
+    for (SegmentIndex si = 0; si < oldns; si++)
+      {
+	const Segment & el = mesh.LineSegment(si);
+
+	INDEX_2 i2 = INDEX_2::Sort(el.p1, el.p2);
+	PointIndex pinew;
+	EdgePointGeomInfo ngi;
+
+	if (between.Used(i2))
+	  {
+	    pinew = between.Get(i2);
+	    ngi = epgi[pinew]; 
+	  }
+	else
+	  {
+	    Point<3> pnew;
+
+	    PointBetween (mesh.Point (el.p1),
+			  mesh.Point (el.p2), 0.5,
+			  el.surfnr1, el.surfnr2,
+			  el.epgeominfo[0], el.epgeominfo[1],
+			  pnew, ngi);
+
+	    pinew = mesh.AddPoint (pnew);
+	    between.Set (i2, pinew);
+
+
+	    if (pinew >= epgi.Size()+PointIndex::BASE)
+	      epgi.SetSize (pinew+1-PointIndex::BASE);
+	    epgi[pinew] = ngi;
+	  }
+
+	Segment ns1 = el;
+	Segment ns2 = el;
+	ns1.p2 = pinew;
+	ns1.epgeominfo[1] = ngi;
+	ns2.p1 = pinew;
+	ns2.epgeominfo[0] = ngi;
+
+	mesh.LineSegment(si) = ns1;
+	mesh.AddSegment (ns2);
+      }
+
+    // refine surface elements
+    ARRAY<PointGeomInfo,PointIndex::BASE> surfgi (8*mesh.GetNP());
+    for (int i = PointIndex::BASE;
+	 i < surfgi.Size()+PointIndex::BASE; i++)
+      surfgi[i].trignum = -1;
+
+
+    oldnf = mesh.GetNSE();
+    for (SurfaceElementIndex sei = 0; sei < oldnf; sei++)
+      {
+	int j, k;
+	const Element2d & el = mesh.SurfaceElement(sei);
+
+	switch (el.GetType())
+	  {
+	  case TRIG:
+	  case TRIG6:
+	    {
+	      ArrayMem<int,6> pnums(6);
+	      ArrayMem<PointGeomInfo,6> pgis(6);
+
+	      static int betw[3][3] =
+		{ { 2, 3, 4 },
+		  { 1, 3, 5 },
+		  { 1, 2, 6 } };
+
+	      for (j = 1; j <= 3; j++)
+		{
+		  pnums.Elem(j) = el.PNum(j);
+		  pgis.Elem(j) = el.GeomInfoPi(j);
+		}
+
+	      for (j = 0; j < 3; j++)
+		{
+		  PointIndex pi1 = pnums.Elem(betw[j][0]);
+		  PointIndex pi2 = pnums.Elem(betw[j][1]);
+
+		  INDEX_2 i2 (pi1, pi2);
+		  i2.Sort();
+
+		  Point<3> pb;
+		  PointGeomInfo pgi;
+		  PointBetween (mesh.Point (pi1),
+				mesh.Point (pi2), 0.5,
+				mesh.GetFaceDescriptor(el.GetIndex ()).SurfNr(),
+				el.GeomInfoPi (betw[j][0]),
+				el.GeomInfoPi (betw[j][1]),
+				pb, pgi);
+
+
+		  pgis.Elem(4+j) = pgi;
+		  if (between.Used(i2))
+		    pnums.Elem(4+j) = between.Get(i2);
+		  else
+		    {
+		      pnums.Elem(4+j) = mesh.AddPoint (pb);
+		      between.Set (i2, pnums.Get(4+j));
+		    }
+
+		  if (surfgi.Size() < pnums.Elem(4+j))
+		    surfgi.SetSize (pnums.Elem(4+j));
+		  surfgi.Elem(pnums.Elem(4+j)) = pgis.Elem(4+j);
+		}
+
+
+	      static int reftab[4][3] =
+		{ { 1, 6, 5 },
+		  { 2, 4, 6 },
+		  { 3, 5, 4 },
+		  { 6, 4, 5 } };
+
+	      int ind = el.GetIndex();
+	      for (j = 0; j < 4; j++)
+		{
+		  Element2d nel(TRIG);
+		  for (k = 1; k <= 3; k++)
+		    {
+		      nel.PNum(k) = pnums.Get(reftab[j][k-1]);
+		      nel.GeomInfoPi(k) = pgis.Get(reftab[j][k-1]);
+		    }
+		  nel.SetIndex(ind);
+
+		  if (j == 0)
+		    mesh.SurfaceElement(sei) = nel;
+		  else
+		    mesh.AddSurfaceElement(nel);
+		}
+	      break;
+	    }
+	  case QUAD:
+	  case QUAD6:
+	  case QUAD8:
+	    {
+	      ArrayMem<int,9> pnums(9);
+	      ArrayMem<PointGeomInfo,9> pgis(9);
+
+	      static int betw[5][3] =
+		{ { 1, 2, 5 },
+		  { 2, 3, 6 },
+		  { 3, 4, 7 },
+		  { 1, 4, 8 },
+		  { 5, 7, 9 } };
+
+	      for (j = 1; j <= 4; j++)
+		{
+		  pnums.Elem(j) = el.PNum(j);
+		  pgis.Elem(j) = el.GeomInfoPi(j);
+		}
+
+	      for (j = 0; j < 5; j++)
+		{
+		  int pi1 = pnums.Elem(betw[j][0]);
+		  int pi2 = pnums.Elem(betw[j][1]);
+
+		  INDEX_2 i2 (pi1, pi2);
+		  i2.Sort();
+
+		  if (between.Used(i2))
+		    {
+		      pnums.Elem(5+j) = between.Get(i2);
+		      pgis.Elem(5+j) = surfgi.Get(pnums.Elem(4+j));
+		    }
+		  else
+		    {
+		      Point<3> pb;
+		      PointBetween (mesh.Point (pi1),
+				    mesh.Point (pi2), 0.5,
+				    mesh.GetFaceDescriptor(el.GetIndex ()).SurfNr(),
+				    el.GeomInfoPi (betw[j][0]),
+				    el.GeomInfoPi (betw[j][1]),
+				    pb, pgis.Elem(5+j));
+
+		      pnums.Elem(5+j) = mesh.AddPoint (pb);
+
+		      between.Set (i2, pnums.Get(5+j));
+		      
+		      if (surfgi.Size() < pnums.Elem(5+j))
+			surfgi.SetSize (pnums.Elem(5+j));
+		      surfgi.Elem(pnums.Elem(5+j)) = pgis.Elem(5+j);
+		    }
+		}
+
+	      static int reftab[4][4] =
+		{
+		  { 1, 5, 9, 8 },
+		  { 5, 2, 6, 9 },
+		  { 8, 9, 7, 4 },
+		  { 9, 6, 3, 7 } };
+
+	      int ind = el.GetIndex();
+	      for (j = 0; j < 4; j++)
+		{
+		  Element2d nel(QUAD);
+		  for (k = 1; k <= 4; k++)
+		    {
+		      nel.PNum(k) = pnums.Get(reftab[j][k-1]);
+		      nel.GeomInfoPi(k) = pgis.Get(reftab[j][k-1]);
+		    }
+		  nel.SetIndex(ind);
+
+		  if (j == 0)
+		    mesh.SurfaceElement(sei) = nel;
+		  else
+		    mesh.AddSurfaceElement(nel);
+		}
+	      break;
+	    }
+	  default:
+	    PrintSysError ("Refine: undefined surface element type ", int(el.GetType()));
+	  }
+      }
+
+    // refine volume elements
+    oldne = mesh.GetNE();
+    for (ElementIndex ei = 0; ei < oldne; ei++)
+      {
+	int j, k;
+
+	const Element & el = mesh.VolumeElement(ei);
+	switch (el.GetType())
+	  {
+	  case TET:
+	  case TET10:
+	    {
+	     ArrayMem<int,10> pnums(10);
+	     static int betw[6][3] =
+	     { { 1, 2, 5 },
+	       { 1, 3, 6 },
+	       { 1, 4, 7 },
+	       { 2, 3, 8 },
+	       { 2, 4, 9 },
+	       { 3, 4, 10 } };
+
+	     int elrev = el.flags.reverse;
+
+	     for (j = 1; j <= 4; j++)
+	     pnums.Elem(j) = el.PNum(j);
+	     if (elrev)
+	     swap (pnums.Elem(3), pnums.Elem(4));
+
+	     for (j = 0; j < 6; j++)
+	     {
+	       INDEX_2 i2;
+	       i2.I1() = pnums.Get(betw[j][0]);
+	       i2.I2() = pnums.Get(betw[j][1]);
+	       i2.Sort();
+
+	       if (between.Used(i2))
+	          pnums.Elem(5+j) = between.Get(i2);
+	       else
+	       {
+		  pnums.Elem(5+j) = mesh.AddPoint
+		  (Center (mesh.Point(i2.I1()),
+			   mesh.Point(i2.I2())));
+		  between.Set (i2, pnums.Elem(5+j));
+	       }
+	    }
+
+	    static int reftab[8][4] =
+	    { { 1, 5, 6, 7 },
+	      { 5, 2, 8, 9 },
+	      { 6, 8, 3, 10 },
+	      { 7, 9, 10, 4 },
+	      { 5, 6, 7, 9 },
+	      { 5, 6, 9, 8 },
+	      { 6, 7, 9, 10 },
+	      { 6, 8, 10, 9 } };
+	/*
+	  { { 1, 5, 6, 7 },
+	  { 5, 2, 8, 9 },
+	  { 6, 8, 3, 10 },
+	  { 7, 9, 10, 4 },
+	  { 5, 6, 7, 9 },
+	  { 5, 6, 8, 9 },
+	  { 6, 7, 9, 10 },
+	  { 6, 8, 9, 10 } };
+	*/
+	   static bool reverse[8] =
+	   {
+	      false, false, false, false, false, true, false, true
+	   };
+
+	   int ind = el.GetIndex();
+	   for (j = 0; j < 8; j++)
+	   {
+	      Element nel;
+	      for (k = 1; k <= 4; k++)
+	        nel.PNum(k) = pnums.Get(reftab[j][k-1]);
+	      nel.SetIndex(ind);
+	      nel.flags.reverse = reverse[j];
+	      if (elrev)
+	      {
+		nel.flags.reverse = !nel.flags.reverse;
+		swap (nel.PNum(3), nel.PNum(4));
+	      }
+
+	      if (j == 0)
+	        mesh.VolumeElement(ei) = nel;
+	      else
+	        mesh.AddVolumeElement (nel);
+	    }
+	    break;
+          }
+          case HEX:
+          {
+	     ArrayMem<int,27> pnums(27);
+	     static int betw[13][3] =
+	     { { 1, 2, 9 },
+	       { 3, 4, 10 },
+	       { 4, 1, 11 },
+               { 2, 3, 12 },
+	       { 5, 6, 13 },
+	       { 7, 8, 14 },
+	       { 8, 5, 15 },
+	       { 6, 7, 16 },
+	       { 1, 5, 17 },
+	       { 2, 6, 18 },
+	       { 3, 7, 19 },
+	       { 4, 8, 20 },
+	       { 2, 8, 21 },
+	       };
+
+	     static int fbetw[12][3] =
+	     { { 1, 3, 22 },
+	       { 2, 4, 22 },
+	       { 5, 7, 23 },
+               { 6, 8, 23 },
+	       { 1, 6, 24 },
+	       { 2, 5, 24 },
+	       { 2, 7, 25 },
+	       { 3, 6, 25 },
+	       { 3, 8, 26 },
+	       { 4, 7, 26 },
+	       { 1, 8, 27 },
+	       { 4, 5, 27 },
+	       };
+
+
+	     pnums = -1;
+
+	     for (j = 1; j <= 8; j++)
+	     pnums.Elem(j) = el.PNum(j);
+
+
+	     for (j = 0; j < 13; j++)
+	     {
+	       INDEX_2 i2;
+	       i2.I1() = pnums.Get(betw[j][0]);
+	       i2.I2() = pnums.Get(betw[j][1]);
+	       i2.Sort();
+
+	       if (between.Used(i2))
+	          pnums.Elem(9+j) = between.Get(i2);
+	       else
+	       {
+		  pnums.Elem(9+j) = mesh.AddPoint
+		  (Center (mesh.Point(i2.I1()),
+			   mesh.Point(i2.I2())));
+		  between.Set (i2, pnums.Elem(9+j));
+	       }
+	    }
+
+	    for (j = 0; j < 6; j++)
+	    {
+	       INDEX_2 i2a, i2b;
+	       i2a.I1() = pnums.Get(fbetw[2*j][0]);
+	       i2a.I2() = pnums.Get(fbetw[2*j][1]);
+	       i2a.Sort();
+	       i2b.I1() = pnums.Get(fbetw[2*j+1][0]);
+	       i2b.I2() = pnums.Get(fbetw[2*j+1][1]);
+	       i2b.Sort();
+
+	       if (between.Used(i2a))
+		 pnums.Elem(22+j) = between.Get(i2a);
+	       else if (between.Used(i2b))
+		 pnums.Elem(22+j) = between.Get(i2b);
+	       else
+		 {
+		   pnums.Elem(22+j) = mesh.AddPoint
+		     (Center (mesh.Point(i2a.I1()),
+			      mesh.Point(i2a.I2())));
+
+		   between.Set (i2a, pnums.Elem(22+j));
+		 }
+	    }
+
+	    static int reftab[8][8] =
+	    { { 1, 9, 22, 11, 17, 24, 21, 27 },
+	      { 9, 2, 12, 22, 24, 18, 25, 21 },
+	      { 11, 22, 10, 4, 27, 21, 26, 20},
+	      { 22, 12, 3, 10, 21, 25, 19, 26},
+	      { 17, 24, 21, 27, 5, 13, 23, 15},
+	      { 24, 18, 25, 21, 13, 6, 16, 23},
+	      { 27, 21, 26, 20, 15, 23, 14, 8},
+	      { 21, 25, 19, 26, 23, 16, 7, 14} };
+
+
+	   int ind = el.GetIndex();
+	   for (j = 0; j < 8; j++)
+	   {
+	      Element nel(HEX);
+	      for (k = 1; k <= 8; k++)
+	        nel.PNum(k) = pnums.Get(reftab[j][k-1]);
+	      nel.SetIndex(ind);
+
+              if (j == 0)
+	        mesh.VolumeElement(ei) = nel;
+	      else
+	        mesh.AddVolumeElement (nel);
+           }
+           break;
+	  }
+	  case PRISM:
+          {
+	     ArrayMem<int,18> pnums(18);
+	     static int betw[9][3] =
+	     { { 3, 1, 7 },
+	       { 1, 2, 8 },
+	       { 3, 2, 9 },
+               { 6, 4, 10 },
+	       { 4, 5, 11 },
+	       { 6, 5, 12 },
+	       { 1, 4, 13 },
+	       { 3, 6, 14 },
+	       { 2, 5, 15 },
+	       };
+
+// he: 15.jul 08, old version is wrong
+//                produces double points ad quad faces and inconsistent mesh
+// 	     static int fbetw[6][3] =
+// 	     { { 1, 6, 16 },
+// 	       { 3, 4, 16 },
+// 	       { 1, 5, 17 },
+//                { 2, 4, 17 },
+// 	       { 2, 6, 18 },
+// 	       { 3, 5, 18 },
+// 	       };
+           
+           static int fbetw[6][3] =
+           { { 7, 10, 16 },
+           { 14, 13, 16 },
+           { 11, 8, 17 },
+           { 13, 15, 17 },
+           { 12, 9, 18 },
+           { 14, 15, 18 },
+           };
+
+	     //int elrev = el.flags.reverse;
+	     pnums = -1;
+
+	     for (j = 1; j <= 6; j++)
+	     pnums.Elem(j) = el.PNum(j);
+	    // if (elrev)
+	    // swap (pnums.Elem(3), pnums.Elem(4));
+
+	     for (j = 0; j < 9; j++)
+	     {
+	       INDEX_2 i2;
+	       i2.I1() = pnums.Get(betw[j][0]);
+	       i2.I2() = pnums.Get(betw[j][1]);
+	       i2.Sort();
+
+	       if (between.Used(i2))
+	          pnums.Elem(7+j) = between.Get(i2);
+	       else
+	       {
+		  pnums.Elem(7+j) = mesh.AddPoint
+		  (Center (mesh.Point(i2.I1()),
+			   mesh.Point(i2.I2())));
+		  between.Set (i2, pnums.Elem(7+j));
+	       }
+	    }
+
+	    for (j = 0; j < 3; j++)
+	    {
+	       INDEX_2 i2a, i2b;
+	       i2a.I1() = pnums.Get(fbetw[2*j][0]);
+	       i2a.I2() = pnums.Get(fbetw[2*j][1]);
+	       i2a.Sort();
+	       i2b.I1() = pnums.Get(fbetw[2*j+1][0]);
+	       i2b.I2() = pnums.Get(fbetw[2*j+1][1]);
+	       i2b.Sort();
+
+	       if (between.Used(i2a))
+		 pnums.Elem(16+j) = between.Get(i2a);
+	       else if (between.Used(i2b))
+		 pnums.Elem(16+j) = between.Get(i2b);
+	       else
+		 {
+		   pnums.Elem(16+j) = mesh.AddPoint
+		     (Center (mesh.Point(i2a.I1()),
+			      mesh.Point(i2a.I2())));
+
+		   between.Set (i2a, pnums.Elem(16+j));
+		 }
+	    }
+
+
+	    static int reftab[8][6] =
+	    { { 1, 8, 7, 13, 17, 16 },
+	      { 7, 8, 9, 16, 17, 18 },
+	      { 7, 9, 3, 16, 18, 14 },
+	      { 8, 2, 9, 17, 15, 18 },
+	      { 13, 17, 16, 4, 11, 10 },
+	      { 16, 17, 18, 10, 11, 12 },
+	      { 16, 18, 14, 10, 12, 6 },
+	      { 17, 15, 18, 11, 5, 12 } };
+
+
+	   int ind = el.GetIndex();
+	   for (j = 0; j < 8; j++)
+	   {
+	      Element nel(PRISM);
+	      for (k = 1; k <= 6; k++)
+	        nel.PNum(k) = pnums.Get(reftab[j][k-1]);
+	      nel.SetIndex(ind);
+
+
+	      //nel.flags.reverse = reverse[j];
+	      //if (elrev)
+	     // {
+		//nel.flags.reverse = 1 - nel.flags.reverse;
+		//swap (nel.PNum(3), nel.PNum(4));
+
+
+	      if (j == 0)
+	        mesh.VolumeElement(ei) = nel;
+	      else
+	        mesh.AddVolumeElement (nel);
+           }
+           break;
+	  }
+	  default:
+	    PrintSysError ("Refine: undefined volume element type ", int(el.GetType()));
+        }
+      }
+
+
+    // update identification tables
+    for (int i = 1; i <= mesh.GetIdentifications().GetMaxNr(); i++)
+      {
+	ARRAY<int,PointIndex::BASE> identmap;
+	mesh.GetIdentifications().GetMap (i, identmap);
+
+	for (int j = 1; j <= between.GetNBags(); j++)
+	  for (int k = 1; k <= between.GetBagSize(j); k++)
+	    {
+	      INDEX_2 i2;
+	      int newpi;
+	      between.GetData (j, k, i2, newpi);
+	      INDEX_2 oi2(identmap.Get(i2.I1()),
+			  identmap.Get(i2.I2()));
+	      oi2.Sort();
+	      if (between.Used (oi2))
+		{
+		  int onewpi = between.Get(oi2);
+		  mesh.GetIdentifications().Add (newpi, onewpi, i);
+		}
+	    }
+
+      }
+
+    mesh.ComputeNVertices();
+    return;
+
+    int cnttrials = 10;
+    int wrongels = 0;
+    for (int i = 1; i <= mesh.GetNE(); i++)
+      if (mesh.VolumeElement(i).Volume(mesh.Points()) < 0)
+	{
+	  wrongels++;
+	  mesh.VolumeElement(i).flags.badel = 1;
+	}
+      else
+	mesh.VolumeElement(i).flags.badel = 0;
+
+    if (wrongels)
+      {
+	cout << "WARNING: " << wrongels << " with wrong orientation found" << endl;
+
+	int np = mesh.GetNP();
+	ARRAY<Point<3> > should(np);
+	ARRAY<Point<3> > can(np);
+	for (int i = 1; i <= np; i++)
+	  {
+	    should.Elem(i) = can.Elem(i) = mesh.Point(i);
+	  }
+	for (int i = 1; i <= between.GetNBags(); i++)
+	  for (int j = 1; j <= between.GetBagSize(i); j++)
+	    {
+	      INDEX_2 parent;
+	      int child;
+	      between.GetData (i, j, parent, child);
+	      can.Elem(child) = Center (can.Elem(parent.I1()),
+					can.Elem(parent.I2()));
+	    }
+
+	BitArray boundp(np);
+	boundp.Clear();
+	for (int i = 1; i <= mesh.GetNSE(); i++)
+	  {
+	    const Element2d & sel = mesh.SurfaceElement(i);
+	    for (int j = 1; j <= sel.GetNP(); j++)
+	      boundp.Set(sel.PNum(j));
+	  }
+
+
+	double lam = 0.5;
+
+	while (lam < 0.9 && cnttrials > 0)
+	  {
+	    lam = 2;
+	    do
+	      {
+		lam *= 0.5;
+		cnttrials--;
+
+		cout << "lam = " << lam << endl;
+
+		for (int i = 1; i <= np; i++)
+		  if (boundp.Test(i))
+		    {
+		      for (int j = 0; j < 3; j++)
+			mesh.Point(i)(j) = 
+			  lam * should.Get(i)(j) +
+			  (1-lam) * can.Get(i)(j);
+		    }
+		  else
+		    mesh.Point(i) = can.Get(i);
+	      
+
+		BitArray free (mesh.GetNP()), fhelp(mesh.GetNP());
+		free.Clear();
+		for (int i = 1; i <= mesh.GetNE(); i++)
+		  {
+		    const Element & el = mesh.VolumeElement(i);
+		    if (el.Volume(mesh.Points()) < 0)
+		      for (int j = 1; j <= el.GetNP(); j++)
+			free.Set (el.PNum(j));
+		  }
+		for (int k = 1; k <= 3; k++)
+		  {
+		    fhelp.Clear();
+		    for (int i = 1; i <= mesh.GetNE(); i++)
+		      {
+			const Element & el = mesh.VolumeElement(i);
+			int freeel = 0;
+			for (int j = 1; j <= el.GetNP(); j++)
+			  if (free.Test(el.PNum(j)))
+			    freeel = 1;
+			if (freeel)
+			  for (int j = 1; j <= el.GetNP(); j++)
+			    fhelp.Set (el.PNum(j));
+		      }
+		    free.Or (fhelp);
+		  }
+
+		(*testout) << "smooth points: " << endl;
+		for (int i = 1; i <= free.Size(); i++)
+		  if (free.Test(i))
+		    (*testout) << "p " << i << endl;
+
+		(*testout) << "surf points: " << endl;
+		for (int i = 1; i <= mesh.GetNSE(); i++)
+		  for (int j = 1; j <= 3; j++)
+		    (*testout) << mesh.SurfaceElement(i).PNum(j) << endl;
+		  
+
+
+		mesh.CalcSurfacesOfNode();
+		free.Invert();
+		mesh.FixPoints (free);
+		mesh.ImproveMesh (OPT_REST);
+
+
+		wrongels = 0;
+		for (int i = 1; i <= mesh.GetNE(); i++)
+		  {
+		    if (mesh.VolumeElement(i).Volume(mesh.Points()) < 0)
+		      {
+			wrongels++;
+			mesh.VolumeElement(i).flags.badel = 1;
+			(*testout) << "wrong el: ";
+			for (int j = 1; j <= 4; j++)
+			  (*testout) << mesh.VolumeElement(i).PNum(j) << " ";
+			(*testout) << endl;
+		      }
+		    else
+		      mesh.VolumeElement(i).flags.badel = 0;
+		  }
+		cout << "wrongels = " << wrongels << endl;
+	      }
+	    while (wrongels && cnttrials > 0);
+	  
+	    for (int i = 1; i <= np; i++)
+	      can.Elem(i) = mesh.Point(i);
+	  }
+      }
+
+    if (cnttrials <= 0)
+      {
+	cerr << "ERROR: Sorry, reverted elements" << endl;
+      }
+ 
+    mesh.ComputeNVertices();
+  }
+}
diff --git a/contrib/Netgen/libsrc/meshing/ruler2.cpp b/contrib/Netgen/libsrc/meshing/ruler2.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..6040ad2152724d9638ee76d80d4b24db8dd81293
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/ruler2.cpp
@@ -0,0 +1,641 @@
+#include <mystdlib.h>
+#include "meshing.hpp"
+
+namespace netgen
+{
+
+
+static double CalcElementBadness (const ARRAY<Point2d> & points,
+				  const Element2d & elem)
+{
+  // badness = sqrt(3) /36 * circumference^2 / area - 1 +
+  //           h / li + li / h - 2
+
+  Vec2d v12, v13, v23;
+  double l12, l13, l23, cir, area;
+  static const double c = sqrt(3.0) / 36;
+
+  v12 = points.Get(elem.PNum(2)) - points.Get(elem.PNum(1));
+  v13 = points.Get(elem.PNum(3)) - points.Get(elem.PNum(1));
+  v23 = points.Get(elem.PNum(3)) - points.Get(elem.PNum(2));
+
+  l12 = v12.Length();
+  l13 = v13.Length();
+  l23 = v23.Length();
+
+  cir = l12 + l13 + l23;
+  area = 0.5 * (v12.X() * v13.Y() - v12.Y() * v13.X());
+  if (area < 1e-6)
+    {
+      return 1e8;
+    }
+
+  if (testmode)
+    {
+      (*testout) << "l = " << l12 << " + " << l13 << " + " << l23 << " = " 
+		 << cir << ", area = " << area << endl;
+      (*testout) << "shapeerr = " << 10 * (c * cir * cir / area - 1) << endl
+		 << "sizeerr = " << 1/l12 + l12 + 1/l13 + l13 + 1/l23 + l23 - 6
+		 << endl;
+    }
+
+  return 10 * (c * cir * cir / area - 1)
+    + 1/l12 + l12 + 1/l13 + l13 + 1/l23 + l23 - 6;
+}
+
+
+
+int Meshing2 ::ApplyRules (ARRAY<Point2d> & lpoints, 
+			   ARRAY<int> & legalpoints,
+			   int maxlegalpoint,
+			   ARRAY<INDEX_2> & llines,
+			   int maxlegalline,
+			   ARRAY<Element2d> & elements,
+			   ARRAY<INDEX> & dellines, int tolerance)
+{
+  int i, j, ri, nlok, npok, incnpok, refpi, locli = 0;
+
+  double maxerr = 0.5 + 0.3 * tolerance;
+  double minelerr = 2 + 0.5 * tolerance * tolerance;
+
+
+  bool ok;
+  int found;   // rule number
+  Vector oldu, newu;
+  Point2d np;
+  Vec2d linevec;
+  int oldnp;
+  INDEX_2 loclin;
+  double hf, elerr;
+  int noldlp, noldll;
+  int loctestmode;
+
+  static ARRAY<int> pused, pmap, pfixed;
+  static ARRAY<int, 1> lmap, lused;
+  static ARRAY<int> pnearness, lnearness;
+  
+  static ARRAY<Point2d> tempnewpoints;
+  static ARRAY<INDEX_2> tempnewlines;
+  static ARRAY<int> tempdellines;
+  static ARRAY<Element2d> tempelements;
+
+
+
+  elements.SetSize (0);
+  dellines.SetSize (0);
+
+  noldlp = lpoints.Size();
+  noldll = llines.Size();
+
+  pused.SetSize (maxlegalpoint);
+  lused.SetSize (maxlegalline);
+  pnearness.SetSize (noldlp);
+  lnearness.SetSize (llines.Size());
+
+
+  testmode = debugparam.debugoutput;
+  loctestmode = testmode;
+
+  if (loctestmode)
+    {
+      (*testout) << endl << endl << "Check new environment" << endl;
+      (*testout) << "tolerance = " << tolerance << endl;
+      for (i = 1; i <= lpoints.Size(); i++)
+	(*testout) << "P" << i << " = " << lpoints.Get(i) << endl;
+      (*testout) << endl;
+      for (i = 1; i <= llines.Size(); i++)
+	(*testout) << "(" << llines.Get(i).I1() << "-" << llines.Get(i).I2() << ")" << endl;
+    }
+
+  // check every rule
+
+  found = 0;
+
+  
+  for (i = 1; i <= noldlp; i++)
+    pnearness.Set(i, 1000);
+  
+  for (j = 1; j <= 2; j++)
+    pnearness.Set(llines.Get(1).I(j), 0);
+    
+
+  do
+    {
+      ok = 1;
+      for (i = 1; i <= maxlegalline; i++)
+	{
+	  const INDEX_2 & hline = llines.Get(i);
+
+	  /*
+	  int minn = INT_MAX-1;
+	  for (j = 1; j <= 2; j++)
+	    {
+	      int hi = pnearness.Get(hline.I(j));
+	      if (hi < minn) minn = hi;
+	    }
+	  */
+	  int minn = pnearness.Get(hline.I1());
+	  int minn2 = pnearness.Get(hline.I2());
+	  if (minn2 < minn)
+	    minn = minn2;
+
+	  /*
+	  for (j = 1; j <= 2; j++)
+	    {
+	      int hpi = hline.I(j);
+	      if (pnearness.Get(hpi) > minn+1)
+		{
+		  ok = 0;
+		  pnearness.Set(hpi, minn+1);
+		}
+	    }
+	  */
+	  int hpi = hline.I1();
+	  if (pnearness.Get(hpi) > minn+1)
+	    {
+	      ok = 0;
+	      pnearness.Set(hpi, minn+1);
+	    }
+	  hpi = hline.I2();
+	  if (pnearness.Get(hpi) > minn+1)
+	    {
+	      ok = 0;
+	      pnearness.Set(hpi, minn+1);
+	    }
+	}
+    }
+  while (!ok);
+  
+  for (i = 1; i <= maxlegalline /* lnearness.Size() */; i++)
+    {
+      lnearness.Set(i, 0);
+      for (j = 1; j <= 2; j++)
+	lnearness.Elem(i) += pnearness.Get(llines.Get(i).I(j));
+    }
+
+
+  for (ri = 1; ri <= rules.Size(); ri++)
+    {
+      netrule * rule = rules.Get(ri);
+
+      if (loctestmode)
+	(*testout) << "Rule " << rule->Name() << endl;
+
+      if (rule->GetQuality() > tolerance) continue;
+
+      pmap.SetSize (rule->GetNP());
+      lmap.SetSize (rule->GetNL());
+      
+      lused = 0;
+      pused = 0;
+      pmap = 0;
+      lmap = 0;
+
+      lused[1] = 1;   // .Set (1, 1);
+      lmap[1] = 1;    // .Set (1, 1);
+
+      for (j = 0; j < 2; j++)
+	{
+          pmap.Elem(rule->GetLine(1)[j]) = llines[0][j];
+          pused.Elem(llines[0][j])++;
+	}
+
+
+      nlok = 2;
+
+      while (nlok >= 2)
+	{
+
+	  if (nlok <= rule->GetNOldL())
+
+	    {
+	      ok = 0;
+	      while (!ok && lmap.Get(nlok) < maxlegalline  /* llines.Size() */)
+		{
+		  lmap.Elem(nlok)++;
+		  locli = lmap.Get(nlok);
+
+		  if (!lused.Get(locli) && 
+		      lnearness.Get(locli) <= rule->GetLNearness (nlok) )
+		    {
+		      ok = 1;
+
+		      loclin = llines.Get(locli);
+                      linevec = lpoints.Get(loclin.I2()) - lpoints.Get(loclin.I1());
+
+		      if (rule->CalcLineError (nlok, linevec) > maxerr)
+			{
+			  ok = 0;
+			  if(loctestmode)
+			    (*testout) << "not ok pos1" << endl;
+			}
+
+		      for (j = 0; j < 2 && ok; j++)
+			{
+			  // refpi = rule->GetPointNr (nlok, j);
+                          refpi = rule->GetLine(nlok)[j];
+
+			  if (pmap.Get(refpi) != 0)
+			    {
+			      if (pmap.Get(refpi) != loclin[j])
+				{
+				  ok = 0;
+				  if(loctestmode)
+				    (*testout) << "not ok pos2" << endl;
+				}
+			    }
+			  else
+			    {
+			      if (rule->CalcPointDist (refpi, lpoints.Get(loclin[j])) > maxerr
+				  || !legalpoints.Get(loclin[j])
+				  || pused.Get(loclin[j]))
+				{
+				  ok = 0;
+				  if(loctestmode)
+				    {
+				      (*testout) << "nok pos3" << endl;
+				      //if(rule->CalcPointDist (refpi, lpoints.Get(loclin[j])) > maxerr)
+				      //(*testout) << "r1" << endl;
+				      //if(!legalpoints.Get(loclin[j]))
+				      //(*testout) << "r2 legalpoints " << legalpoints << " loclin " << loclin << " j " << j << endl;
+				      //if(pused.Get(loclin[j]))
+				      //(*testout) << "r3" << endl;
+				    }
+				}
+			    }
+			}
+		    }
+		}
+
+	      if (ok)
+		{
+		  lused.Elem (locli) = 1;
+		  for (j = 0; j < 2; j++)
+		    {
+		      pmap.Set(rule->GetLine (nlok)[j], loclin[j]);
+		      pused.Elem(loclin[j])++;
+		    }
+
+		  nlok++;
+		}
+	      else
+		{
+		  lmap.Elem(nlok) = 0;
+		  nlok--;
+
+		  lused.Elem (lmap.Get(nlok)) = 0;
+		  for (j = 0; j < 2; j++)
+		    {
+		      pused.Elem(llines.Get(lmap.Get(nlok))[j]) --;
+		      if (! pused.Get (llines.Get (lmap.Get (nlok))[j]))
+			pmap.Set (rule->GetLine (nlok)[j], 0);
+		    }
+		}
+	    }
+
+	  else
+
+	    {
+
+	      // all lines are mapped !!
+
+	      // map also all points:
+
+	      npok = 1;
+	      incnpok = 1;
+
+	      pfixed.SetSize (pmap.Size());
+	      for (i = 0; i < pmap.Size(); i++)
+		pfixed[i] = (pmap[i] >= 1);
+
+	      while (npok >= 1)
+		{
+
+		  if (npok <= rule->GetNOldP())
+
+		    {
+		      if (pfixed.Get(npok))
+
+			{
+			  if (incnpok)
+			    npok++;
+			  else
+			    npok--;
+			}
+
+		      else
+
+			{
+			  ok = 0;
+
+			  if (pmap.Get(npok))
+			    pused.Elem(pmap.Get(npok))--;
+
+			  while (!ok && pmap.Get(npok) < maxlegalpoint)
+			    {
+			      ok = 1;
+
+			      pmap.Elem(npok)++;
+
+			      if (pused.Get(pmap.Get(npok)))
+				{
+				  ok = 0;
+				}
+			      else
+				{
+				  if (rule->CalcPointDist (npok, lpoints.Get(pmap.Get(npok))) > maxerr 
+				      || !legalpoints.Get(pmap.Get(npok))) 
+                                    
+                                    ok = 0;
+				}
+			    }
+
+			  if (ok)
+			    {
+			      pused.Elem(pmap.Get(npok))++;
+			      npok++;
+			      incnpok = 1;
+			    }
+
+			  else
+
+			    {
+			      pmap.Elem(npok) = 0;
+			      npok--;
+			      incnpok = 0;
+			    }
+			}
+		    }
+
+		  else
+
+		    {
+		      if (ok)
+			foundmap.Elem(ri)++; 
+
+		      if (loctestmode)
+			(*testout) << "lines and points mapped" << endl;
+
+
+		      ok = 1;
+
+		      // check orientations
+
+		      for (i = 1; i <= rule->GetNOrientations() && ok; i++)
+			{
+			  if (CW (lpoints.Get(pmap.Get(rule->GetOrientation(i).i1)),
+				  lpoints.Get(pmap.Get(rule->GetOrientation(i).i2)),
+				  lpoints.Get(pmap.Get(rule->GetOrientation(i).i3))) )
+			    {
+			      ok = 0;
+			      if (loctestmode)
+				(*testout) << "Orientation " << i << " not ok" << endl;
+			    }
+			}
+
+		      if (ok)
+			{
+			  oldu.SetSize (2 * rule->GetNOldP());
+			  
+			  for (i = 1; i <= rule->GetNOldP(); i++)
+			    {
+			      Vec2d ui(rule->GetPoint(i), lpoints.Get(pmap.Get(i)));
+			      oldu.Set (2*i-1, ui.X());
+			      oldu.Set (2*i  , ui.Y());
+			    }
+			  
+			  rule -> SetFreeZoneTransformation (oldu, tolerance);
+			}
+		      
+
+		      if (ok && !rule->ConvexFreeZone())
+			{
+			  ok = 0;
+			  if (loctestmode) 
+			    (*testout) << "freezone not convex" << endl;
+
+			  /*
+			  static int cnt = 0;
+			  cnt++;
+			  if (cnt % 100 == 0)
+			    {
+			      cout << "freezone not convex, cnt = " << cnt << "; rule = " << rule->Name() << endl;
+			      (*testout) << "freezone not convex, cnt = " << cnt << "; rule = " << rule->Name() << endl;
+			      (*testout) << "tol = " << tolerance << endl;
+			      (*testout) << "maxerr = " << maxerr << "; minerr = " << minelerr << endl;
+			      (*testout) << "freezone = " << rule->GetTransFreeZone() << endl;
+			    }
+			  */
+			}
+
+		      // check freezone:
+
+		      for (i = 1; i <= maxlegalpoint && ok; i++)
+			{
+			  if ( !pused.Get(i) &&
+			       rule->IsInFreeZone (lpoints.Get(i)) )
+			    {
+			      ok = 0;
+			      if (loctestmode)
+				(*testout) << "Point " << i << " in freezone" << endl;
+			    }
+			}
+
+
+		      for (i = maxlegalpoint+1; i <= lpoints.Size() && ok; i++)
+			{
+			  if ( rule->IsInFreeZone (lpoints.Get(i)) )
+			    {
+			      ok = 0;
+			      if (loctestmode)
+				(*testout) << "Point " << i << " in freezone" << endl;
+			    }
+			}
+
+		      for (i = 1; i <= maxlegalline && ok; i++)
+			{
+			  if (!lused.Get(i) && 
+			      rule->IsLineInFreeZone (lpoints.Get(llines.Get(i).I1()),
+						      lpoints.Get(llines.Get(i).I2())))
+			    {
+			      ok = 0;
+			      if (loctestmode)
+				(*testout) << "line " << llines.Get(i).I1() << "-"
+					   << llines.Get(i).I2() << " in freezone" << endl;
+			    }
+			}
+		      for (i = maxlegalline+1; i <= llines.Size() && ok; i++)
+			{
+			  if (rule->IsLineInFreeZone (lpoints.Get(llines.Get(i).I1()),
+						      lpoints.Get(llines.Get(i).I2())))
+			    {
+			      ok = 0;
+			      if (loctestmode)
+				(*testout) << "line " << llines.Get(i).I1() << "-"
+					   << llines.Get(i).I2() << " in freezone" << endl;
+			    }
+			}
+
+
+		      /*
+		      // check orientations
+
+		      for (i = 1; i <= rule->GetNOrientations() && ok; i++)
+			{
+			  if (CW (lpoints.Get(pmap.Get(rule->GetOrientation(i).i1)),
+				  lpoints.Get(pmap.Get(rule->GetOrientation(i).i2)),
+				  lpoints.Get(pmap.Get(rule->GetOrientation(i).i3))) )
+			    {
+			      ok = 0;
+			      if (loctestmode)
+				(*testout) << "Orientation " << i << " not ok" << endl;
+			    }
+			}
+		      */
+
+
+		      if (ok)
+			{
+			  if (loctestmode)
+			    (*testout) << "rule ok" << endl;
+
+			  //			  newu = rule->GetOldUToNewU() * oldu;
+			  if (rule->GetNOldP() < rule->GetNP())
+			    {
+			      newu.SetSize (rule->GetOldUToNewU().Height());
+			      rule->GetOldUToNewU().Mult (oldu, newu);
+			    }
+
+			  // Setze neue Punkte:
+
+			  oldnp = rule->GetNOldP();
+
+			  for (i = oldnp + 1; i <= rule->GetNP(); i++)
+			    {
+			      np = rule->GetPoint(i);
+			      np.X() += newu.Elem (2 * (i-oldnp) - 1);
+			      np.Y() += newu.Elem (2 * (i-oldnp));
+
+			      pmap.Elem(i) = lpoints.Append (np);
+			    }
+
+			  // Setze neue Linien:
+
+			  for (i = rule->GetNOldL() + 1; i <= rule->GetNL(); i++)
+			    {
+			      llines.Append (INDEX_2 (pmap.Get(rule->GetLine (i)[0]),
+						      pmap.Get(rule->GetLine (i)[1])));
+			    }
+
+
+			  // delete old lines:
+                          for (i = 1; i <= rule->GetNDelL(); i++)
+                            dellines.Append (lmap.Get(rule->GetDelLine(i)));
+
+                          // dellines.Append (lmap[rule->GetDelLines()]);
+                          // lmap[rule->GetDelLines()];
+
+
+			  // insert new elements:
+
+			  for (i = 1; i <= rule->GetNE(); i++)
+			    {
+			      elements.Append (rule->GetElement(i));
+			      for (j = 1; j <= elements.Get(i).GetNP(); j++)
+				elements.Elem(i).PNum(j) = pmap.Get(elements.Get(i).PNum(j));
+			    }
+
+
+			  elerr = 0;
+			  for (i = 1; i <= elements.Size(); i++)
+			    {
+			      if (!mparam.quad)
+				hf = CalcElementBadness (lpoints, elements.Get(i));
+			      else
+				hf = elements.Get(i).CalcJacobianBadness (lpoints) * 5;
+			      if (loctestmode)
+				(*testout) << "r " << rule->Name() << "bad = " << hf << endl;
+			      if (hf > elerr) elerr = hf;
+			    }
+
+			  if (loctestmode)
+			    (*testout) << "error = " << elerr;
+
+
+			  canuse.Elem(ri) ++;
+
+			  if (elerr < 0.99*minelerr)
+			    {
+
+			      if (loctestmode)
+				{
+				  (*testout) << "rule = " << rule->Name() << endl;
+				  (*testout) << "class = " << tolerance << endl;
+				  (*testout) << "lpoints: " << endl;
+				  for (i = 1; i <= lpoints.Size(); i++)
+				    (*testout) << lpoints.Get(i) << endl;
+				  (*testout) << "llines: " << endl;
+				  for (i = 1; i <= llines.Size(); i++)
+				    (*testout) << llines.Get(i).I1() << " " << llines.Get(i).I2() << endl;
+
+				  (*testout) << "Freezone: ";
+				  for (i = 1; i <= rule -> GetTransFreeZone().Size(); i++)
+				    (*testout) << rule->GetTransFreeZone().Get(i) << endl;
+				}
+
+
+			      minelerr = elerr;
+			      found = ri;
+
+                              tempnewpoints = lpoints.Range (noldlp, lpoints.Size());
+                              tempnewlines = llines.Range (noldll, llines.Size());
+                              tempdellines = dellines;
+                              tempelements = elements;
+			    }
+
+			  lpoints.SetSize (noldlp);
+			  llines.SetSize (noldll);
+			  dellines.SetSize (0);
+			  elements.SetSize (0);
+			  ok = 0;
+			}
+
+		      npok = rule->GetNOldP();
+		      incnpok = 0;
+		    }
+		}
+
+	      nlok = rule->GetNOldL();
+
+	      lused.Set (lmap.Get(nlok), 0);
+
+	      for (j = 1; j <= 2; j++)
+		{
+		  refpi = rule->GetPointNr (nlok, j);
+		  pused.Elem(pmap.Get(refpi))--;
+
+		  if (pused.Get(pmap.Get(refpi)) == 0)
+                    pmap.Set(refpi, 0);
+		}
+	    }
+	}
+    }
+
+
+  if (found)
+    {
+      lpoints.Append (tempnewpoints);
+      llines.Append (tempnewlines);
+      dellines.Append (tempdellines);
+      elements.Append (tempelements);
+    }
+
+
+  return found;
+}
+
+
+
+
+
+}
diff --git a/contrib/Netgen/libsrc/meshing/ruler2.hpp b/contrib/Netgen/libsrc/meshing/ruler2.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..696bafa94d8b2f6d476c4f8c1f1f3ca859c7696e
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/ruler2.hpp
@@ -0,0 +1,167 @@
+#ifndef FILE_NETRULE
+#define FILE_NETRULE
+
+///
+class netrule
+{
+private:
+  ///
+  typedef struct tf 
+  { float f1, f2, f3; }   threefloat;
+  
+  class threeint 
+  { 
+  public: int i1, i2, i3; 
+    threeint() { } 
+    threeint(int ai1, int ai2, int ai3) 
+    { i1 = ai1; i2 = ai2; i3 = ai3; } 
+  };
+
+
+  ///
+  int quality;
+  ///
+  char * name;
+  ///
+  ARRAY<Point2d> points;
+  ///
+  ARRAY<INDEX_2> lines;
+  ///
+  ARRAY<Point2d> freezone, freezonelimit;
+  ///
+  ARRAY<Point2d> transfreezone;
+
+  ///
+  ARRAY<int> dellines;
+  ///
+  ARRAY<Element2d> elements;
+  ///
+  ARRAY<threefloat> tolerances, linetolerances;
+  ///
+  ARRAY<threeint> orientations;
+  ///
+  DenseMatrix oldutonewu, oldutofreearea, oldutofreearealimit;
+  ///
+  ARRAY<DenseMatrix*> oldutofreearea_i;
+  ///
+  MatrixFixWidth<3> freesetinequ;
+
+  ///
+  ARRAY<Vec2d> linevecs;
+
+  ///
+  int noldp, noldl;
+  ///
+  float fzminx, fzmaxx, fzminy, fzmaxy;
+
+  /// topological distance of line to base element
+  ARRAY<int> lnearness;
+
+public:
+
+  ///
+  netrule ();
+  ///
+  ~netrule();
+
+  ///
+  int GetNP () const { return points.Size(); }
+  ///
+  int GetNL () const { return lines.Size(); }
+  ///
+  int GetNE () const { return elements.Size(); }
+  ///
+  int GetNOldP () const { return noldp; }
+  ///
+  int GetNOldL () const { return noldl; }
+  ///
+  int GetNDelL () const { return dellines.Size(); }
+  ///
+  int GetNOrientations () const { return orientations.Size(); }
+  ///
+  int GetQuality () const { return quality; }
+  ///
+  int GetLNearness (int li) const { return lnearness.Get(li); }
+
+  ///
+  const Point2d & GetPoint (int i) const { return points.Get(i); }
+  ///
+  const INDEX_2 & GetLine (int i) const { return lines.Get(i); }
+  ///
+  const Element2d & GetElement (int i) const { return elements.Get(i); }
+  ///
+  const threeint & GetOrientation (int i) const { return orientations.Get(i); }
+  ///
+  int GetDelLine (int i) const { return dellines.Get(i); }
+  ///
+  const ARRAY<int> & GetDelLines() const { return dellines; }
+  ///
+  void GetFreeZone (ARRAY<Point2d> & afreearea);
+  ///
+
+  double CalcPointDist (int pi, const Point2d & p) const
+  {
+    double dx = p.X() - points.Get(pi).X();
+    double dy = p.Y() - points.Get(pi).Y();
+    const threefloat * tfp = &tolerances.Get(pi);
+    return tfp->f1 * dx * dx + tfp->f2 * dx * dy + tfp->f3 * dy * dy;
+  }
+
+  ///
+  float CalcLineError (int li, const Vec2d & v) const;
+
+  ///
+  void SetFreeZoneTransformation (const Vector & u, int tolclass);
+
+  ///
+  bool IsInFreeZone (const Point2d & p) const
+  {
+    if (p.X() < fzminx || p.X() > fzmaxx ||
+	p.Y() < fzminy || p.Y() > fzmaxy) return 0;
+
+    for (int i = 0; i < transfreezone.Size(); i++)
+      {
+	if (freesetinequ(i, 0) * p.X() + 
+	    freesetinequ(i, 1) * p.Y() +
+	    freesetinequ(i, 2) > 0) return 0;
+      }
+    return 1;
+  }
+
+  ///
+  int IsLineInFreeZone (const Point2d & p1, const Point2d & p2) const
+  {
+    if (p1.X() > fzmaxx && p2.X() > fzmaxx ||
+	p1.X() < fzminx && p2.X() < fzminx ||
+	p1.Y() > fzmaxy && p2.Y() > fzmaxy ||
+	p1.Y() < fzminy && p2.Y() < fzminy) return 0;
+    return IsLineInFreeZone2 (p1, p2);
+  }
+  ///
+  int IsLineInFreeZone2 (const Point2d & p1, const Point2d & p2) const;
+  ///
+  int ConvexFreeZone () const;
+  ///
+  const ARRAY<Point2d> & GetTransFreeZone () { return transfreezone; }
+
+  ///
+  int GetPointNr (int ln, int endp) const { return lines.Get(ln).I(endp); }
+
+  ///
+  const DenseMatrix & GetOldUToNewU () const { return oldutonewu; }
+  ///
+  const DenseMatrix & GetOldUToFreeArea () const { return oldutofreearea; }
+  ///
+  const char * Name () const { return name; }
+
+  ///
+  void LoadRule (istream & ist);
+};
+
+
+
+/** Draws 2D rules.
+    Visual testing of 2D meshing rules */
+extern void DrawRules ();
+#endif
+
diff --git a/contrib/Netgen/libsrc/meshing/ruler3.cpp b/contrib/Netgen/libsrc/meshing/ruler3.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..30a812bcca770edb1125ce34dcc9ec18a1139766
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/ruler3.cpp
@@ -0,0 +1,1137 @@
+#include <mystdlib.h>
+#include "meshing.hpp"
+
+
+namespace netgen
+{
+extern double minother;
+extern double minwithoutother;
+
+
+static double CalcElementBadness (const ARRAY<Point3d> & points,
+				  const Element & elem)
+{
+  double vol, l, l4, l5, l6;
+  if (elem.GetNP() != 4) 
+    {
+      if (elem.GetNP() == 5)
+	{
+	  double z = points.Get(elem.PNum(5)).Z();
+	  if (z > -1e-8) return 1e8;
+	  return (-1 / z) - z; //  - 2;
+	}
+      return 0;
+    }
+  
+  Vec3d v1 = points.Get(elem.PNum(2)) - points.Get(elem.PNum(1));
+  Vec3d v2 = points.Get(elem.PNum(3)) - points.Get(elem.PNum(1));
+  Vec3d v3 = points.Get(elem.PNum(4)) - points.Get(elem.PNum(1));
+  
+  vol = - (Cross (v1, v2) * v3);
+  l4 = Dist (points.Get(elem.PNum(2)), points.Get(elem.PNum(3)));
+  l5 = Dist (points.Get(elem.PNum(2)), points.Get(elem.PNum(4)));
+  l6 = Dist (points.Get(elem.PNum(3)), points.Get(elem.PNum(4)));
+
+  l = v1.Length() + v2.Length() + v3.Length() + l4 + l5 + l6;
+  
+  //  testout << "vol = " << vol << " l = " << l << endl;
+  if (vol < 1e-8) return 1e10;
+  //  (*testout) << "l^3/vol = " << (l*l*l / vol) << endl;
+  
+  double err = pow (l*l*l/vol, 1.0/3.0) / 12;
+  return err;
+}
+
+
+
+
+
+
+int Meshing3 :: ApplyRules 
+(
+ ARRAY<Point3d> & lpoints,     // in: local points, out: old+new local points
+ ARRAY<int> & allowpoint,      // in: 2 .. it is allowed to use pointi, 1..will be allowed later, 0..no means
+ ARRAY<MiniElement2d> & lfaces,    // in: local faces, out: old+new local faces
+ INDEX lfacesplit,	       // for local faces in outer radius
+ INDEX_2_HASHTABLE<int> & connectedpairs,  // connected pairs for prism-meshing
+ ARRAY<Element> & elements,    // out: new elements
+ ARRAY<INDEX> & delfaces,      // out: face indices of faces to delete
+ int tolerance,                // quality class: 1 best 
+ double sloppy,                // quality strength
+ int rotind1,                  // how to rotate base element
+ float & retminerr             // element error 
+ )
+
+{
+  NgProfiler::RegionTimer regtot(97);
+
+  int i, j, k, ri, nfok, npok, incnpok, refpi, locpi, locfi, locfr;
+  float hf, err, minerr, teterr, minteterr;
+  char ok, found, hc;
+  vnetrule * rule;
+  Vector oldu, newu, newu1, newu2, allp;
+  Vec3d ui;
+  Point3d np;
+  int oldnp, noldlp, noldlf;
+  const MiniElement2d * locface = NULL;
+  int loktestmode;
+
+
+  static ARRAY<int> pused;        // point is already mapped
+  static ARRAY<char> fused;       // face is already mapped
+  static ARRAY<int> pmap;         // map of reference point to local point
+  static ARRAY<char> pfixed;      // point mapped by face-map
+  static ARRAY<int> fmapi;        // face in reference is mapped to face nr ...
+  static ARRAY<int> fmapr;        // face in reference is rotated to map 
+  static ARRAY<Point3d> transfreezone;  // transformed free-zone
+  static int cnt = 0;
+  static INDEX_2_CLOSED_HASHTABLE<int> ledges(100); // edges in local environment
+  
+  static ARRAY<Point3d> tempnewpoints;
+  static ARRAY<MiniElement2d> tempnewfaces;
+  static ARRAY<int> tempdelfaces;
+  static ARRAY<Element> tempelements;
+  static ARRAY<Box3d> triboxes;         // bounding boxes of local faces
+
+
+  static ARRAY<int, PointIndex::BASE> pnearness;
+  static ARRAY<int> fnearness;
+
+  cnt++;
+  
+  delfaces.SetSize (0);
+  elements.SetSize (0);
+
+  // determine topological distance of faces and points to
+  // base element
+
+  pnearness.SetSize (lpoints.Size());
+  fnearness.SetSize (lfacesplit);
+
+  pnearness = INT_MAX/10;
+  for (j = 0; j < lfaces[0].GetNP(); j++)
+    pnearness[lfaces[0][j]] = 0;
+
+  NgProfiler::RegionTimer reg2(98);
+  
+  NgProfiler::StartTimer (90);
+
+  for (int loop = 0; loop < 2; loop++)
+    {
+
+      for (i = 0; i < lfacesplit; i++)
+	{
+	  const MiniElement2d & hface = lfaces[i];
+
+	  int minn = INT_MAX-1;
+	  for (j = 0; j < hface.GetNP(); j++)
+	    {
+	      int hi = pnearness[hface[j]];
+	      if (hi < minn) minn = hi;
+	    }
+	  if (minn < INT_MAX/10)
+	    for (j = 0; j < hface.GetNP(); j++)
+	      if (pnearness[hface[j]] > minn+1)
+		pnearness[hface[j]] = minn+1;
+	}
+
+      for (i = 1; i <= connectedpairs.GetNBags(); i++)
+	for (j = 1; j <= connectedpairs.GetBagSize(i); j++)
+	  {
+	    INDEX_2 edge;
+	    int val;
+	    connectedpairs.GetData (i, j, edge, val);
+
+	    if (pnearness[edge.I1()] > pnearness[edge.I2()] + 1)
+	      pnearness[edge.I1()] = pnearness[edge.I2()] + 1;
+
+	    if (pnearness[edge.I2()] > pnearness[edge.I1()] + 1)
+	      pnearness[edge.I2()] = pnearness[edge.I1()] + 1;
+	  }
+
+    }
+
+  for (i = 0; i < fnearness.Size(); i++)
+    {
+      int sum = 0;
+      for (j = 0; j < lfaces[i].GetNP(); j++)
+	sum += pnearness[lfaces[i][j]];
+      fnearness[i] = sum;
+    }
+
+  
+  NgProfiler::StopTimer (90);
+  NgProfiler::StartTimer (91);
+
+  // find bounding boxes of faces
+
+  triboxes.SetSize (lfaces.Size());
+  for (i = 0; i < lfaces.Size(); i++)
+    {
+      const MiniElement2d & face = lfaces[i];
+      triboxes[i].SetPoint (lpoints.Get(face[0]));
+      for (j = 1; j < face.GetNP(); j++)
+	triboxes[i].AddPoint (lpoints.Get(face[j]));
+    }
+
+  NgProfiler::StopTimer (91);
+  NgProfiler::StartTimer (92);
+
+  
+  bool useedges = 0;
+  for (ri = 0; ri < rules.Size(); ri++)
+    if (rules[ri]->GetNEd()) useedges = 1;
+
+  if (useedges)
+    {
+      ledges.SetSize (5 * lfacesplit);
+      
+      for (j = 0; j < lfacesplit; j++)
+	// if (fnearness[j] <= 5) 
+	  {
+	    const MiniElement2d & face = lfaces[j];
+	    int newp, oldp;
+	    
+	    newp = face[face.GetNP()-1];
+	    for (k = 0; k < face.GetNP(); k++)
+	      {
+		oldp = newp;
+		newp = face[k];
+		ledges.Set (INDEX_2::Sort(oldp, newp), 1);
+	      }
+	  }
+    }
+
+  NgProfiler::StopTimer (92);
+
+  NgProfiler::RegionTimer reg3(99);
+
+  pused.SetSize (lpoints.Size());
+  fused.SetSize (lfaces.Size());
+
+  found = 0;
+  minerr = tolfak * tolerance * tolerance;
+  minteterr = sloppy * tolerance;
+
+  if (testmode)
+    (*testout) << "cnt = " << cnt << " class = " << tolerance << endl;
+
+
+
+  // impossible, if no rule can be applied at any tolerance class
+  bool impossible = 1;
+
+
+  // check each rule:
+
+  for (ri = 1; ri <= rules.Size(); ri++)
+    { 
+      int base = (lfaces[0].GetNP() == 3) ? 100 : 200;
+      NgProfiler::RegionTimer regx1(base);
+      NgProfiler::RegionTimer regx(base+ri);
+
+      sprintf (problems.Elem(ri), "");
+
+      rule = rules.Get(ri);
+      
+      if (rule->GetNP(1) != lfaces[0].GetNP())
+	continue;
+
+      if (rule->GetQuality() > tolerance)
+	{
+	  if (rule->GetQuality() < 100) impossible = 0;
+
+	  if (testmode)
+	    sprintf (problems.Elem(ri), "Quality not ok");
+	  continue;
+	}
+      
+      if (testmode)
+	sprintf (problems.Elem(ri), "no mapping found");
+      
+      loktestmode = testmode || rule->TestFlag ('t') || tolerance > 5;
+
+      if (loktestmode)
+	(*testout) << "Rule " << ri << " = " << rule->Name() << endl;
+      
+      pmap.SetSize (rule->GetNP());
+      fmapi.SetSize (rule->GetNF());
+      fmapr.SetSize (rule->GetNF());
+      
+      fused = 0;
+      pused = 0;
+      pmap = 0;
+      fmapi = 0;
+      for (i = 1; i <= fmapr.Size(); i++)
+	fmapr.Set(i, rule->GetNP(i));
+      
+      fused[0] = 1;
+      fmapi[0] = 1;
+      fmapr[0] = rotind1;
+
+      
+      for (j = 1; j <= lfaces.Get(1).GetNP(); j++)
+	{
+	  locpi = lfaces[0].PNumMod (j+rotind1);
+	  pmap.Set (rule->GetPointNr (1, j), locpi);
+	  pused.Elem(locpi)++;
+	}
+
+      /*
+	map all faces
+	nfok .. first nfok-1 faces are mapped properly
+	*/
+
+      nfok = 2;
+      NgProfiler::RegionTimer regfa(300);
+      NgProfiler::RegionTimer regx2(base+50+ri);
+      while (nfok >= 2)
+	{
+	  
+	  if (nfok <= rule->GetNOldF())
+	    {
+	      // not all faces mapped
+
+	      ok = 0;
+	      locfi = fmapi.Get(nfok);
+	      locfr = fmapr.Get(nfok);
+
+	      int actfnp = rule->GetNP(nfok);
+
+	      while (!ok)
+		{
+		  locfr++;
+		  if (locfr == actfnp + 1)
+		    {
+		      locfr = 1;
+		      locfi++;
+		      if (locfi > lfacesplit) break;
+		    }
+		  
+		  
+		  if (fnearness.Get(locfi) > rule->GetFNearness (nfok) ||
+		      fused.Get(locfi) ||
+		      actfnp != lfaces.Get(locfi).GetNP() )
+		    {
+		      // face not feasible in any rotation
+
+		      locfr = actfnp;
+		    }
+		  else
+		    {
+		      
+		      ok = 1;
+		      
+		      locface = &lfaces.Get(locfi);
+
+		      
+		      // reference point already mapped differently ?
+		      for (j = 1; j <= actfnp && ok; j++)
+			{
+			  locpi = pmap.Get(rule->GetPointNr (nfok, j));
+			  
+			  if (locpi && locpi != locface->PNumMod(j+locfr))
+			    ok = 0;
+			}
+		      
+		      // local point already used or point outside tolerance ?
+		      for (j = 1; j <= actfnp && ok; j++)
+			{
+			  refpi = rule->GetPointNr (nfok, j);
+			  
+			  if (pmap.Get(refpi) == 0)
+			    {
+			      locpi = locface->PNumMod (j + locfr);
+
+			      if (pused.Get(locpi))
+				ok = 0;
+			      else
+				{
+				  const Point3d & lp = lpoints.Get(locpi);
+				  const Point3d & rp = rule->GetPoint(refpi);
+
+				  if ( Dist2 (lp, rp) * rule->PointDistFactor(refpi) > minerr)
+				    {
+				      impossible = 0;
+				      ok = 0;
+				    }
+				}
+			    }
+			}
+		    }
+		}
+	      
+	      
+	      if (ok)
+		{
+		  // map face nfok
+
+		  fmapi.Set (nfok, locfi);
+		  fmapr.Set (nfok, locfr);
+		  fused.Set (locfi, 1);
+		  
+		  for (j = 1; j <= rule->GetNP (nfok); j++)
+		    {
+		      locpi = locface->PNumMod(j+locfr);
+		      
+		      if (rule->GetPointNr (nfok, j) <= 3 &&
+			  pmap.Get(rule->GetPointNr(nfok, j)) != locpi)
+			(*testout) << "change face1 point, mark1" << endl;
+		      
+		      pmap.Set(rule->GetPointNr (nfok, j), locpi);
+		      pused.Elem(locpi)++;
+		    }
+		  
+		  nfok++;
+		}
+	      else
+		{
+		  // backtrack one face
+		  fmapi.Set (nfok, 0);
+		  fmapr.Set (nfok, rule->GetNP(nfok));
+		  nfok--;
+		  
+		  fused.Set (fmapi.Get(nfok), 0);
+		  for (j = 1; j <= rule->GetNP (nfok); j++)
+		    {
+		      refpi = rule->GetPointNr (nfok, j);
+		      pused.Elem(pmap.Get(refpi))--;
+		      
+		      if (pused.Get(pmap.Get(refpi)) == 0)
+			{
+			  pmap.Set(refpi, 0);
+			}
+		    }
+		}
+	    }
+	  
+	  else
+	    
+	    { 
+	      NgProfiler::RegionTimer regfb(301);
+
+	      // all faces are mapped
+	      // now map all isolated points:
+	      
+	      if (loktestmode)
+		{
+		  (*testout) << "Faces Ok" << endl;
+		  sprintf (problems.Elem(ri), "Faces Ok");
+		}
+	      
+	      npok = 1;
+	      incnpok = 1;
+	      
+	      pfixed.SetSize (pmap.Size());
+	      for (i = 1; i <= pmap.Size(); i++)
+		pfixed.Set(i, (pmap.Get(i) != 0) );
+	      
+	      while (npok >= 1)
+		{
+		  
+		  if (npok <= rule->GetNOldP())
+		    {
+		      
+		      if (pfixed.Get(npok))
+			
+			{
+			  if (incnpok)
+			    npok++;
+			  else
+			    npok--;
+			}
+		      
+		      else
+			
+			{
+			  locpi = pmap.Elem(npok);
+			  ok = 0;
+			  
+			  if (locpi)
+			    pused.Elem(locpi)--;
+			  
+			  while (!ok && locpi < lpoints.Size())
+			    {
+			      ok = 1;
+			      locpi++;
+			      
+			      if (pused.Get(locpi) || 
+				  pnearness.Get(locpi) > rule->GetPNearness(npok))
+				{
+				  ok = 0;
+				}
+			      else if (allowpoint.Get(locpi) != 2)
+				{
+				  ok = 0;
+				  if (allowpoint.Get(locpi) == 1)
+				    impossible = 0;
+				}
+			      else
+				{
+				  const Point3d & lp = lpoints.Get(locpi);
+				  const Point3d & rp = rule->GetPoint(npok);
+
+				  if ( Dist2 (lp, rp) * rule->PointDistFactor(npok) > minerr)
+				    {
+				      ok = 0;
+				      impossible = 0;
+				    }
+				}
+			    }
+			  
+			  
+			  if (ok)
+			    {
+			      pmap.Set (npok, locpi);
+			      
+			      if (npok <= 3)
+				(*testout) << "set face1 point, mark3" << endl;
+			      
+			      pused.Elem(locpi)++;
+			      npok++;
+			      incnpok = 1;
+			    }
+			  
+			  else
+			    
+			    {
+			      pmap.Set (npok, 0);
+			      
+			      if (npok <= 3)
+				(*testout) << "set face1 point, mark4" << endl;
+			      
+			      npok--;
+			      incnpok = 0;
+			    }
+			}
+		    }
+		  
+		  else
+		    
+		    {
+		      NgProfiler::RegionTimer regfa2(302);		      
+
+		      // all points are mapped
+		      
+		      if (loktestmode)
+			{
+			  (*testout) << "Mapping found!!: Rule " << rule->Name() << endl;
+			  for (i = 1; i <= pmap.Size(); i++)
+			    (*testout) << pmap.Get(i) << " ";
+			  (*testout) << endl;
+			  sprintf (problems.Elem(ri), "mapping found");
+			  (*testout) << rule->GetNP(1) << " = " << lfaces.Get(1).GetNP() << endl;
+			}
+		      
+		      ok = 1;
+		      
+		      
+		      // check mapedges:
+		      for (i = 1; i <= rule->GetNEd(); i++)
+			{
+			  INDEX_2 in2(pmap.Get(rule->GetEdge(i).i1),
+				      pmap.Get(rule->GetEdge(i).i2));
+			  in2.Sort();
+			  if (!ledges.Used (in2)) ok = 0;
+			}
+
+
+		      // check prism edges:
+		      for (i = 1; i <= rule->GetNE(); i++)
+			{
+			  const Element & el = rule->GetElement (i);
+			  if (el.GetType() == PRISM) 
+			    { 
+			      for (j = 1; j <= 3; j++)
+				{
+				  INDEX_2 in2(pmap.Get(el.PNum(j)),
+					      pmap.Get(el.PNum(j+3)));      
+				  in2.Sort();
+				  if (!connectedpairs.Used (in2)) ok = 0;
+				}
+			    }
+			  if (el.GetType() == PYRAMID) 
+			    { 
+			      if (loktestmode)
+				(*testout) << "map pyramid, rule = " << rule->Name() << endl;
+			      for (j = 1; j <= 2; j++)
+				{
+				  INDEX_2 in2;
+				  if (j == 1)
+				    {
+				      in2.I1() = pmap.Get(el.PNum(2));
+				      in2.I2() = pmap.Get(el.PNum(3));
+				    }
+				  else
+				    {
+				      in2.I1() = pmap.Get(el.PNum(1));
+				      in2.I2() = pmap.Get(el.PNum(4));
+				    }
+				  in2.Sort();
+				  if (!connectedpairs.Used (in2)) 
+				    {
+				      ok = 0;
+				      if (loktestmode)
+					(*testout) << "no pair" << endl;
+				    }
+				}
+			    }
+
+			}
+		      
+
+		      
+		      for (i = rule->GetNOldF() + 1; i <= rule->GetNF(); i++)
+			fmapi.Set(i, 0);
+		      
+
+		      if (ok)
+			{
+			  foundmap.Elem(ri)++;
+			}
+
+		      
+
+
+		      // deviation of existing points
+
+		      oldu.SetSize (3 * rule->GetNOldP());
+		      newu.SetSize (3 * (rule->GetNP() - rule->GetNOldP()));
+		      allp.SetSize (3 * rule->GetNP());
+		      
+		      for (i = 1; i <= rule->GetNOldP(); i++)
+			{
+			  const Point3d & lp = lpoints.Get(pmap.Get(i));
+			  const Point3d & rp = rule->GetPoint(i);
+			  oldu.Set (3*i-2, lp.X()-rp.X());
+			  oldu.Set (3*i-1, lp.Y()-rp.Y());
+			  oldu.Set (3*i  , lp.Z()-rp.Z());
+			  
+			  allp.Set (3*i-2, lp.X());
+			  allp.Set (3*i-1, lp.Y());
+			  allp.Set (3*i  , lp.Z());
+			}
+
+		      if (rule->GetNP() > rule->GetNOldP())
+			{
+			  newu.SetSize (rule->GetOldUToNewU().Height());
+			  rule->GetOldUToNewU().Mult (oldu, newu);
+			}
+
+		      //		      int idiff = 3 * (rule->GetNP()-rule->GetNOldP());
+		      int idiff = 3 * rule->GetNOldP();
+		      for (i = rule->GetNOldP()+1; i <= rule->GetNP(); i++)
+			{
+			  const Point3d & rp = rule->GetPoint(i);
+			  allp.Set (3*i-2, rp.X() + newu.Get(3*i-2 - idiff));
+			  allp.Set (3*i-1, rp.Y() + newu.Get(3*i-1 - idiff));
+			  allp.Set (3*i  , rp.Z() + newu.Get(3*i   - idiff));
+			}
+		      
+		      rule->SetFreeZoneTransformation (allp, 
+						       tolerance + int(sloppy));
+
+		      if (!rule->ConvexFreeZone())
+			{
+			  ok = 0;
+			  sprintf (problems.Elem(ri), "Freezone not convex");
+
+			  if (loktestmode)
+			    (*testout) << "Freezone not convex" << endl;
+			}
+
+		      if (loktestmode)
+			{
+			  const ARRAY<Point3d> & fz = rule->GetTransFreeZone();
+			  (*testout) << "Freezone: " << endl;
+			  for (i = 1; i <= fz.Size(); i++)
+			    (*testout) << fz.Get(i) << endl;
+			}
+		      
+
+		      // check freezone:
+		      
+		      for (i = 1; i <= lpoints.Size(); i++)
+			{
+			  if ( !pused.Get(i) )
+			    {
+			      const Point3d & lp = lpoints.Get(i);
+
+			      if (rule->fzbox.IsIn (lp))
+				{
+				  if (rule->IsInFreeZone(lp))
+				    {
+				      if (loktestmode)
+					{
+					  (*testout) << "Point " << i 
+						     << " in Freezone" << endl;
+					  sprintf (problems.Elem(ri), 
+						   "locpoint %d in Freezone", i);
+					}
+				      ok = 0;
+				      break;
+				    }
+				}
+			    }
+			}
+
+		      for (i = 1; i <= lfaces.Size() && ok; i++)
+			{
+			  static ARRAY<int> lpi(4);
+
+			  if (!fused.Get(i))
+			    { 
+			      int triin;
+			      const MiniElement2d & lfacei = lfaces.Get(i);
+
+			      if (!triboxes.Elem(i).Intersect (rule->fzbox))
+				triin = 0;
+			      else
+				{
+				  int li, lj;
+				  for (li = 1; li <= lfacei.GetNP(); li++)
+				    {
+				      int lpii = 0;
+				      int pi = lfacei.PNum(li);
+				      for (lj = 1; lj <= rule->GetNOldP(); lj++)
+					if (pmap.Get(lj) == pi)
+					  lpii = lj;
+				      lpi.Elem(li) = lpii;
+				    }
+
+
+				  if (lfacei.GetNP() == 3)
+				    {
+				      triin = rule->IsTriangleInFreeZone 
+					(
+					 lpoints.Get(lfacei.PNum(1)),
+					 lpoints.Get(lfacei.PNum(2)),
+					 lpoints.Get(lfacei.PNum(3)), lpi, 1
+					 );
+				    }
+				  else
+				    {
+				      triin = rule->IsQuadInFreeZone 
+					(
+					 lpoints.Get(lfacei.PNum(1)),
+					 lpoints.Get(lfacei.PNum(2)),
+					 lpoints.Get(lfacei.PNum(3)), 
+					 lpoints.Get(lfacei.PNum(4)), 
+					 lpi, 1
+					 );
+				    }
+				}
+
+
+			      if (triin == -1)
+				{
+				  ok = 0;
+				}
+			      
+			      if (triin == 1)
+				{
+#ifdef TEST_JS
+				  ok = 0;
+
+				  if (loktestmode)
+				    {
+				      (*testout) << "El with " << lfaces.Get(i).GetNP() << " points in freezone: "
+						 << lfaces.Get(i).PNum(1) << " - " 
+						 << lfaces.Get(i).PNum(2) << " - "
+						 << lfaces.Get(i).PNum(3) << " - "
+						 << lfaces.Get(i).PNum(4) << endl;
+				      for (int lj = 1; lj <= lfaces.Get(i).GetNP(); lj++)
+					(*testout) << lpoints.Get(lfaces.Get(i).PNum(lj)) << " ";
+
+				      (*testout) << endl;
+
+				      sprintf (problems.Elem(ri), "triangle (%d, %d, %d) in Freezone",
+					       lfaces.Get(i).PNum(1), lfaces.Get(i).PNum(2),
+					       lfaces.Get(i).PNum(3));
+				    }
+#else
+				  if (loktestmode)
+				    {
+				      if (lfacei.GetNP() == 3)
+					{
+					  (*testout) << "Triangle in freezone: "
+						     << lfacei.PNum(1) << " - " 
+						     << lfacei.PNum(2) << " - "
+						     << lfacei.PNum(3) 
+						     << ", or "
+						     << lpoints.Get(lfacei.PNum(1)) << " - " 
+						     << lpoints.Get(lfacei.PNum(2)) << " - "
+						     << lpoints.Get(lfacei.PNum(3)) 
+						     << endl;
+					  (*testout) << "lpi = " << lpi.Get(1) << ", " 
+						     << lpi.Get(2) << ", " << lpi.Get(3) << endl;
+					}
+				      else
+					  (*testout) << "Quad in freezone: "
+						     << lfacei.PNum(1) << " - " 
+						     << lfacei.PNum(2) << " - "
+						     << lfacei.PNum(3) << " - "
+						     << lfacei.PNum(4) 
+						     << ", or "
+						     << lpoints.Get(lfacei.PNum(1)) << " - " 
+						     << lpoints.Get(lfacei.PNum(2)) << " - "
+						     << lpoints.Get(lfacei.PNum(3)) << " - "
+						     << lpoints.Get(lfacei.PNum(4)) 
+						     << endl;
+
+				      sprintf (problems.Elem(ri), "triangle (%d, %d, %d) in Freezone",
+					       int(lfaces.Get(i).PNum(1)), 
+					       int(lfaces.Get(i).PNum(2)),
+					       int(lfaces.Get(i).PNum(3)));
+				    }	
+
+				  hc = 0;
+				  for (k = rule->GetNOldF() + 1; k <= rule->GetNF(); k++)
+				    {
+				      if (rule->GetPointNr(k, 1) <= rule->GetNOldP() &&
+					  rule->GetPointNr(k, 2) <= rule->GetNOldP() &&
+					  rule->GetPointNr(k, 3) <= rule->GetNOldP())
+					{
+					  for (j = 1; j <= 3; j++)
+					    if (lfaces.Get(i).PNumMod(j  ) == pmap.Get(rule->GetPointNr(k, 1)) &&
+						lfaces.Get(i).PNumMod(j+1) == pmap.Get(rule->GetPointNr(k, 3)) &&
+						lfaces.Get(i).PNumMod(j+2) == pmap.Get(rule->GetPointNr(k, 2)))
+					      {
+						fmapi.Elem(k) = i;
+						hc = 1;
+
+						
+ // 						(*testout) << "found from other side: " 
+//  							   << rule->Name() 
+//  							   << " ( " << pmap.Get (rule->GetPointNr(k, 1))
+//  							   << " - " << pmap.Get (rule->GetPointNr(k, 2))
+//  							   << " - " << pmap.Get (rule->GetPointNr(k, 3)) << " ) "
+//  							   << endl;
+
+						strcpy (problems.Elem(ri), "other");
+					      }
+					}
+				    }
+				  
+				  if (!hc)
+				    {
+				      if (loktestmode)
+					{
+					  (*testout) << "Triangle in freezone: "
+						     << lfaces.Get(i).PNum(1) << " - " 
+						     << lfaces.Get(i).PNum(2) << " - "
+						     << lfaces.Get(i).PNum(3) << endl;
+
+					  sprintf (problems.Elem(ri), "triangle (%d, %d, %d) in Freezone",
+						   int (lfaces.Get(i).PNum(1)), 
+						   int (lfaces.Get(i).PNum(2)),
+						   int (lfaces.Get(i).PNum(3)));
+					}
+				      ok = 0;
+				    }
+#endif
+				}
+			    }
+			   
+			}
+
+		      
+		      if (ok)
+			{
+			  err = 0;
+			  for (i = 1; i <= rule->GetNOldP(); i++)
+			    {
+			      hf = rule->CalcPointDist (i, lpoints.Get(pmap.Get(i)));
+			      if (hf > err) err = hf;
+			    }
+			  
+			  
+			  if (loktestmode)
+			    {
+			      (*testout) << "Rule ok" << endl;
+			      sprintf (problems.Elem(ri), "Rule ok, err = %f", err);
+			    }
+
+
+			  //			  newu = rule->GetOldUToNewU() * oldu;
+
+			  // set new points:
+			  
+			  oldnp = rule->GetNOldP();
+			  noldlp = lpoints.Size();
+			  noldlf = lfaces.Size();
+			  
+			  
+			  for (i = oldnp + 1; i <= rule->GetNP(); i++)
+			    {
+			      np = rule->GetPoint(i);
+			      np.X() += newu.Elem (3 * (i-oldnp) - 2);
+			      np.Y() += newu.Elem (3 * (i-oldnp) - 1);
+			      np.Z() += newu.Elem (3 * (i-oldnp));
+			      
+			      pmap.Elem(i) = lpoints.Append (np);
+			    }
+			  
+			  // Set new Faces:
+			  
+			  for (i = rule->GetNOldF() + 1; i <= rule->GetNF(); i++)
+			    if (!fmapi.Get(i))
+			      {
+				MiniElement2d nface(rule->GetNP(i));
+				for (j = 1; j <= nface.GetNP(); j++)
+				  nface.PNum(j) = pmap.Get(rule->GetPointNr (i, j));
+				
+				lfaces.Append (nface);
+			      }
+			  
+			  
+			  // Delete old Faces:
+
+			  for (i = 1; i <= rule->GetNDelF(); i++)
+			    delfaces.Append (fmapi.Get(rule->GetDelFace(i)));
+			  for (i = rule->GetNOldF()+1; i <= rule->GetNF(); i++)
+			    if (fmapi.Get(i))
+			      {
+				delfaces.Append (fmapi.Get(i));
+				fmapi.Elem(i) = 0;
+			      }
+			  
+
+			  // check orientation
+			  for (i = 1; i <= rule->GetNO() && ok; i++)
+			    {
+			      const fourint * fouri;
+			      
+			      fouri = &rule->GetOrientation(i);
+			      Vec3d v1 (lpoints.Get(pmap.Get(fouri->i1)), 
+					lpoints.Get(pmap.Get(fouri->i2)));
+			      Vec3d v2 (lpoints.Get(pmap.Get(fouri->i1)), 
+					lpoints.Get(pmap.Get(fouri->i3)));
+			      Vec3d v3 (lpoints.Get(pmap.Get(fouri->i1)), 
+					lpoints.Get(pmap.Get(fouri->i4)));
+
+			      Vec3d n;
+			      Cross (v1, v2, n);
+			      //if (n * v3 >= -1e-7*n.Length()*v3.Length()) // OR -1e-7???
+			      if (n * v3 >= -1e-9)
+				{
+				  if (loktestmode)
+				    {
+				      sprintf (problems.Elem(ri), "Orientation wrong");
+				      (*testout) << "Orientation wrong ("<< n*v3 << ")" << endl;
+				    }
+				  ok = 0;
+				}
+			    }
+
+			  
+
+			  // new points in free-zone ?
+			  for (i = rule->GetNOldP() + 1; i <= rule->GetNP() && ok; i++)
+			    if (!rule->IsInFreeZone (lpoints.Get(pmap.Get(i))))
+			      {
+				if (loktestmode)
+				  {
+				    (*testout) << "Newpoint " << lpoints.Get(pmap.Get(i))
+					       << " outside convex hull" << endl;
+				    sprintf (problems.Elem(ri), "newpoint outside convex hull");
+				  }
+				ok = 0;
+				
+			      }
+			  
+			  // insert new elements
+			  
+			  for (i = 1; i <= rule->GetNE(); i++)
+			    {
+			      elements.Append (rule->GetElement(i));
+			      for (j = 1; j <= elements.Get(i).NP(); j++)
+				elements.Elem(i).PNum(j) = pmap.Get(elements.Get(i).PNum(j));
+			    }
+			  
+
+			  // Calculate Element badness
+			  
+			  teterr = 0;
+			  for (i = 1; i <= elements.Size(); i++)
+			    {
+			      hf = CalcElementBadness (lpoints, elements.Get(i));
+			      if (hf > teterr) teterr = hf;
+			    }
+
+			  /*
+			    // keine gute Erfahrung am 25.1.2000, js
+			  if (ok && teterr < 100 &&
+			      (rule->TestFlag('b') || tolerance > 10) )
+			    {
+			      (*mycout) << "Reset teterr " 
+				   << rule->Name() 
+				   << " err = " << teterr 
+				   << endl;
+			      teterr = 1;
+			    }
+			  */
+
+			  // compare edgelength
+			  if (rule->TestFlag('l'))
+			    {
+			      double oldlen = 0;
+			      double newlen = 0;
+
+			      for (i = 1; i <= rule->GetNDelF(); i++)
+				{
+				  const Element2d & face = 
+				    rule->GetFace (rule->GetDelFace(i));
+				  for (j = 1; j <= 3; j++)
+				    {
+				      const Point3d & p1 =
+					lpoints.Get(pmap.Get(face.PNumMod(j)));
+				      const Point3d & p2 =
+					lpoints.Get(pmap.Get(face.PNumMod(j+1)));
+				      oldlen += Dist(p1, p2);
+				    }
+				}
+
+			      for (i = rule->GetNOldF()+1; i <= rule->GetNF(); i++)
+				{
+				  const Element2d & face = rule->GetFace (i);
+				  for (j = 1; j <= 3; j++)
+				    {
+				      const Point3d & p1 =
+					lpoints.Get(pmap.Get(face.PNumMod(j)));
+				      const Point3d & p2 =
+					lpoints.Get(pmap.Get(face.PNumMod(j+1)));
+				      newlen += Dist(p1, p2);
+				    }
+				}
+
+			      if (oldlen < newlen) 
+				{
+				  ok = 0;
+				  if (loktestmode)
+				    sprintf (problems.Elem(ri), "oldlen < newlen");
+				}
+			    }
+			  
+
+			  if (loktestmode)
+			    (*testout) << "ok = " << int(ok) 
+				       << "teterr = " << teterr 
+				       << "minteterr = " << minteterr << endl;
+
+
+			  if (ok && teterr < tolerance)
+			    {
+			      canuse.Elem(ri) ++;
+			      /*
+			      (*testout) << "can use rule " << rule->Name() 
+					 << ", err = " << teterr << endl;
+			      for (i = 1; i <= pmap.Size(); i++)
+				(*testout) << pmap.Get(i) << " ";
+			      (*testout) << endl;
+			      */
+
+			      if (strcmp (problems.Elem(ri), "other") == 0)
+				{
+				  if (teterr < minother)
+				    minother = teterr;
+				}
+			      else
+				{
+				  if (teterr < minwithoutother)
+				    minwithoutother = teterr;
+				}
+			    }
+
+
+			  if (teterr > minteterr) impossible = 0;
+
+			  if (ok && teterr < minteterr)
+			    {
+
+			      if (loktestmode)
+				(*testout) << "use rule" << endl;
+
+			      found = ri;
+			      minteterr = teterr;
+			      
+			      if (testmode)
+				{
+				  for (i = 1; i <= rule->GetNOldP(); i++)
+				    {
+				      (*testout) << "P" << i << ": Ref: "
+						 << rule->GetPoint (i) << "  is: "
+						 << lpoints.Get(pmap.Get(i)) << endl;
+				    }
+				}
+			      
+			      tempnewpoints.SetSize (0);
+			      for (i = noldlp+1; i <= lpoints.Size(); i++)
+				tempnewpoints.Append (lpoints.Get(i));
+			      
+			      tempnewfaces.SetSize (0);
+			      for (i = noldlf+1; i <= lfaces.Size(); i++)
+				tempnewfaces.Append (lfaces.Get(i));
+
+			      tempdelfaces.SetSize (0);
+			      for (i = 1; i <= delfaces.Size(); i++)
+				tempdelfaces.Append (delfaces.Get(i));
+			      
+			      tempelements.SetSize (0);
+			      for (i = 1; i <= elements.Size(); i++)
+				tempelements.Append (elements.Get(i));
+			    }
+			  
+
+			  lpoints.SetSize (noldlp);
+			  lfaces.SetSize (noldlf);
+			  delfaces.SetSize (0);
+			  elements.SetSize (0);
+			}
+		      
+		      npok = rule->GetNOldP();
+		      incnpok = 0;
+		    }
+		}
+	      
+	      nfok = rule->GetNOldF();
+	      
+	      for (j = 1; j <= rule->GetNP (nfok); j++)
+		{
+		  refpi = rule->GetPointNr (nfok, j);
+		  pused.Elem(pmap.Get(refpi))--;
+		  
+		  if (pused.Get(pmap.Get(refpi)) == 0)
+		    {
+		      pmap.Set(refpi, 0);
+		    }
+		}
+	      
+	    }
+	}
+      if (loktestmode)
+	(*testout) << "end rule" << endl;
+    }
+
+  if (found)
+    {
+      for (i = 1; i <= tempnewpoints.Size(); i++)
+	lpoints.Append (tempnewpoints.Get(i));
+      for (i = 1; i <= tempnewfaces.Size(); i++)
+	if (tempnewfaces.Get(i).PNum(1))
+	  lfaces.Append (tempnewfaces.Get(i));
+      for (i = 1; i <= tempdelfaces.Size(); i++)
+	delfaces.Append (tempdelfaces.Get(i));
+      for (i = 1; i <= tempelements.Size(); i++)
+	elements.Append (tempelements.Get(i));
+    }
+  
+  retminerr = minerr;
+
+
+  if (impossible && found == 0)
+    return -1;
+
+  return found;
+}
+}
diff --git a/contrib/Netgen/libsrc/meshing/ruler3.hpp b/contrib/Netgen/libsrc/meshing/ruler3.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..483d83ed4ebf9d3b5e4fd1e7acaee36b3dcbcb38
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/ruler3.hpp
@@ -0,0 +1,210 @@
+#ifndef FILE_RULER3
+#define FILE_RULER3
+
+
+/**
+  3D element generation rule.
+ */
+class vnetrule
+{
+private:
+  /// rule is applicable for quality classes above this value
+  int quality;
+  /// name of rule
+  char * name;
+  /// point coordinates in reference position
+  ARRAY<Point3d> points;
+  /// old and new faces in reference numbering
+  ARRAY<Element2d> faces;
+  /// additional edges of rule
+  ARRAY<twoint> edges;
+
+  /// points of freezone in reference coordinates
+  ARRAY<Point3d> freezone;
+  /// points of freezone in reference coordinates if tolcalss to infty
+  ARRAY<Point3d> freezonelimit;
+  /// point index, if point equal to mappoint, otherwise 0
+  ARRAY<int> freezonepi;
+  /// faces of each convex part of freezone
+  ARRAY<ARRAY<threeint>*> freefaces;
+  /// set of points of each convex part of freezone
+  ARRAY<ARRAY<int>*> freesets;
+  /// points of transformed freezone
+  ARRAY<Point3d> transfreezone;
+  /// edges of each convex part of freezone
+  ARRAY<ARRAY<twoint>*> freeedges;
+
+  /// face numbers to be deleted
+  ARRAY<int> delfaces;
+  /// elements to be generated
+  ARRAY<Element> elements;
+  /// tolerances for points and faces (used ??)
+  ARRAY<double> tolerances, linetolerances;
+  /// transformation matrix 
+  DenseMatrix oldutonewu;
+  /// transformation matrix: deviation old point to dev. freezone
+  DenseMatrix * oldutofreezone;
+  /** transformation matrix: deviation old point to dev. freezone, 
+    quality class to infinity */
+  DenseMatrix * oldutofreezonelimit;
+
+  // can be deleted:
+  // BaseMatrix *outf, *outfl;
+
+  /**
+    a point is outside of convex part of freezone, 
+    iff mat * (point, 1) >= 0 for each component (correct ?)
+    */
+  ARRAY<DenseMatrix*> freefaceinequ;
+  /// 
+  ARRAY<fourint> orientations;
+  /**
+    flags specified in rule-description file:
+    t .. test rule
+    */
+  ARRAY<char> flags;
+
+  /**
+    topological distance of face to base element
+    non-connected: > 100  (??) 
+    */
+  ARRAY<int> fnearness;
+  ARRAY<int> pnearness;
+  int maxpnearness;
+
+  /// number of old points in rule
+  int noldp;
+  /// number of new poitns in rule
+  int noldf;
+  /// box containing free-zone
+public:  
+  // double fzminx, fzmaxx, fzminy, fzmaxy, fzminz, fzmaxz;
+  Box3d fzbox;
+
+public:
+  
+  ///
+  vnetrule ();
+  ///
+  ~vnetrule ();
+  ///
+  int GetNP () const { return points.Size(); }
+  ///
+  int GetNF () const { return faces.Size(); }
+  ///
+  int GetNE () const { return elements.Size(); }
+  ///
+  int GetNO () const { return orientations.Size(); }
+  ///
+  int GetNEd () const { return edges.Size(); }
+  ///
+  int GetNOldP () const { return noldp; }
+  ///
+  int GetNOldF () const { return noldf; }
+  ///
+  int GetNDelF () const { return delfaces.Size(); }
+  ///
+  int GetQuality () const { return quality; }
+  ///
+  int GetFNearness (int fi) const { return fnearness.Get(fi); }
+  ///
+  int GetPNearness (int pi) const { return pnearness.Get(pi); }
+  ///
+  int GetMaxPNearness () const { return maxpnearness; }
+
+
+  ///
+  const Point3d & GetPoint (int i) const { return points.Get(i); }
+  ///
+  const Element2d & GetFace (int i) const { return faces.Get(i); }
+  ///
+  const Element & GetElement (int i) const { return elements.Get(i); }
+  ///
+  const twoint & GetEdge (int i) const { return edges.Get(i); }
+  ///
+  int GetDelFace (int i) const { return delfaces.Get(i); }
+  ///
+  int IsDelFace (int fn) const;
+  
+  ///
+  float CalcPointDist (int pi, const Point3d & p) const;
+  ///
+  double PointDistFactor (int pi) const
+    {
+      return tolerances.Get(pi);
+    }
+  ///
+  void SetFreeZoneTransformation (const Vector & allp,
+				  int tolclass);
+  ///
+  int IsInFreeZone (const Point3d & p) const;
+  /**
+    0 not in free-zone
+    1 in free-zone
+    -1 maybe 
+   */
+  int IsTriangleInFreeZone (const Point3d & p1, const Point3d & p2,
+                            const Point3d & p3, const ARRAY<int> & pi, int newone);
+  ///
+  int IsQuadInFreeZone (const Point3d & p1, const Point3d & p2,
+			const Point3d & p3, const Point3d & p4,
+			const ARRAY<int> & pi, int newone);
+  ///
+  int IsTriangleInFreeSet (const Point3d & p1, const Point3d & p2,
+                           const Point3d & p3, int fs, const ARRAY<int> & pi, int newone);
+
+  ///
+  int IsQuadInFreeSet (const Point3d & p1, const Point3d & p2,
+		       const Point3d & p3, const Point3d & p4,
+		       int fs, const ARRAY<int> & pi, int newone);
+  
+  ///
+  int ConvexFreeZone () const;
+  
+  /// if t1 and t2 are neighbourtriangles, NTP returns the opposite Point of t1 in t2
+  int NeighbourTrianglePoint (const threeint & t1, const threeint & t2) const;
+  ///
+  const Point3d & GetTransFreeZone (int i) { return transfreezone.Get(i); }
+
+  ///
+  int GetNP (int fn) const
+  { return faces.Get(fn).GetNP(); }
+  ///
+  int GetPointNr (int fn, int endp) const
+  { return faces.Get(fn).PNum(endp); }
+  ///
+  int GetPointNrMod (int fn, int endp) const
+  { return faces.Get(fn).PNumMod(endp); }
+  ///
+  const fourint & GetOrientation (int i) { return orientations.Get(i); }
+
+  ///
+  int TestFlag (char flag) const;
+
+  ///
+  const DenseMatrix & GetOldUToNewU () const { return oldutonewu; }
+  //
+  //  const DenseMatrix & GetOldUToFreeZone () const { return oldutofreezone; }
+  //
+  //  const DenseMatrix & GetOldUToFreeZoneLimit () const 
+  //    { return oldutofreezonelimit; }
+  ///
+  const char * Name () const { return name; }
+  ///
+  void LoadRule (istream & ist);
+
+  ///
+  const ARRAY<Point3d> & GetTransFreeZone () { return transfreezone; }
+  ///
+  int TestOk () const;
+
+  ///
+  friend void TestRules ();
+  ///
+  //  friend void Plot3DRule (const ROT3D & r, char key);
+};
+
+
+
+#endif
+
diff --git a/contrib/Netgen/libsrc/meshing/secondorder.cpp b/contrib/Netgen/libsrc/meshing/secondorder.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..66c91cfea92c1aa01dabdb5e31c7da2591c077ae
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/secondorder.cpp
@@ -0,0 +1,486 @@
+#include <mystdlib.h>
+#include "meshing.hpp"
+
+
+namespace netgen
+{
+
+
+
+  
+  void Refinement :: MakeSecondOrder (Mesh & mesh)
+  {
+    int nseg, nse, ne;
+
+    mesh.ComputeNVertices();
+    mesh.SetNP(mesh.GetNV());
+  
+    INDEX_2_HASHTABLE<int> between(mesh.GetNP() + 5);
+
+
+    bool thinlayers = 0;
+    for (ElementIndex ei = 0; ei < mesh.GetNE(); ei++)
+      if (mesh[ei].GetType() == PRISM ||
+	  mesh[ei].GetType() == PRISM12)
+	thinlayers = 1;
+    
+
+    nseg = mesh.GetNSeg();
+    for (SegmentIndex si = 0; si < nseg; si++)
+      {
+	Segment & el = mesh.LineSegment(si);
+
+	INDEX_2 i2 = INDEX_2::Sort (el.p1, el.p2);
+
+	if (between.Used(i2))
+	  el.pmid = between.Get(i2);
+	else
+	  {
+	    Point<3> pb;
+	    EdgePointGeomInfo ngi;
+            PointBetween (mesh.Point (el.p1),
+                          mesh.Point (el.p2), 0.5,
+			  el.surfnr1, el.surfnr2,
+			  el.epgeominfo[0], el.epgeominfo[1],
+			  pb, ngi);
+	  
+	    el.pmid = mesh.AddPoint (pb);
+	    between.Set (i2, el.pmid);
+	  }
+      }
+
+    // refine surface elements
+    nse = mesh.GetNSE();
+    for (SurfaceElementIndex sei = 0; sei < nse; sei++)
+      {
+	int j;
+	const Element2d & el = mesh.SurfaceElement(sei);
+
+	int onp(0);
+      
+	Element2d newel;
+	newel.SetIndex (el.GetIndex());
+
+	static int betw_trig[3][3] =
+	  { { 1, 2, 3 },
+	    { 0, 2, 4 },
+	    { 0, 1, 5 } };
+	static int betw_quad6[2][3] =
+	  { { 0, 1, 4 },
+	    { 3, 2, 5 } };
+	static int betw_quad8[4][3] =
+	  { { 0, 1, 4 },
+	    { 3, 2, 5 },
+	    { 0, 3, 6 },
+	    { 1, 2, 7 } };
+	int (*betw)[3](NULL);
+      
+	switch (el.GetType())
+	  {
+	  case TRIG:
+	  case TRIG6:
+	    {
+	      betw = betw_trig;
+	      newel.SetType (TRIG6);
+	      onp = 3;
+	      break;
+	    }
+	  case QUAD:
+	  case QUAD6: 
+	  case QUAD8:
+	    {
+	      if (thinlayers)
+		{
+		  betw = betw_quad6;
+		  newel.SetType (QUAD6);
+		}
+	      else
+		{
+		  betw = betw_quad8;
+		  newel.SetType (QUAD8);
+		}
+	      onp = 4;
+	      break;
+	    }
+	  default:
+	    PrintSysError ("Unhandled element in secondorder:", int(el.GetType()));
+	  }
+
+	for (j = 0; j < onp; j++)
+	  newel[j] = el[j];
+      
+	int nnp = newel.GetNP();
+	for (j = 0; j < nnp-onp; j++)
+	  {
+	    int pi1 = newel[betw[j][0]];
+	    int pi2 = newel[betw[j][1]];
+	  
+	    INDEX_2 i2 = INDEX_2::Sort (pi1, pi2);
+	  
+	    if (between.Used(i2))
+	      newel[onp+j] = between.Get(i2);
+	    else
+	      {
+		Point<3> pb;
+		PointGeomInfo newgi;
+		PointBetween (mesh.Point (pi1),
+			      mesh.Point (pi2), 0.5, 
+			      mesh.GetFaceDescriptor(el.GetIndex ()).SurfNr(),
+			      el.GeomInfoPi (betw[j][0]+1),
+			      el.GeomInfoPi (betw[j][1]+1),
+			      pb, newgi);
+
+		newel[onp+j] = mesh.AddPoint (pb);
+		between.Set (i2, newel[onp+j]);
+	      }
+	  }
+      
+	mesh.SurfaceElement(sei) = newel;
+      }
+
+ 
+    //    int i, j;
+
+
+
+    // refine volume elements
+    ne = mesh.GetNE();
+    for (int i = 1; i <= ne; i++)
+      {
+	const Element & el = mesh.VolumeElement(i);
+	int onp(0);
+
+	Element newel;
+	newel.SetIndex (el.GetIndex());
+
+	static int betw_tet[6][3] =
+	  { { 0, 1, 4 },
+	    { 0, 2, 5 },
+	    { 0, 3, 6 },
+	    { 1, 2, 7 },
+	    { 1, 3, 8 },
+	    { 2, 3, 9 } };
+	static int betw_prism[6][3] =
+	  {
+	    { 0, 2, 6 },
+	    { 0, 1, 7 },
+	    { 1, 2, 8 },
+	    { 3, 5, 9 },
+	    { 3, 4, 10 },
+	    { 4, 5, 11 },
+	  };
+	int (*betw)[3](NULL);
+
+	switch (el.GetType())
+	  {
+	  case TET:
+	  case TET10:
+	    {
+	      betw = betw_tet;
+	      newel.SetType (TET10);
+	      onp = 4;
+	      break;
+	    }
+	  case PRISM:
+	  case PRISM12:
+	    {
+	      betw = betw_prism;
+	      newel.SetType (PRISM12);
+	      onp = 6;
+	      break;
+	    }
+	  default:
+	    PrintSysError ("MakeSecondOrder, illegal vol type ", el.GetType());
+	  }
+
+
+	for (int j = 1; j <= onp; j++)
+	  newel.PNum(j) = el.PNum(j);
+	int nnp = newel.GetNP();
+
+	for (int j = 0; j < nnp-onp; j++)
+	  {
+	    INDEX_2 i2(newel[betw[j][0]],
+		       newel[betw[j][1]]);
+	    i2.Sort();
+	  
+	    if (between.Used(i2))
+	      newel.PNum(onp+1+j) = between.Get(i2);
+	    else
+	      {
+		newel.PNum(onp+1+j) = mesh.AddPoint
+		  (Center (mesh.Point(i2.I1()),
+			   mesh.Point(i2.I2())));
+		between.Set (i2, newel.PNum(onp+1+j));
+	      }
+	  }
+
+	mesh.VolumeElement (i) = newel;
+      }
+
+
+    // makes problems after linear mesh refinement, since
+    // 2nd order identifications are not removed
+    // update identification tables
+    for (int i = 1; i <= mesh.GetIdentifications().GetMaxNr(); i++)
+      {
+	ARRAY<int,PointIndex::BASE> identmap;
+	mesh.GetIdentifications().GetMap (i, identmap);
+
+	for (INDEX_2_HASHTABLE<int>::Iterator it = between.Begin();
+	     it != between.End(); it++)
+	  {
+	      INDEX_2 i2;
+	      int newpi;
+	      between.GetData (it, i2, newpi);
+	      INDEX_2 oi2(identmap.Get(i2.I1()),
+			  identmap.Get(i2.I2()));
+	      oi2.Sort();
+	      if (between.Used (oi2))
+		{
+		  int onewpi = between.Get(oi2);
+		  mesh.GetIdentifications().Add (newpi, onewpi, i);
+		}
+	  }
+
+	/*
+	for (int j = 1; j <= between.GetNBags(); j++)
+	  for (int k = 1; k <= between.GetBagSize(j); k++)
+	    {
+	      INDEX_2 i2;
+	      int newpi;
+	      between.GetData (j, k, i2, newpi);
+	      INDEX_2 oi2(identmap.Get(i2.I1()),
+			  identmap.Get(i2.I2()));
+	      oi2.Sort();
+	      if (between.Used (oi2))
+		{
+		  int onewpi = between.Get(oi2);
+		  mesh.GetIdentifications().Add (newpi, onewpi, i);
+		}
+	    }
+	*/
+      }
+
+
+    //  mesh.mglevels++;
+    int oldsize = mesh.mlbetweennodes.Size();
+    mesh.mlbetweennodes.SetSize(mesh.GetNP());
+    for (int i = oldsize; i < mesh.GetNP(); i++)
+      mesh.mlbetweennodes[i] = INDEX_2(0,0);
+
+    /*
+    for (i = 1; i <= between.GetNBags(); i++)
+      for (j = 1; j <= between.GetBagSize(i); j++)
+	{
+	  INDEX_2 oldp;
+	  int newp;
+	  between.GetData (i, j, oldp, newp);
+	  mesh.mlbetweennodes.Elem(newp) = oldp;
+	}
+    */
+
+    for (INDEX_2_HASHTABLE<int>::Iterator it = between.Begin();
+	 it != between.End(); it++)
+      {
+	mesh.mlbetweennodes[between.GetData (it)] = between.GetHash(it);
+      }
+
+    mesh.ComputeNVertices();
+  
+    //  ValidateSecondOrder (mesh);
+  }
+
+
+  void Refinement :: ValidateSecondOrder (Mesh & mesh)
+  {
+    PrintMessage (3, "Validate mesh");
+    int np = mesh.GetNP();
+    int ne = mesh.GetNE();
+    // int i, j;
+    ARRAY<INDEX_2> parents(np);
+  
+    for (int i = 1; i <= np; i++)
+      parents.Elem(i) = INDEX_2(0,0);
+
+    for (int i = 1; i <= ne; i++)
+      {
+	const Element & el = mesh.VolumeElement(i);
+	if (el.GetType() == TET10)
+	  {
+	    static int betweentab[6][3] =
+	      { { 1, 2, 5 },
+		{ 1, 3, 6 },
+		{ 1, 4, 7 },
+		{ 2, 3, 8 },
+		{ 2, 4, 9 },
+		{ 3, 4, 10 } };
+	    for (int j = 0; j < 6; j++)
+	      {
+		int f1 = el.PNum (betweentab[j][0]);
+		int f2 = el.PNum (betweentab[j][1]);
+		int son = el.PNum (betweentab[j][2]);
+		parents.Elem(son).I1() = f1;
+		parents.Elem(son).I2() = f2;
+	      }
+	  }
+      }
+
+    ValidateRefinedMesh (mesh, parents);
+  }
+
+
+  void Refinement ::
+  ValidateRefinedMesh (Mesh & mesh, 
+		       ARRAY<INDEX_2> & parents)
+  {
+    // int i, j, k;
+  
+    // homotopy method
+
+    int ne = mesh.GetNE();
+
+    int cnttrials = 100;
+    int wrongels = 0;
+    for (int i = 1; i <= ne; i++)
+      if (mesh.VolumeElement(i).CalcJacobianBadness (mesh.Points()) > 1e10)
+	{
+	  wrongels++;
+	  mesh.VolumeElement(i).flags.badel = 1;
+	}
+      else
+	mesh.VolumeElement(i).flags.badel = 0;
+
+    double facok = 0;
+    double factry;
+
+    BitArray illegalels(ne);
+    illegalels.Clear();
+
+      
+    if (wrongels)
+      {
+	cout << "WARNING: " << wrongels << " illegal element(s) found" << endl;
+
+	int np = mesh.GetNP();
+	ARRAY<Point<3> > should(np);
+	ARRAY<Point<3> > can(np);
+
+	for (int i = 1; i <= np; i++)
+	  {
+	    should.Elem(i) = can.Elem(i) = mesh.Point(i);
+	  }
+
+	for (int i = 1; i <= parents.Size(); i++)
+	  {
+	    if (parents.Get(i).I1())
+	      can.Elem(i) = Center (can.Elem(parents.Get(i).I1()),
+				    can.Elem(parents.Get(i).I2()));
+	  }
+
+	BitArray boundp(np);
+	boundp.Clear();
+	for (int i = 1; i <= mesh.GetNSE(); i++)
+	  {
+	    const Element2d & sel = mesh.SurfaceElement(i);
+	    for (int j = 1; j <= sel.GetNP(); j++)
+	      boundp.Set(sel.PNum(j));
+	  }
+
+
+	(*testout) << "bpoints:" << endl;
+	for (int i = 1; i <= np; i++)
+	  if (boundp.Test(i))
+	    (*testout) << i << endl;
+
+	double lam = 0.5;
+
+	while (facok < 1-1e-8 && cnttrials > 0)
+	  {
+	    lam *= 4;
+	    if (lam > 2) lam = 2;
+
+	    do
+	      {
+		//	      cout << "trials: " << cnttrials << endl;
+		lam *= 0.5;
+		cnttrials--;
+
+		cout << "lam = " << lam << endl;
+
+		factry = lam + (1-lam) * facok;
+		cout << "trying: " << factry << endl;
+
+		for (int i = 1; i <= np; i++)
+		  if (boundp.Test(i))
+		    {
+		      for (int j = 0; j < 3; j++)
+			mesh.Point(i)(j) = 
+			  lam * should.Get(i)(j) +
+			  (1-lam) * can.Get(i)(j);
+		    }
+		  else
+		    mesh.Point(i) = Point<3> (can.Get(i));
+	      
+		//	      (*testout) << "bad els: " << endl;
+		wrongels = 0;
+		for (int i = 1; i <= ne; i++)
+		  {
+		    if (!illegalels.Test(i) && 
+			mesh.VolumeElement(i).
+			CalcJacobianBadness(mesh.Points()) > 1e10)
+		      {
+			wrongels++;
+			Element & el = mesh.VolumeElement(i);
+			el.flags.badel = 1;
+		     
+		      
+			if (lam < 1e-4)
+			  illegalels.Set(i);
+ 
+
+			/*
+			  (*testout) << i << ": ";
+			  for (j = 1; j <= el.GetNP(); j++)
+			  (*testout) << el.PNum(j) << " ";
+			  (*testout) << endl;
+			*/
+		      }
+		    else
+		      mesh.VolumeElement(i).flags.badel = 0;
+		  }
+		cout << "wrongels = " << wrongels << endl;
+	      }
+	    while (wrongels && cnttrials > 0);
+
+	    mesh.CalcSurfacesOfNode();
+	    mesh.ImproveMeshJacobian (OPT_WORSTCASE);	      
+	  
+	    facok = factry;
+	    for (int i = 1; i <= np; i++)
+	      can.Elem(i) = mesh.Point(i);
+	  }
+      }
+
+
+      
+    for (int i = 1; i <= ne; i++)
+      {
+	if (illegalels.Test(i))
+	  {
+	    cout << "illegal element: " << i << endl;
+	    mesh.VolumeElement(i).flags.badel = 1;	
+	  }
+	else
+	  mesh.VolumeElement(i).flags.badel = 0;	
+      }
+  
+    /*
+      if (cnttrials <= 0)
+      {
+      cerr << "ERROR: Sorry, illegal elements:" << endl;
+      }
+    */
+  }
+
+}
diff --git a/contrib/Netgen/libsrc/meshing/smoothing2.5.cpp b/contrib/Netgen/libsrc/meshing/smoothing2.5.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..2789b785bcf4ea82f07efc9cf4d4e5d0e5105e81
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/smoothing2.5.cpp
@@ -0,0 +1,265 @@
+#include <mystdlib.h>
+
+#include "meshing.hpp"
+#include <opti.hpp>
+
+namespace netgen
+{
+
+
+  void MeshOptimize2d :: ProjectBoundaryPoints(ARRAY<int> & surfaceindex, 
+					       const ARRAY<Point<3>* > & from, ARRAY<Point<3>* > & dest)
+  {
+    for(int i=0; i<surfaceindex.Size(); i++)
+      {
+	if(surfaceindex[i] >= 0)
+	  {
+	    *dest[i] = *from[i];
+	    ProjectPoint(surfaceindex[i],*dest[i]);
+	  }
+      }
+      
+
+  }
+
+  void MeshOptimize2d :: ImproveVolumeMesh (Mesh & mesh)
+  {
+    
+    if (!faceindex)
+      {
+	PrintMessage (3, "Smoothing");
+
+	for (faceindex = 1; faceindex <= mesh.GetNFD(); faceindex++)
+	  {
+	    ImproveVolumeMesh (mesh);
+	    if (multithread.terminate)
+	      throw NgException ("Meshing stopped");
+	  }
+	faceindex = 0;
+	return;
+      }
+      
+
+
+    static int timer = NgProfiler::CreateTimer ("MeshSmoothing 2D");
+    NgProfiler::RegionTimer reg (timer);
+
+
+
+    CheckMeshApproximation (mesh);
+
+    int i, j, k;
+    SurfaceElementIndex sei;
+
+    ARRAY<SurfaceElementIndex> seia;
+    mesh.GetSurfaceElementsOfFace (faceindex, seia);
+
+    bool mixed = 0;
+    for (i = 0; i < seia.Size(); i++)
+      if (mesh[seia[i]].GetNP() != 3)
+	{
+	  mixed = 1;
+	  break;
+	}
+
+
+    int loci;
+    double fact;
+    bool moveisok;
+
+    PointGeomInfo ngi;
+    Point<3> origp;
+
+    Vector x(3);
+
+    ARRAY<MeshPoint, PointIndex::BASE> savepoints(mesh.GetNP());
+
+    ARRAY<int, PointIndex::BASE> nelementsonpoint(mesh.GetNP());
+    nelementsonpoint = 0;
+
+    for (i = 0; i < seia.Size(); i++)
+      {
+	const Element2d & el = mesh[seia[i]];
+	for (j = 0; j < el.GetNP(); j++)
+	  nelementsonpoint[el[j]]++;
+      }
+
+
+    TABLE<SurfaceElementIndex,PointIndex::BASE> elementsonpoint(nelementsonpoint);
+    for (i = 0; i < seia.Size(); i++)
+      {
+	const Element2d & el = mesh[seia[i]];
+	for (j = 0; j < el.GetNP(); j++)
+	  elementsonpoint.Add (el[j], seia[i]);
+      }
+    
+
+    JacobianPointFunction pf(mesh.Points(),mesh.VolumeElements());
+
+
+
+//     Opti2SurfaceMinFunction surfminf(mesh);
+//     Opti2EdgeMinFunction edgeminf(mesh);
+//     Opti2SurfaceMinFunctionJacobian surfminfj(mesh);
+
+    OptiParameters par;
+    par.maxit_linsearch = 8;
+    par.maxit_bfgs = 5;
+
+    int np = mesh.GetNP();
+    int ne = mesh.GetNE();
+
+    BitArray badnodes(np);
+    badnodes.Clear();
+
+    for (i = 1; i <= ne; i++)
+      {
+	const Element & el = mesh.VolumeElement(i);
+	double bad = el.CalcJacobianBadness (mesh.Points());
+	if (bad > 1)
+	  for (j = 1; j <= el.GetNP(); j++)
+	    badnodes.Set (el.PNum(j));
+      }
+
+
+    bool printeddot = 0;
+    char plotchar = '.';
+    int modplot = 1;
+    if (mesh.GetNP() > 1000)
+      {
+	plotchar = '+';
+	modplot = 10;
+      }
+    if (mesh.GetNP() > 10000)
+      {
+	plotchar = 'o';
+	modplot = 100;
+      }
+    int cnt = 0;
+
+
+    ARRAY<SurfaceElementIndex> locelements(0);
+    ARRAY<int> locrots(0);
+
+    for (PointIndex pi = PointIndex::BASE; 
+	 pi < mesh.GetNP()+PointIndex::BASE; pi++)
+      {
+	if (mesh[pi].Type() != SURFACEPOINT)
+	  continue;
+
+	if (multithread.terminate)
+	  throw NgException ("Meshing stopped");
+	
+	int surfi(-1);
+
+	if(elementsonpoint[pi].Size() == 0)
+	  continue;
+
+	Element2d & hel = mesh[elementsonpoint[pi][0]];
+
+	if(hel.GetIndex() != faceindex)
+	  continue;
+
+	cnt++;
+	if (cnt % modplot == 0 && writestatus)
+	  {
+	    printeddot = 1;
+	    PrintDot (plotchar);
+	  }
+
+		
+	int hpi = 0;
+	for (j = 1; j <= hel.GetNP(); j++)
+	  if (hel.PNum(j) == pi)
+	    {
+	      hpi = j;
+	      break;
+	    }
+	PointGeomInfo gi1 = hel.GeomInfoPi(hpi);
+	
+	locelements.SetSize(0);
+	locrots.SetSize (0);
+	
+	for (j = 0; j < elementsonpoint[pi].Size(); j++)
+	  {
+	    sei = elementsonpoint[pi][j];
+	    const Element2d & bel = mesh[sei];
+	    surfi = mesh.GetFaceDescriptor(bel.GetIndex()).SurfNr();
+	    
+	    locelements.Append (sei);
+	    
+	    for (k = 1; k <= bel.GetNP(); k++)
+	      if (bel.PNum(k) == pi)
+		{
+		  locrots.Append (k);
+		  break;
+		}
+	  }
+	 
+
+	double lh = mesh.GetH(mesh.Point(pi));
+	par.typx = lh;
+
+	pf.SetPointIndex(pi);
+	
+	x = 0;
+	bool pok = (pf.Func (x) < 1e10); 
+	
+	if (pok)
+	  {
+	    BFGS (x, pf, par);
+	    
+	    origp = mesh[pi];
+	    loci = 1;
+	    fact = 1;
+	    moveisok = false;
+	
+	    
+	    //optimizer loop (if whole distance is not possible, move only a bit!!!!)
+	    while (loci <= 5 && !moveisok)
+	      {
+		loci ++;
+		mesh[pi](0) = origp(0) + x.Get(1)*fact;
+		mesh[pi](1) = origp(1) + x.Get(2)*fact;
+		mesh[pi](2) = origp(2) + x.Get(3)*fact;
+		fact = fact/2.;
+	    
+	    
+		//cout << "origp " << origp << " newp " << mesh[pi];
+	    
+		ngi = gi1;
+		moveisok = (ProjectPointGI (surfi, mesh[pi], ngi) != 0);
+
+		//cout << " projected " << mesh[pi] << endl;
+
+		// point lies on same chart in stlsurface
+		
+		if (moveisok)
+		  {
+		    for (j = 0; j < locelements.Size(); j++)
+		      mesh[locelements[j]].GeomInfoPi(locrots[j]) = ngi;
+
+		    //cout << "moved " << origp << " to " << mesh[pi] << endl;
+		  }
+		else
+		  {
+		    mesh[pi] = origp;
+		  }
+	    
+	      }
+	  }
+	else
+	  {
+	    cout << "el not ok (point " << pi << ": " << mesh[pi] << ")" << endl;
+	  }
+      }
+
+    if (printeddot)
+      PrintDot ('\n');
+  
+    CheckMeshApproximation (mesh);
+    mesh.SetNextTimeStamp();
+  }
+
+  
+}
diff --git a/contrib/Netgen/libsrc/meshing/smoothing2.cpp b/contrib/Netgen/libsrc/meshing/smoothing2.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..e43352828bd31f843634e22b9545552a47460ade
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/smoothing2.cpp
@@ -0,0 +1,985 @@
+#include <mystdlib.h>
+
+#include "meshing.hpp"
+#include <opti.hpp>
+
+namespace netgen
+{
+
+  static const MeshOptimize2d * meshthis;
+
+
+#ifdef OLD
+
+  void CalcTriangleBadness (double x2, double x3, double y3, double metricweight,
+				   double h, double & badness, double & g1x, double & g1y)
+  {
+    // badness = sqrt(3.0) /36 * circumference^2 / area - 1 
+    // p1 = (0, 0), p2 = (x2, 0), p3 = (x3, y3);
+
+    Vec2d v23;
+    double l12, l13, l23, cir, area;
+    static const double c = sqrt(3.0) / 36;
+    double c1, c2, c3, c4;
+
+    v23.X() = x3 - x2;
+    v23.Y() = y3;
+
+    l12 = x2;
+    l13 = sqrt (x3*x3 + y3*y3);
+    l23 = v23.Length();
+
+    cir = l12 + l13 + l23;
+    area = 0.5 * x2 * y3;
+
+    if (area <= 1e-24 * cir * cir)
+      {
+	g1x = 0;
+	g1y = 0;
+	badness = 1e10;
+	return;
+      }
+
+    badness = c * cir * cir / area - 1;
+
+    c1 = 2 * c * cir / area;
+    c2 = 0.5 * c * cir * cir / (area * area);
+
+    g1x = c1 * ( - 1 - x3 / l13) - c2 * (-v23.Y());
+    g1y = c1 * (     - y3 / l13) - c2 * ( v23.X());
+  
+    //  metricweight = 0.1;
+    if (metricweight > 0)
+      {
+	// area = (x2 - x1) * (y3 - y1) - (x3 - x1) * (y2 - y1);
+	// add:  metricweight * (area / h^2 + h^2 / area - 2)
+      
+	const double area = x2 * y3;
+	const double dareax1 = -y3; 
+	const double dareay1 = x3 - x2; 
+
+	const double areahh = area / (h * h);
+	const double fac = metricweight * (areahh - 1 / areahh) / area;
+
+	badness += metricweight * (areahh + 1 / areahh - 2);
+	g1x += fac * dareax1;
+	g1y += fac * dareay1; 
+      
+	/*
+	// add: metricweight * (l1^2/h^2 + l2^2/h^2 + l3^2/h2 + h^2/l1^2 + h^2/l2^2 + h^2/l3^2 - 6)
+	double h2 = h*h;
+	double l1 = x2*x2;
+	double l2 = x3*x3+y3*y3;
+	double l3 = (x2-x3)*(x2-x3)+y3*y3;
+	double dl1dx = 2*(-x2);
+	double dl1dy = 0;
+	double dl2dx = -2*x3;
+	double dl2dy = -2*y3;
+
+	badness += (l1/h2 + l2/h2 + l3/h2 +h2/l1 + h2/l2 + h2/l3-6) * metricweight;
+
+	g1x += metricweight * (dl1dx/h2-h2/(l1*l1)*dl1dx + dl2dx/h2-h2/(l2*l2)*dl2dx);
+	g1y += metricweight * (dl1dy/h2-h2/(l1*l1)*dl1dy + dl2dy/h2-h2/(l2*l2)*dl2dy);
+	*/
+      }
+  }
+
+#endif
+
+  static const double c_trig = 0.14433756;      // sqrt(3.0) / 12
+  static const double c_trig4 = 0.57735026;     // sqrt(3.0) / 3
+
+  inline double CalcTriangleBadness (double x2, double x3, double y3, 
+				     double metricweight, double h)
+  {
+    // badness = sqrt(3.0) / 12 * (\sum l_i^2) / area - 1 
+    // p1 = (0, 0), p2 = (x2, 0), p3 = (x3, y3);
+
+    double cir_2 = (x2*x2 + x3*x3 + y3*y3 - x2*x3);
+    double area = x2 * y3;
+    
+    if (area <= 1e-24 * cir_2)
+      return 1e10;
+    
+    double badness = c_trig4 * cir_2 / area - 1;
+    
+    if (metricweight > 0)
+      {
+	// add:  metricweight * (area / h^2 + h^2 / area - 2)
+
+	double areahh = area / (h * h);
+	badness += metricweight * (areahh + 1 / areahh - 2);
+      }
+    return badness;
+  }
+
+  
+  inline void CalcTriangleBadness (double x2, double x3, double y3, double metricweight,
+				   double h, double & badness, double & g1x, double & g1y)
+  {
+    // old: badness = sqrt(3.0) /36 * circumference^2 / area - 1 
+    // badness = sqrt(3.0) / 12 * (\sum l_i^2) / area - 1 
+    // p1 = (0, 0), p2 = (x2, 0), p3 = (x3, y3);
+
+
+    double cir_2 = 2* (x2*x2 + x3*x3 + y3*y3 - x2*x3);
+    double area = 0.5 * x2 * y3;
+
+    if (area <= 1e-24 * cir_2)
+      {
+	g1x = 0;
+	g1y = 0;
+	badness = 1e10;
+	return;
+      }
+
+    badness = c_trig * cir_2 / area - 1;
+
+    double c1 = -2 * c_trig / area;
+    double c2 = 0.5 * c_trig * cir_2 / (area * area);
+    g1x = c1 * (x2 + x3) + c2 * y3;
+    g1y = c1 * (y3)      + c2 * (x2-x3); 
+
+    if (metricweight > 0)
+      {
+	// area = (x2 - x1) * (y3 - y1) - (x3 - x1) * (y2 - y1);
+	// add:  metricweight * (area / h^2 + h^2 / area - 2)
+      
+	area = x2 * y3;
+	double dareax1 = -y3; 
+	double dareay1 = x3 - x2; 
+
+	double areahh = area / (h * h);
+	double fac = metricweight * (areahh - 1 / areahh) / area;
+
+	badness += metricweight * (areahh + 1 / areahh - 2);
+	g1x += fac * dareax1;
+	g1y += fac * dareay1; 
+      }
+  }
+
+
+
+
+
+
+
+
+
+#ifdef OLD
+  double CalcTriangleBadness (const Point3d & p1, 
+			      const Point3d & p2, 
+			      const Point3d & p3,
+			      double metricweight,
+			      double h)
+  {
+    double badness;
+    double g1x, g1y;
+  
+    Vec3d e1 (p1, p2);
+    Vec3d e2 (p1, p3);
+  
+    double e1l = e1.Length() + 1e-24;
+    e1 /= e1l;
+    double e1e2 = (e1 * e2);
+    e2.Add (-e1e2, e1);
+    double e2l = e2.Length();
+  
+    CalcTriangleBadness ( e1l, e1e2, e2l,
+			  metricweight, h, badness, g1x, g1y);
+    return badness;
+  }
+#endif
+
+
+
+
+  double CalcTriangleBadness (const Point3d & p1, 
+			      const Point3d & p2, 
+			      const Point3d & p3,
+			      double metricweight,
+			      double h)
+  {
+    // badness = sqrt(3.0) / 12 * (\sum l_i^2) / area - 1 
+    // p1 = (0, 0), p2 = (x2, 0), p3 = (x3, y3);
+
+    Vec3d e12(p1,p2);
+    Vec3d e13(p1,p3);
+    Vec3d e23(p2,p3);
+  
+    double l12_2 = e12.Length2();
+    double l13_2 = e13.Length2();
+    double l23_2 = e23.Length2();
+
+    double cir_2 = l12_2 + l13_2 + l23_2;
+    Vec3d area_v = Cross (e12, e13);
+    double area = 0.5 * area_v.Length();
+
+    if (area <= 1e-24 * cir_2)
+      return 1e10;
+
+    double badness = c_trig * cir_2 / area - 1;
+
+    if (metricweight > 0)
+      {
+	// area = (x2 - x1) * (y3 - y1) - (x3 - x1) * (y2 - y1);
+	// add:  metricweight * (area / h^2 + h^2 / area - 2)
+
+	const double areahh = area / (h * h);
+	badness += metricweight * (areahh + 1 / areahh - 2);
+      }
+
+    return badness;
+  }
+
+
+  double CalcTriangleBadness (const Point3d & p1, 
+			      const Point3d & p2, 
+			      const Point3d & p3,
+			      const Vec3d & n,
+			      double metricweight,
+			      double h)
+  {
+    Vec3d v1 (p1, p2);
+    Vec3d v2 (p1, p3);
+
+    Vec3d e1 = v1;
+    Vec3d e2 = v2;
+
+    e1 -= (e1 * n) * n;
+    e1 /= (e1.Length() + 1e-24);
+    e2 = Cross (n, e1);
+
+    return CalcTriangleBadness ( (e1 * v1), (e1 * v2), (e2 * v2), 
+				 metricweight, h);
+  }
+
+
+
+
+
+  static MeshPoint sp1; 
+  static PointGeomInfo gi1;
+  static Vec<3> normal, t1, t2;
+  static ARRAY<SurfaceElementIndex> locelements(0);
+  static ARRAY<int> locrots(0);
+  static ARRAY<double> lochs(0);
+  // static int locerr2;
+  static double locmetricweight = 0;
+  static double loch;
+  static int surfi, surfi2;
+  static int uselocalh;
+
+
+  class Opti2SurfaceMinFunction : public MinFunction
+  {
+    const Mesh & mesh;
+  public:
+    Opti2SurfaceMinFunction (const Mesh & amesh)
+      : mesh(amesh)
+    { } ;
+    virtual double FuncGrad (const Vector & x, Vector & g) const;
+    virtual double FuncDeriv (const Vector & x, const Vector & dir, double & deriv) const;
+    virtual double Func (const Vector & x) const;
+  };
+  
+  double Opti2SurfaceMinFunction :: 
+  Func (const Vector & x) const
+  {
+    Vector g(x.Size());
+    return FuncGrad (x, g);
+  }
+
+
+  double Opti2SurfaceMinFunction :: 
+  FuncGrad (const Vector & x, Vector & grad) const
+  {
+    Vec<3> n, vgrad;
+    Point<3> pp1;
+    double g1x, g1y;
+    double badness, hbadness;
+
+    vgrad = 0;
+    badness = 0;
+
+    meshthis -> GetNormalVector (surfi, sp1, gi1, n);
+    pp1 = sp1 + x(0) * t1 + x(1) * t2;
+
+    //  meshthis -> ProjectPoint (surfi, pp1);
+    // meshthis -> GetNormalVector (surfi, pp1, n);
+
+    for (int j = 0; j < locelements.Size(); j++)
+      {
+	int roti = locrots[j];
+	const Element2d & bel = mesh[locelements[j]];
+
+	Vec<3> e1 = mesh[bel.PNumMod(roti + 1)] - pp1;
+	Vec<3> e2 = mesh[bel.PNumMod(roti + 2)] - pp1;
+
+	if (uselocalh) loch = lochs[j];
+
+	double e1l = e1.Length();
+	if (Determinant(e1, e2, n) > 1e-8 * e1l * e2.Length())
+	  {
+	    e1 /= e1l;
+	    double e1e2 = e1 * e2;
+            e2 -= e1e2 * e1;
+	    double e2l = e2.Length();
+
+	    CalcTriangleBadness ( e1l, e1e2, e2l, locmetricweight, loch,
+				  hbadness, g1x, g1y);
+
+	    badness += hbadness;
+            vgrad += g1x * e1 + (g1y/e2l) * e2;
+	  }
+	else
+	  {
+	    (*testout) << "very very bad badness" << endl;
+	    badness += 1e8;
+	  }
+      }
+
+    vgrad -=  (vgrad * n) * n;
+
+    grad(0) = vgrad * t1;
+    grad(1) = vgrad * t2;
+    return badness;
+  }
+
+
+
+
+  double Opti2SurfaceMinFunction :: 
+  FuncDeriv (const Vector & x, const Vector & dir, double & deriv) const
+  {
+    Vec<3> n, vgrad;
+    Point<3> pp1;
+    double g1x, g1y;
+    double badness, hbadness;
+
+    vgrad = 0;
+    badness = 0;
+
+    meshthis -> GetNormalVector (surfi, sp1, gi1, n);
+
+    pp1 = sp1 + x(0) * t1 + x(1) * t2;
+
+    for (int j = 0; j < locelements.Size(); j++)
+      {
+	int roti = locrots[j];
+
+	const Element2d & bel = mesh[locelements[j]];
+
+	Vec<3> e1 = mesh[bel.PNumMod(roti + 1)] - pp1;
+	Vec<3> e2 = mesh[bel.PNumMod(roti + 2)] - pp1;
+
+	if (uselocalh) loch = lochs[j];
+
+	double e1l = e1.Length();
+	if (Determinant(e1, e2, n) > 1e-8 * e1l * e2.Length())
+	  {
+	    e1 /= e1l;
+	    double e1e2 = e1 * e2;
+	    e2 -= e1e2 * e1;
+	    double e2l = e2.Length();
+
+	    CalcTriangleBadness ( e1l, e1e2, e2l, locmetricweight, loch,
+				  hbadness, g1x, g1y);
+
+	    badness += hbadness;
+            vgrad += g1x * e1 + (g1y / e2l) * e2;
+	  }
+	else
+	  {
+	    (*testout) << "very very bad badness" << endl;
+	    badness += 1e8;
+	  }
+      }
+
+    vgrad -= (vgrad * n) * n;
+    deriv = dir(0) * (vgrad*t1) + dir(1) * (vgrad*t2);
+
+    return badness;
+  }
+
+
+
+
+
+
+
+
+
+
+
+
+  class Opti2EdgeMinFunction : public MinFunction
+  {
+    const Mesh & mesh;
+  public:
+    Opti2EdgeMinFunction (const Mesh & amesh)
+      : mesh(amesh) { } ;
+
+    virtual double FuncGrad (const Vector & x, Vector & g) const;
+    virtual double Func (const Vector & x) const;
+  };
+
+  double Opti2EdgeMinFunction :: Func (const Vector & x) const
+  {
+    Vector g(x.Size());
+    return FuncGrad (x, g);
+  }
+
+  double Opti2EdgeMinFunction :: FuncGrad (const Vector & x, Vector & grad) const
+  {
+    int j, rot;
+    Vec<3> n1, n2, v1, v2, e1, e2, vgrad;
+    Point<3> pp1;
+    Vec<2> g1;
+    double badness, hbadness;
+
+    vgrad = 0.0;
+    badness = 0;
+
+    pp1 = sp1 + x.Get(1) * t1;
+    meshthis -> ProjectPoint2 (surfi, surfi2, pp1);
+
+    for (j = 0; j < locelements.Size(); j++)
+      {
+	rot = locrots[j];
+	const Element2d & bel = mesh[locelements[j]];
+
+	v1 = mesh[bel.PNumMod(rot + 1)] - pp1;
+	v2 = mesh[bel.PNumMod(rot + 2)] - pp1;
+
+	e1 = v1;
+	e2 = v2;
+	e1 /= e1.Length();
+	e2 -= (e1 * e2) * e1;
+	e2 /= e2.Length();
+
+	if (uselocalh) loch = lochs[j];
+	CalcTriangleBadness ( (e1 * v1), (e1 * v2), (e2 * v2), locmetricweight, loch,
+			      hbadness, g1(0), g1(1));
+
+	badness += hbadness;
+        vgrad += g1(0) * e1 + g1(1) * e2;
+      }
+
+    meshthis -> GetNormalVector (surfi, pp1, n1);
+    meshthis -> GetNormalVector (surfi2, pp1, n2);
+
+    v1 = Cross (n1, n2);
+    v1.Normalize();
+
+    grad(0) = (vgrad * v1) * (t1 * v1);
+
+    return badness;
+  }
+
+
+
+
+  class Opti2SurfaceMinFunctionJacobian : public MinFunction
+  {
+    const Mesh & mesh;
+  public:
+    Opti2SurfaceMinFunctionJacobian (const Mesh & amesh)
+      : mesh(amesh)
+    { } ;
+    virtual double FuncGrad (const Vector & x, Vector & g) const;
+    virtual double FuncDeriv (const Vector & x, const Vector & dir, double & deriv) const;
+    virtual double Func (const Vector & x) const;
+  };
+  
+  double Opti2SurfaceMinFunctionJacobian :: 
+  Func (const Vector & x) const
+  {
+    Vector g(x.Size());
+    return FuncGrad (x, g);
+  }
+
+
+  double Opti2SurfaceMinFunctionJacobian :: 
+  FuncGrad (const Vector & x, Vector & grad) const
+  {
+    // from 2d:
+
+    int lpi, gpi;
+    Vec<3> n, vgrad;
+    Point<3> pp1;
+    Vec2d g1, vdir;
+    double badness, hbad, hderiv;
+
+    vgrad = 0;
+    badness = 0;
+
+    meshthis -> GetNormalVector (surfi, sp1, gi1, n);
+
+    pp1 = sp1 + x(0) * t1 + x(1) * t2;
+
+    //  meshthis -> ProjectPoint (surfi, pp1);
+    //  meshthis -> GetNormalVector (surfi, pp1, n);
+
+    static ARRAY<Point2d> pts2d;
+    pts2d.SetSize(mesh.GetNP());
+
+    grad = 0;
+
+    for (int j = 1; j <= locelements.Size(); j++)
+      {
+	lpi = locrots.Get(j);
+	const Element2d & bel = 
+	  mesh[locelements.Get(j)];
+      
+	gpi = bel.PNum(lpi);
+
+	for (int k = 1; k <= bel.GetNP(); k++)
+	  {
+	    PointIndex pi = bel.PNum(k);
+	    pts2d.Elem(pi) = Point2d (t1 * (mesh.Point(pi) - sp1), 
+				      t2 * (mesh.Point(pi) - sp1)); 
+	  }				    
+	pts2d.Elem(gpi) = Point2d (x.Get(1), x.Get(2));
+      
+
+	for (int k = 1; k <= 2; k++)
+	  {
+	    if (k == 1)
+	      vdir = Vec2d (1, 0);
+	    else
+	      vdir = Vec2d (0, 1);
+	  
+	    hbad = bel.
+	      CalcJacobianBadnessDirDeriv (pts2d, lpi, vdir, hderiv);
+
+	    grad.Elem(k) += hderiv;
+	    if (k == 1)
+	      badness += hbad;
+	  }
+      }
+
+
+    /*
+      vgrad.Add (-(vgrad * n), n);
+
+      grad.Elem(1) = vgrad * t1;
+      grad.Elem(2) = vgrad * t2;
+    */
+    return badness;
+  }
+
+
+
+
+  double Opti2SurfaceMinFunctionJacobian :: 
+  FuncDeriv (const Vector & x, const Vector & dir, double & deriv) const
+  {
+    // from 2d:
+
+    int j, k, lpi, gpi;
+    Vec<3> n, vgrad;
+    Point<3> pp1;
+    Vec2d g1, vdir;
+    double badness, hbad, hderiv;
+
+    vgrad = 0;
+    badness = 0;
+
+    meshthis -> GetNormalVector (surfi, sp1, gi1, n);
+
+    // pp1 = sp1;
+    //    pp1.Add2 (x.Get(1), t1, x.Get(2), t2);
+    pp1 = sp1 + x.Get(1) * t1 + x.Get(2) * t2;
+
+    static ARRAY<Point2d> pts2d;
+    pts2d.SetSize(mesh.GetNP());
+
+    deriv = 0;
+
+    for (j = 1; j <= locelements.Size(); j++)
+      {
+	lpi = locrots.Get(j);
+	const Element2d & bel = 
+	  mesh[locelements.Get(j)];
+      
+	gpi = bel.PNum(lpi);
+
+	for (k = 1; k <= bel.GetNP(); k++)
+	  {
+	    PointIndex pi = bel.PNum(k);
+	    pts2d.Elem(pi) = Point2d (t1 * (mesh.Point(pi) - sp1), 
+				      t2 * (mesh.Point(pi) - sp1)); 
+	  }				    
+	pts2d.Elem(gpi) = Point2d (x.Get(1), x.Get(2));
+      
+
+	vdir = Vec2d (dir(0), dir(1));
+	  
+	hbad = bel.
+	  CalcJacobianBadnessDirDeriv (pts2d, lpi, vdir, hderiv);
+      
+	deriv += hderiv;
+	badness += hbad;
+      }
+
+
+    return badness;
+  }
+
+
+
+
+
+
+
+  MeshOptimize2d dummy;
+
+  MeshOptimize2d :: MeshOptimize2d ()
+  {
+    SetFaceIndex (0);
+    SetImproveEdges (0);
+    SetMetricWeight (0);
+    SetWriteStatus (1);
+  }
+
+
+  void MeshOptimize2d :: SelectSurfaceOfPoint (const Point<3> & p,
+					       const PointGeomInfo & gi)
+  {
+    ;
+  }
+
+  void MeshOptimize2d :: ImproveMesh (Mesh & mesh)
+  {
+    if (!faceindex)
+      {
+	PrintMessage (3, "Smoothing");
+
+	for (faceindex = 1; faceindex <= mesh.GetNFD(); faceindex++)
+	  {
+	    ImproveMesh (mesh);
+	    if (multithread.terminate)
+	      throw NgException ("Meshing stopped");
+	  }
+	faceindex = 0;
+	return;
+      }
+ 
+
+
+    static int timer = NgProfiler::CreateTimer ("MeshSmoothing 2D");
+    NgProfiler::RegionTimer reg (timer);
+
+
+    CheckMeshApproximation (mesh);
+
+    SurfaceElementIndex sei;
+
+    ARRAY<SurfaceElementIndex> seia;
+    mesh.GetSurfaceElementsOfFace (faceindex, seia);
+
+    bool mixed = 0;
+    for (int i = 0; i < seia.Size(); i++)
+      if (mesh[seia[i]].GetNP() != 3)
+	{
+	  mixed = 1;
+	  break;
+	}
+
+    int loci;
+    double fact;
+    int moveisok;
+
+    PointGeomInfo ngi;
+    Point3d origp;
+
+    Vec3d n1, n2;
+    Vector x(2), xedge(1);
+
+    ARRAY<MeshPoint, PointIndex::BASE> savepoints(mesh.GetNP());
+    uselocalh = mparam.uselocalh;
+
+    ARRAY<int, PointIndex::BASE> nelementsonpoint(mesh.GetNP());
+
+    nelementsonpoint = 0;
+    for (int i = 0; i < seia.Size(); i++)
+      {
+	const Element2d & el = mesh[seia[i]];
+	for (int j = 0; j < el.GetNP(); j++)
+	  nelementsonpoint[el[j]]++;
+      }
+
+    TABLE<SurfaceElementIndex,PointIndex::BASE> elementsonpoint(nelementsonpoint);
+    for (int i = 0; i < seia.Size(); i++)
+      {
+	const Element2d & el = mesh[seia[i]];
+	for (int j = 0; j < el.GetNP(); j++)
+	  elementsonpoint.Add (el[j], seia[i]);
+      }
+
+    loch = mparam.maxh;
+    locmetricweight = metricweight;
+    meshthis = this;
+
+    Opti2SurfaceMinFunction surfminf(mesh);
+    Opti2EdgeMinFunction edgeminf(mesh);
+    Opti2SurfaceMinFunctionJacobian surfminfj(mesh);
+
+    OptiParameters par;
+    par.maxit_linsearch = 8;
+    par.maxit_bfgs = 5;
+
+    /*
+    int i, j, k;
+
+      if (improveedges)
+      for (i = 1; i <= mesh.GetNP(); i++)
+      if (mesh.PointType(i) == EDGEPOINT)
+      {
+      continue;
+      PrintDot ();
+      sp1 = mesh.Point(i);
+	  
+      locelements.SetSize(0);
+      locrots.SetSize (0);
+      lochs.SetSize (0);
+      surfi = surfi2 = surfi3 = 0;
+	  
+      for (j = 0; j < elementsonpoint[i].Size(); j++)
+      {
+      sei = elementsonpoint[i][j];
+      const Element2d * bel = &mesh[sei];
+	      
+      if (!surfi)
+      surfi = mesh.GetFaceDescriptor(bel->GetIndex()).SurfNr();
+      else if (surfi != mesh.GetFaceDescriptor(bel->GetIndex()).SurfNr())
+      {
+      if (surfi2 != 0 && surfi2 != 
+      mesh.GetFaceDescriptor(bel->GetIndex()).SurfNr())
+      surfi3 = mesh.GetFaceDescriptor(bel->GetIndex()).SurfNr();
+      else
+      surfi2 = mesh.GetFaceDescriptor(bel->GetIndex()).SurfNr();
+      }
+	      
+      locelements.Append (sei);
+	      
+      if (bel->PNum(1) == i)
+      locrots.Append (1);
+      else if (bel->PNum(2) == i)
+      locrots.Append (2);
+      else
+      locrots.Append (3);
+
+      if (uselocalh)
+      {
+      Point3d pmid = Center (mesh.Point(bel->PNum(1)),
+      mesh.Point(bel->PNum(2)),
+      mesh.Point(bel->PNum(3)));
+      lochs.Append (mesh.GetH(pmid));
+      }
+      }
+	  
+      if (surfi2 && !surfi3)
+      {
+      GetNormalVector (surfi, sp1, n1);
+      GetNormalVector (surfi2, sp1, n2);
+      t1 = Cross (n1, n2);
+	      
+      xedge = 0;
+      BFGS (xedge, edgeminf, par, 1e-6);
+	      
+      mesh.Point(i).X() += xedge.Get(1) * t1.X();
+      mesh.Point(i).Y() += xedge.Get(1) * t1.Y();
+      mesh.Point(i).Z() += xedge.Get(1) * t1.Z();
+      ProjectPoint2 (surfi, surfi2, mesh.Point(i));
+      }
+      }
+    */
+
+
+    bool printeddot = 0;
+    char plotchar = '.';
+    int modplot = 1;
+    if (mesh.GetNP() > 1000)
+      {
+	plotchar = '+';
+	modplot = 10;
+      }
+    if (mesh.GetNP() > 10000)
+      {
+	plotchar = 'o';
+	modplot = 100;
+      }
+    int cnt = 0;
+
+    for (PointIndex pi = PointIndex::BASE; pi < mesh.GetNP()+PointIndex::BASE; pi++)
+      if (mesh[pi].Type() == SURFACEPOINT)
+	{
+	  if (multithread.terminate)
+	    throw NgException ("Meshing stopped");
+	
+	  cnt++;
+	  if (cnt % modplot == 0 && writestatus)
+	    {
+	      printeddot = 1;
+	      PrintDot (plotchar);
+	    }
+	
+	  if (elementsonpoint[pi].Size() == 0)
+	    continue;
+	
+	  sp1 = mesh[pi];
+
+	  Element2d & hel = mesh[elementsonpoint[pi][0]];
+
+	  int hpi = 0;
+	  for (int j = 1; j <= hel.GetNP(); j++)
+	    if (hel.PNum(j) == pi)
+	      {
+		hpi = j;
+		break;
+	      }
+
+	  gi1 = hel.GeomInfoPi(hpi);
+	  SelectSurfaceOfPoint (sp1, gi1);
+	  
+	  locelements.SetSize(0);
+	  locrots.SetSize (0);
+	  lochs.SetSize (0);
+	
+	  for (int j = 0; j < elementsonpoint[pi].Size(); j++)
+	    {
+	      sei = elementsonpoint[pi][j];
+	      const Element2d & bel = mesh[sei];
+	      surfi = mesh.GetFaceDescriptor(bel.GetIndex()).SurfNr();
+	    
+	      locelements.Append (sei);
+	    
+	      for (int k = 1; k <= bel.GetNP(); k++)
+		if (bel.PNum(k) == pi)
+		  {
+		    locrots.Append (k);
+		    break;
+		  }
+	      
+	      if (uselocalh)
+		{
+		  Point3d pmid = Center (mesh[bel[0]], mesh[bel[1]], mesh[bel[2]]);
+		  lochs.Append (mesh.GetH(pmid));
+		}
+	    }
+	  
+	  GetNormalVector (surfi, sp1, gi1, normal);
+	  t1 = normal.GetNormal ();
+	  t2 = Cross (normal, t1);
+	  
+	  // save points, and project to tangential plane
+	  for (int j = 0; j < locelements.Size(); j++)
+	    {
+	      const Element2d & el = mesh[locelements[j]];
+	      for (int k = 0; k < el.GetNP(); k++)
+		savepoints[el[k]] = mesh[el[k]];
+	    }
+
+	  for (int j = 0; j < locelements.Size(); j++)
+	    {
+	      const Element2d & el = mesh[locelements[j]];
+	      for (int k = 0; k < el.GetNP(); k++)
+		{
+		  PointIndex hhpi = el[k];
+		  double lam = normal * (mesh[hhpi] - sp1);
+		  mesh[hhpi] -= lam * normal;
+		}
+	    }
+	  
+	  x = 0;
+	  par.typx = lochs[0];
+
+	  if (mixed)
+	    {
+	      //	      (*testout) << "vorher : " << surfminfj.Func (x) << endl;
+	      BFGS (x, surfminfj, par, 1e-6);
+	      //	      (*testout) << "nachher: " << surfminfj.Func (x) << endl;
+	      //	      (*testout) << "x = " << x << endl;
+	    }
+	  else
+	    {
+	      //	      (*testout) << "vorher : " << surfminf.Func (x) << endl;
+	      BFGS (x, surfminf, par, 1e-6);
+	      //	      (*testout) << "nachher: " << surfminf.Func (x) << endl;
+	      //	      (*testout) << "x = " << x << endl;
+	    }
+
+	
+	  origp = mesh[pi];
+	  loci = 1;
+	  fact = 1;
+	  moveisok = 0;
+
+	  // restore other points
+	  for (int j = 0; j < locelements.Size(); j++)
+	    {
+	      const Element2d & el = mesh[locelements[j]];
+	      for (int k = 0; k < el.GetNP(); k++)
+		{
+		  PointIndex hhpi = el[k];
+		  if (hhpi != pi) mesh[hhpi] = savepoints[hhpi];
+		}
+	    }
+
+	  
+	  //optimizer loop (if whole distance is not possible, move only a bit!!!!)
+	  while (loci <= 5 && !moveisok)
+	    {
+	      loci ++;
+              /*
+	      mesh[pi].X() = origp.X() + (x.Get(1) * t1.X() + x.Get(2) * t2.X())*fact;
+	      mesh[pi].Y() = origp.Y() + (x.Get(1) * t1.Y() + x.Get(2) * t2.Y())*fact;
+	      mesh[pi].Z() = origp.Z() + (x.Get(1) * t1.Z() + x.Get(2) * t2.Z())*fact;
+              */
+              Vec<3> hv = x(0) * t1 + x(1) * t2;
+              Point3d hnp = origp + Vec3d (hv);
+              mesh[pi](0) = hnp.X();
+              mesh[pi](1) = hnp.Y();
+              mesh[pi](2) = hnp.Z();
+
+	      fact = fact/2.;
+
+	      // ProjectPoint (surfi, mesh[pi]);
+	      // moveisok = CalcPointGeomInfo(surfi, ngi, mesh[pi]); 
+
+	      ngi = gi1;
+	      moveisok = ProjectPointGI (surfi, mesh[pi], ngi);
+	      // point lies on same chart in stlsurface
+	    
+	      if (moveisok)
+		{
+		  for (int j = 0; j < locelements.Size(); j++)
+		    mesh[locelements[j]].GeomInfoPi(locrots[j]) = ngi;
+		}
+	      else
+		{
+		  mesh[pi] = Point<3> (origp);
+		}
+	    
+	    }
+	}
+
+    if (printeddot)
+      PrintDot ('\n');
+  
+    CheckMeshApproximation (mesh);
+    mesh.SetNextTimeStamp();
+  }
+
+  void MeshOptimize2d :: GetNormalVector(INDEX /* surfind */, const Point<3> & p, Vec<3> & nv) const
+  {
+    nv = Vec<3> (0, 0, 1);
+  }
+
+  void MeshOptimize2d :: GetNormalVector(INDEX surfind, const Point<3> & p, PointGeomInfo & gi, Vec<3> & n) const
+  {
+    GetNormalVector (surfind, p, n);
+  }
+}
diff --git a/contrib/Netgen/libsrc/meshing/smoothing3.cpp b/contrib/Netgen/libsrc/meshing/smoothing3.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..55b3ad9ef4254afd2469758e1e9ac6226d2d72ff
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/smoothing3.cpp
@@ -0,0 +1,1878 @@
+#include <mystdlib.h>
+
+#include "meshing.hpp"
+#ifdef SOLIDGEOM
+#include <csg.hpp>
+#endif
+#include <opti.hpp>
+
+
+namespace netgen
+{
+  
+
+  double MinFunctionSum :: Func (const Vector & x) const
+  {
+    double retval = 0;
+    for(int i=0; i<functions.Size(); i++)
+      retval += functions[i]->Func(x);
+      
+    return retval;
+  }
+
+  void MinFunctionSum :: Grad (const Vector & x, Vector & g) const
+  {
+    g = 0.;
+    static Vector gi(3);
+    for(int i=0; i<functions.Size(); i++)
+      {
+	functions[i]->Grad(x,gi);
+	for(int j=0; j<g.Size(); j++)
+	  g[j] += gi[j];
+      }
+  }
+      
+
+  double MinFunctionSum :: FuncGrad (const Vector & x, Vector & g) const
+  {
+    double retval = 0;
+    g = 0.;
+    static Vector gi(3);
+    for(int i=0; i<functions.Size(); i++)
+      {
+	retval += functions[i]->FuncGrad(x,gi);
+	for(int j=0; j<g.Size(); j++)
+	  g[j] += gi[j];
+      }
+    return retval;
+  }
+
+  double MinFunctionSum :: FuncDeriv (const Vector & x, const Vector & dir, double & deriv) const
+  {
+    double retval = 0;
+    deriv = 0.;
+    double derivi;
+    for(int i=0; i<functions.Size(); i++)
+      {
+	retval += functions[i]->FuncDeriv(x,dir,derivi);
+	deriv += derivi;
+      }
+    return retval;
+  }
+
+  double MinFunctionSum :: GradStopping (const Vector & x) const
+  {
+    double minfs(0), mini;
+    for(int i=0; i<functions.Size(); i++)
+      {
+	mini = functions[i]->GradStopping(x);
+	if(i==0 || mini < minfs)
+	  minfs = mini;
+      }
+    return minfs;
+  }
+
+
+  void MinFunctionSum :: AddFunction(MinFunction & fun)
+  {
+    functions.Append(&fun);
+  }
+  
+  const MinFunction & MinFunctionSum :: Function(int i) const
+  {
+    return *functions[i];
+  }
+  MinFunction & MinFunctionSum :: Function(int i)
+  {
+    return *functions[i];
+  }
+
+
+  PointFunction1 :: PointFunction1 (Mesh::T_POINTS & apoints, 
+				    const ARRAY<INDEX_3> & afaces,
+				    double ah)
+    : points(apoints), faces(afaces)
+  {
+    h = ah;
+  }
+  
+
+  double PointFunction1 :: Func (const Vector & vp) const
+  {
+    double badness = 0;
+    Point<3> pp(vp(0), vp(1), vp(2));
+
+    for (int j = 0; j < faces.Size(); j++)
+      {
+	const INDEX_3 & el = faces[j];
+
+	double bad = CalcTetBadness (points[el.I1()], 
+				     points[el.I3()], 
+				     points[el.I2()], 
+				     pp, 0);
+	badness += bad;
+      }
+ 
+    return badness;
+  }
+
+
+  double PointFunction1 :: 
+  FuncDeriv (const Vector & x, const Vector & dir, double & deriv) const
+  {
+    static Vector hx(3);
+    static double eps = 1e-6;
+
+    double dirlen = dir.L2Norm();
+    if (dirlen < 1e-14)
+      {
+	deriv = 0;
+	return Func(x);
+      }
+
+    hx.Set(1, x);
+    hx.Add(eps * h / dirlen, dir);
+    double fr = Func (hx);
+    hx.Set(1, x);
+    hx.Add(-eps * h / dirlen, dir);
+    double fl = Func (hx);
+
+    deriv = (fr - fl) / (2 * eps * h) * dirlen;
+
+    return Func(x);
+  }
+
+
+  double PointFunction1 :: FuncGrad (const Vector & x, Vector & g) const
+  {
+    static Vector hx(3);
+    static double eps = 1e-6;
+
+    hx = x;
+    for (int i = 1; i <= 3; i++)
+      {
+	hx.Elem(i) = x.Get(i) + eps * h;
+	double fr = Func (hx);
+	hx.Elem(i) = x.Get(i) - eps * h;
+	double fl = Func (hx);
+	hx.Elem(i) = x.Get(i);
+
+	g.Elem(i) = (fr - fl) / (2 * eps * h);
+      }
+
+    return Func(x);
+  }
+
+  double PointFunction1 :: GradStopping (const Vector & x) const
+  {
+    double f = Func(x);
+    return 1e-8 * f * f;
+  }
+
+
+
+
+  /* Cheap Functional depending of inner point inside triangular surface */
+
+  // is it used ????
+  class CheapPointFunction1 : public MinFunction
+  {
+    Mesh::T_POINTS & points;
+    const ARRAY<INDEX_3> & faces;
+    DenseMatrix m;
+    double h;
+  public:
+    CheapPointFunction1 (Mesh::T_POINTS & apoints, 
+			 const ARRAY<INDEX_3> & afaces,
+			 double ah);
+  
+    virtual double Func (const Vector & x) const;
+    virtual double FuncGrad (const Vector & x, Vector & g) const;
+  };
+
+  CheapPointFunction1 :: CheapPointFunction1 (Mesh::T_POINTS & apoints, 
+					      const ARRAY<INDEX_3> & afaces,
+					      double ah)
+    : points(apoints), faces(afaces)
+  {
+    h = ah;
+  
+
+    int nf = faces.Size();
+
+    m.SetSize (nf, 4);
+  
+    for (int i = 1; i <= nf; i++)
+      {
+	const Point3d & p1 = points[faces.Get(i).I1()];
+	const Point3d & p2 = points[faces.Get(i).I2()];
+	const Point3d & p3 = points[faces.Get(i).I3()];
+	Vec3d v1 (p1, p2);
+	Vec3d v2 (p1, p3);
+	Vec3d n;
+	Cross (v1, v2, n);
+	n /= n.Length();
+
+	m.Elem(i, 1) = n.X();
+	m.Elem(i, 2) = n.Y();
+	m.Elem(i, 3) = n.Z();
+	m.Elem(i, 4) = - (n.X() * p1.X() + n.Y() * p1.Y() + n.Z() * p1.Z());
+      } 
+  }
+  
+  double CheapPointFunction1 :: Func (const Vector & vp) const
+  {
+
+    /*
+      int j;
+      double badness = 0;
+      Point3d pp(vp.Get(1), vp.Get(2), vp.Get(3));
+
+      for (j = 1; j <= faces.Size(); j++)
+      {
+      const INDEX_3 & el = faces.Get(j);
+
+      double bad = CalcTetBadness (points.Get(el.I1()), 
+      points.Get(el.I3()), 
+      points.Get(el.I2()), 
+      pp, 0);
+      badness += bad;
+      }
+    */
+
+    int i;
+    double badness = 0;
+    static Vector hv(4);
+    static Vector res;
+    res.SetSize (m.Height());
+
+    for (i = 1;i <= 3; i++)
+      hv.Elem(i) = vp.Get(i);
+    hv.Elem(4) = 1;
+    m.Mult (hv, res);
+
+    for (i = 1; i <= res.Size(); i++)
+      {
+	if (res.Get(i) < 1e-10)
+	  badness += 1e24;
+	else
+	  badness += 1 / res.Get(i);
+      }
+ 
+    return badness;
+  }
+
+
+  double CheapPointFunction1 :: FuncGrad (const Vector & x, Vector & g) const
+  {
+    static Vector hx(3);
+    static double eps = 1e-6;
+
+    hx = x;
+    for (int i = 1; i <= 3; i++)
+      {
+	hx.Elem(i) = x.Get(i) + eps * h;
+	double fr = Func (hx);
+	hx.Elem(i) = x.Get(i) - eps * h;
+	double fl = Func (hx);
+	hx.Elem(i) = x.Get(i);
+
+	g.Elem(i) = (fr - fl) / (2 * eps * h);
+      }
+
+    return Func(x);
+  }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+  /* ************* PointFunction **************************** */
+
+
+  class PointFunction 
+  {
+  public:
+    Mesh::T_POINTS & points;
+    const Mesh::T_VOLELEMENTS & elements;
+    TABLE<INDEX,PointIndex::BASE> elementsonpoint;
+    PointIndex actpind;
+    double h;
+  
+  public:
+    PointFunction (Mesh::T_POINTS & apoints, 
+		   const Mesh::T_VOLELEMENTS & aelements);
+  
+    virtual void SetPointIndex (PointIndex aactpind);
+    void SetLocalH (double ah) { h = ah; }
+    double GetLocalH () const { return h; }
+    virtual double PointFunctionValue (const Point<3> & pp) const;
+    virtual double PointFunctionValueGrad (const Point<3> & pp, Vec<3> & grad) const;
+    virtual double PointFunctionValueDeriv (const Point<3> & pp, const Vec<3> & dir, double & deriv) const;
+
+    int MovePointToInner ();
+  };
+
+
+  PointFunction :: PointFunction (Mesh::T_POINTS & apoints, 
+				  const Mesh::T_VOLELEMENTS & aelements)
+    : points(apoints), elements(aelements), elementsonpoint(apoints.Size())
+  {
+    INDEX i;
+    int j;
+  
+    for (i = 1; i <= elements.Size(); i++)
+      {
+	if (elements.Get(i).NP() == 4)
+	  for (j = 1; j <= elements.Get(i).NP(); j++)
+	    elementsonpoint.Add (elements.Get(i).PNum(j), i);  
+      }
+  }
+
+  void PointFunction :: SetPointIndex (PointIndex aactpind)
+  {
+    actpind = aactpind; 
+  }  
+
+  double PointFunction :: PointFunctionValue (const Point<3> & pp) const
+  {
+    int j;
+    INDEX eli;
+    const Element * el;
+    double badness;
+    //  ARRAY<const Point3d*> p(4);
+    Point<3> hp;
+
+    badness = 0;
+
+    hp = points[actpind];
+    points[actpind] = Point<3> (pp);
+
+    for (j = 0; j < elementsonpoint[actpind].Size(); j++)
+      {
+	eli = elementsonpoint[actpind][j];
+	el = &elements.Get(eli);
+	badness += CalcTetBadness (points[el->PNum(1)], 
+				   points[el->PNum(2)], 
+				   points[el->PNum(3)], 
+				   points[el->PNum(4)], -1);
+      }
+  
+    points[actpind] = Point<3> (hp); 
+    return badness;
+  }
+
+
+  double PointFunction :: PointFunctionValueGrad (const Point<3> & pp, Vec<3> & grad) const
+  {
+    double f;//, delta = h * 1e-6;
+    // Point<3> hpp;
+
+    f = PointFunctionValue (pp);
+
+    /*
+      hpp = pp;
+      hpp.X() = pp.X() + delta;
+      fr = PointFunctionValue (hpp);
+      hpp.X() = pp.X() - delta;
+      fl = PointFunctionValue (hpp);
+      grad.Elem(1) = (fr - fl) / (2 * delta);
+
+      hpp = pp;
+      hpp.Y() = pp.Y() + delta;
+      fr = PointFunctionValue (hpp);
+      hpp.Y() = pp.Y() - delta;
+      fl = PointFunctionValue (hpp);
+      grad.Elem(2) = (fr - fl) / (2 * delta);
+
+      hpp = pp;
+      hpp.Z() = pp.Z() + delta;
+      fr = PointFunctionValue (hpp);
+      hpp.Z() = pp.Z() - delta;
+      fl = PointFunctionValue (hpp);
+      grad.Elem(3) = (fr - fl) / (2 * delta);
+    */
+
+
+    // new gradient calculation
+    //  double badness;
+    Point<3> hp;
+    Vec<3> vgradi, vgrad(0,0,0);
+
+    //  badness = 0;
+
+    hp = points[actpind];
+    points[actpind] = Point<3> (pp);
+
+    for (int j = 0; j < elementsonpoint[actpind].Size(); j++)
+      {
+	INDEX eli = elementsonpoint[actpind][j];
+	const Element & el = elements.Get(eli);
+
+	for (int k = 1; k <= 4; k++)
+	  if (el.PNum(k) == actpind)
+	    {
+	      CalcTetBadnessGrad (points[el.PNum(1)], 
+				  points[el.PNum(2)], 
+				  points[el.PNum(3)], 
+				  points[el.PNum(4)], -1, k, vgradi);
+
+	      vgrad += vgradi;
+	    }
+      }
+
+    points[actpind] = Point<3> (hp); 
+
+    grad = vgrad;
+    return f;
+  }
+
+
+  double PointFunction :: PointFunctionValueDeriv (const Point<3> & pp, const Vec<3> & dir,
+						   double & deriv) const
+  {
+    double f;
+    // Point<3> hpp;
+
+    Vec<3> dirn (dir);
+    //double ldir = dir.Length();
+
+    int j, k;
+    INDEX eli;
+    //  double badness;
+    Point<3> hp;
+    Vec<3> vgradi, vgrad(0,0,0);
+
+    //  badness = 0;
+
+    hp = points[actpind];
+    points[actpind] = pp;
+    f = 0;
+
+    for (j = 0; j < elementsonpoint[actpind].Size(); j++)
+      {
+	eli = elementsonpoint[actpind][j];
+	const Element & el = elements.Get(eli);
+
+	for (k = 1; k <= 4; k++)
+	  if (el.PNum(k) == actpind)
+	    {
+	      f += CalcTetBadnessGrad (points[el.PNum(1)], 
+				       points[el.PNum(2)], 
+				       points[el.PNum(3)], 
+				       points[el.PNum(4)], -1, k, vgradi);
+
+	      vgrad += vgradi;
+	    }
+      }
+
+    points[actpind] = Point<3> (hp); 
+    deriv = dir * vgrad;
+    return f;
+  }
+
+  int PointFunction :: MovePointToInner ()
+  {
+    // try point movement 
+    ARRAY<Element2d> faces;
+  
+    for (int j = 0; j < elementsonpoint[actpind].Size(); j++)
+      {
+	const Element & el = 
+	  elements.Get(elementsonpoint[actpind][j]);
+      
+	for (int k = 1; k <= 4; k++)
+	  if (el.PNum(k) == actpind)
+	    {
+	      Element2d face;
+	      el.GetFace (k, face);
+	      Swap (face.PNum(2), face.PNum(3));
+	      faces.Append (face);
+	    }
+      }
+  
+    Point3d hp;
+    int hi = FindInnerPoint (points, faces, hp);
+    if (hi)
+      {
+	// cout << "inner point found" << endl;
+	points[actpind] = Point<3> (hp);
+      }
+    else
+      ;
+    //      cout << "no inner point found" << endl;
+
+    /*
+    Point3d hp2;
+    int hi2 = FindInnerPoint (points, faces, hp2);
+    if (hi2)
+      {
+	cout << "new: inner point found" << endl;
+      }
+    else
+      cout << "new: no inner point found" << endl;
+  
+    (*testout) << "hi(orig) = " << hi << ", hi(new) = " << hi2;
+    if (hi != hi2) (*testout) << "hi different" << endl;
+    */
+
+    return hi;
+  }
+
+
+
+
+
+
+  class CheapPointFunction : public PointFunction
+  {
+    DenseMatrix m;
+  public:
+    CheapPointFunction (Mesh::T_POINTS & apoints, 
+			const Mesh::T_VOLELEMENTS & aelements);
+    virtual void SetPointIndex (PointIndex aactpind);
+    virtual double PointFunctionValue (const Point<3> & pp) const;
+    virtual double PointFunctionValueGrad (const Point<3> & pp, Vec<3> & grad) const;
+  };
+
+
+  CheapPointFunction :: CheapPointFunction (Mesh::T_POINTS & apoints, 
+					    const Mesh::T_VOLELEMENTS & aelements)
+    : PointFunction (apoints, aelements)
+  {
+    ;
+  }
+
+
+  void CheapPointFunction :: SetPointIndex (PointIndex aactpind)
+  {
+    actpind = aactpind; 
+
+    int ne = elementsonpoint[actpind].Size();
+    int i, j;
+    int pi1, pi2, pi3;
+
+    m.SetSize (ne, 4);
+
+    for (i = 0; i < ne; i++)
+      {
+	pi1 = 0;
+	pi2 = 0;
+	pi3 = 0;
+
+	const Element & el = elements.Get (elementsonpoint[actpind][i]);
+	for (j = 1; j <= 4; j++)
+	  if (el.PNum(j) != actpind)
+	    {
+	      pi3 = pi2;
+	      pi2 = pi1;
+	      pi1 = el.PNum(j);
+	    }
+
+	const Point3d & p1 = points[pi1];
+	Vec3d v1 (p1, points[pi2]);
+	Vec3d v2 (p1, points[pi3]);
+	Vec3d n;
+	Cross (v1, v2, n);
+	n /= n.Length();
+
+	Vec3d v (p1, points[actpind]);
+	double c = v * n;
+      
+	if (c < 0)
+	  n *= -1;    
+      
+	// n is inner normal
+
+	m.Elem(i+1, 1) = n.X();
+	m.Elem(i+1, 2) = n.Y();
+	m.Elem(i+1, 3) = n.Z();
+	m.Elem(i+1, 4) = - (n.X() * p1.X() + n.Y() * p1.Y() + n.Z() * p1.Z());
+      }
+  }
+
+  double CheapPointFunction :: PointFunctionValue (const Point<3> & pp) const
+  {
+    static Vector p4(4);
+    static Vector di;
+    int n = m.Height();
+
+    p4.Elem(1) = pp(0);
+    p4.Elem(2) = pp(1);
+    p4.Elem(3) = pp(2);
+    p4.Elem(4) = 1;
+
+    di.SetSize (n);
+    m.Mult (p4, di);
+  
+    double sum = 0;
+    for (int i = 1; i <= n; i++)
+      {
+	if (di.Get(i) > 0)
+	  sum += 1 / di.Get(i);
+	else
+	  return 1e16;
+      }
+    return sum;
+  }
+
+
+
+
+  double CheapPointFunction :: PointFunctionValueGrad (const Point<3> & pp, Vec<3> & grad) const
+  {
+    static Vector p4(4);
+    static Vector di;
+
+    int n = m.Height();
+
+    p4.Elem(1) = pp(0);
+    p4.Elem(2) = pp(1);
+    p4.Elem(3) = pp(2);
+    p4.Elem(4) = 1;
+
+    di.SetSize (n);
+    m.Mult (p4, di);
+  
+    double sum = 0;
+    grad = 0;
+    for (int i = 1; i <= n; i++)
+      {
+	if (di.Get(i) > 0)
+	  {
+	    double idi = 1 / di.Get(i);
+	    sum += idi;
+	    grad(0) -= idi * idi * m.Get(i, 1);
+	    grad(1) -= idi * idi * m.Get(i, 2);
+	    grad(2) -= idi * idi * m.Get(i, 3);
+	  }
+	else
+	  {
+	    return 1e16;
+	  }
+      }
+    return sum;
+  }
+
+
+
+
+
+
+
+
+  class Opti3FreeMinFunction : public MinFunction
+  { 
+    const PointFunction & pf;
+    Point<3> sp1;
+  
+  public:
+    Opti3FreeMinFunction (const PointFunction & apf);
+    void SetPoint (const Point<3> & asp1) { sp1 = asp1; }
+    virtual double Func (const Vector & x) const;
+    virtual double FuncGrad (const Vector & x, Vector & g) const;
+    virtual double FuncDeriv (const Vector & x, const Vector & dir, double & deriv) const;  
+    virtual double GradStopping (const Vector & x) const;
+    virtual void ApproximateHesse (const Vector & x,
+				   DenseMatrix & hesse) const;
+  };
+
+  Opti3FreeMinFunction :: Opti3FreeMinFunction (const PointFunction & apf)
+    : pf(apf)
+  {
+    ;
+  }
+
+  double Opti3FreeMinFunction :: Func (const Vector & x) const
+  {
+    Point<3> pp;
+    for (int j = 0; j < 3; j++)
+      pp(j) = sp1(j) + x(j);
+    return pf.PointFunctionValue (pp);
+  }
+  
+  double Opti3FreeMinFunction :: FuncGrad (const Vector & x, Vector & grad) const
+  {
+    Vec<3> vgrad;
+    Point<3> pp;
+
+    for (int j = 0; j < 3; j++)
+      pp(j) = sp1(j) + x(j);
+
+    double val = pf.PointFunctionValueGrad (pp, vgrad);
+
+    for (int j = 0; j < 3; j++)
+      grad(j) = vgrad(j);
+
+    return val;
+  }
+
+  double Opti3FreeMinFunction :: FuncDeriv (const Vector & x, const Vector & dir, double & deriv) const
+  {
+    Point<3> pp;
+
+    for (int j = 0; j < 3; j++)
+      pp(j) = sp1(j) + x(j);
+
+    Vec<3> vdir;
+    for (int j = 0; j < 3; j++)
+      vdir(j) = dir(j);
+
+    return pf.PointFunctionValueDeriv (pp, vdir, deriv);
+  }
+  
+  double Opti3FreeMinFunction :: GradStopping (const Vector & x) const
+  {
+    double f = Func(x);
+    return 1e-3 * f / pf.GetLocalH();
+  }
+
+
+  void Opti3FreeMinFunction :: ApproximateHesse (const Vector & x,
+						 DenseMatrix & hesse) const
+  {
+    int n = x.Size();
+
+    static Vector hx;
+    hx.SetSize(n);
+
+    double eps = 1e-8;
+    double f, f11, f22; //, f12, f21
+
+    f = Func(x);
+  
+    for (int i = 1; i <= n; i++)
+      {
+	for (int j = 1; j < i; j++)
+	  {
+	    /*
+	      hx = x;
+	      hx.Elem(i) = x.Get(i) + eps;
+	      hx.Elem(j) = x.Get(j) + eps;
+	      f11 = Func(hx);
+	      hx.Elem(i) = x.Get(i) + eps;
+	      hx.Elem(j) = x.Get(j) - eps;
+	      f12 = Func(hx);
+	      hx.Elem(i) = x.Get(i) - eps;
+	      hx.Elem(j) = x.Get(j) + eps;
+	      f21 = Func(hx);
+	      hx.Elem(i) = x.Get(i) - eps;
+	      hx.Elem(j) = x.Get(j) - eps;
+	      f22 = Func(hx);
+	    */
+	    hesse.Elem(i, j) = hesse.Elem(j, i) = 0;
+	    //	    (f11 + f22 - f12 - f21) / (2 * eps * eps);
+	  }
+
+	hx = x;
+	hx.Elem(i) = x.Get(i) + eps;
+	f11 = Func(hx);
+	hx.Elem(i) = x.Get(i) - eps;
+	f22 = Func(hx);
+
+	hesse.Elem(i, i) = (f11 + f22 - 2 * f) / (eps * eps) + 1e-12;
+      }
+  }
+
+
+
+
+
+
+#ifdef SOLIDGEOM
+  class Opti3SurfaceMinFunction : public MinFunction
+  {
+    const PointFunction & pf;
+    Point3d sp1;
+    const Surface * surf;
+    Vec3d t1, t2;
+  
+  public:
+    Opti3SurfaceMinFunction (const PointFunction & apf);
+  
+    void SetPoint (const Surface * asurf, const Point3d & asp1);
+
+    void CalcNewPoint (const Vector & x, Point3d & np) const; 
+    virtual double Func (const Vector & x) const;
+    virtual double FuncGrad (const Vector & x, Vector & g) const;
+  };
+
+
+  Opti3SurfaceMinFunction :: Opti3SurfaceMinFunction (const PointFunction & apf)
+    : MinFunction(), pf(apf)
+  {
+    ;
+  }
+
+  void Opti3SurfaceMinFunction :: SetPoint (const Surface * asurf, const Point3d & asp1)
+  { 
+    Vec3d n;
+    sp1 = asp1; 
+    surf = asurf;
+  
+    Vec<3> hn;
+    surf -> GetNormalVector (sp1, hn);
+    n = hn;
+
+    n.GetNormal (t1);
+    t1 /= t1.Length();
+    t2 = Cross (n, t1);
+  }
+
+  
+  void Opti3SurfaceMinFunction :: CalcNewPoint (const Vector & x, 
+						Point3d & np) const
+  {
+    np.X() = sp1.X() + x.Get(1) * t1.X() + x.Get(2) * t2.X();
+    np.Y() = sp1.Y() + x.Get(1) * t1.Y() + x.Get(2) * t2.Y();
+    np.Z() = sp1.Z() + x.Get(1) * t1.Z() + x.Get(2) * t2.Z();
+
+    Point<3> hnp = np;
+    surf -> Project (hnp);
+    np = hnp;
+  }
+
+
+  double Opti3SurfaceMinFunction :: Func (const Vector & x) const
+  {
+    Point3d pp1;
+
+    CalcNewPoint (x, pp1);
+    return pf.PointFunctionValue (pp1);
+  }
+
+
+
+  double Opti3SurfaceMinFunction :: FuncGrad (const Vector & x, Vector & grad) const
+  {
+    Vec3d n, vgrad;
+    Point3d pp1;
+    double badness;
+    static Vector freegrad(3);
+
+    CalcNewPoint (x, pp1);
+
+    badness = pf.PointFunctionValueGrad (pp1, freegrad);
+    vgrad.X() = freegrad.Get(1);
+    vgrad.Y() = freegrad.Get(2);
+    vgrad.Z() = freegrad.Get(3);
+
+    Vec<3> hn;
+    surf -> GetNormalVector (pp1, hn);
+    n = hn;
+
+    vgrad -= (vgrad * n) * n;
+
+    grad.Elem(1) = vgrad * t1;
+    grad.Elem(2) = vgrad * t2;
+    
+    return badness;
+  }
+#endif
+  
+  
+  
+
+
+  
+  
+  
+#ifdef SOLIDGEOM
+  class Opti3EdgeMinFunction : public MinFunction
+  {
+    const PointFunction & pf;
+    Point3d sp1;
+    const Surface *surf1, *surf2;
+    Vec3d t1;
+  
+  public:
+    Opti3EdgeMinFunction (const PointFunction & apf);
+  
+    void SetPoint (const Surface * asurf1, const Surface * asurf2,
+		   const Point3d & asp1);
+    void CalcNewPoint (const Vector & x, Point3d & np) const; 
+    virtual double FuncGrad (const Vector & x, Vector & g) const;
+    virtual double Func (const Vector & x) const;
+  };
+
+  Opti3EdgeMinFunction :: Opti3EdgeMinFunction (const PointFunction & apf)
+    : MinFunction(), pf(apf)
+  {
+    ;
+  }
+  
+  void Opti3EdgeMinFunction :: SetPoint (const Surface * asurf1, 
+					 const Surface * asurf2, 
+					 const Point3d & asp1) 
+  { 
+    Vec3d n1, n2;
+    sp1 = asp1; 
+    surf1 = asurf1;
+    surf2 = asurf2;
+
+    Vec<3> hn1, hn2;
+    surf1 -> GetNormalVector (sp1, hn1);
+    surf2 -> GetNormalVector (sp1, hn2);
+    n1 = hn1;
+    n2 = hn2;
+    t1 = Cross (n1, n2);
+  }
+
+  void Opti3EdgeMinFunction :: CalcNewPoint (const Vector & x,
+					     Point3d & np) const
+{
+  np.X() = sp1.X() + x.Get(1) * t1.X();
+  np.Y() = sp1.Y() + x.Get(1) * t1.Y();
+  np.Z() = sp1.Z() + x.Get(1) * t1.Z();
+  Point<3> hnp = np;
+  ProjectToEdge (surf1, surf2, hnp);
+  np = hnp;
+}   
+
+double Opti3EdgeMinFunction :: Func (const Vector & x) const
+{
+  Vector g(x.Size());
+  return FuncGrad (x, g);
+}
+
+
+double Opti3EdgeMinFunction :: FuncGrad (const Vector & x, Vector & grad) const
+{
+  Vec3d n1, n2, v1, vgrad;
+  Point3d pp1;
+  double badness;
+  static Vector freegrad(3);
+
+  CalcNewPoint (x, pp1);
+
+
+  badness = pf.PointFunctionValueGrad (pp1, freegrad);
+
+  vgrad.X() = freegrad.Get(1);
+  vgrad.Y() = freegrad.Get(2);
+  vgrad.Z() = freegrad.Get(3);
+
+  Vec<3> hn1, hn2;
+  surf1 -> GetNormalVector (pp1, hn1);
+  surf2 -> GetNormalVector (pp1, hn2);
+  n1 = hn1;
+  n2 = hn2;
+
+  v1 = Cross (n1, n2);
+  v1 /= v1.Length();
+
+  grad.Elem(1) = (vgrad * v1) * (t1 * v1);
+  return badness;
+}
+#endif
+
+
+
+
+double CalcBad (const Mesh::T_POINTS & points, const Element & elem,
+		double h)
+{
+  if (elem.GetType() == TET)
+    return CalcTetBadness (points[elem.PNum(1)], 
+			   points[elem.PNum(2)],  
+			   points[elem.PNum(3)],  
+			   points[elem.PNum(4)], h);  
+  return 0;
+}
+
+
+extern double teterrpow;
+double CalcTotalBad (const Mesh::T_POINTS & points, 
+		     const Mesh::T_VOLELEMENTS & elements)
+{
+  int i;
+  double sum = 0;
+  double elbad;
+  
+  tets_in_qualclass.SetSize(20);
+  for (i = 1; i <= 20; i++)
+    tets_in_qualclass.Elem(i) = 0;
+
+
+  for (i = 1; i <= elements.Size(); i++)
+    {
+      elbad = pow (max2(CalcBad (points, elements.Get(i), 0),1e-10),
+		   1/teterrpow);
+
+      int qualclass = int (20 / elbad + 1);
+      if (qualclass < 1) qualclass = 1;
+      if (qualclass > 20) qualclass = 20;
+      tets_in_qualclass.Elem(qualclass)++;
+
+      sum += elbad;
+    }
+  return sum;
+}
+
+int WrongOrientation (const Mesh::T_POINTS & points, const Element & el)
+{
+  const Point3d & p1 = points[el.PNum(1)];
+  const Point3d & p2 = points[el.PNum(2)];
+  const Point3d & p3 = points[el.PNum(3)];
+  const Point3d & p4 = points[el.PNum(4)];
+
+  Vec3d v1(p1, p2);
+  Vec3d v2(p1, p3);
+  Vec3d v3(p1, p4);
+  Vec3d n;
+
+  Cross (v1, v2, n);
+  double vol = n * v3;
+
+  return (vol > 0);
+}
+
+
+
+
+
+
+
+
+
+
+
+/* ************* JacobianPointFunction **************************** */
+
+
+
+
+// class JacobianPointFunction : public MinFunction
+// {
+// public:
+//   Mesh::T_POINTS & points;
+//   const Mesh::T_VOLELEMENTS & elements;
+//   TABLE<INDEX> elementsonpoint;
+//   PointIndex actpind;
+  
+// public:
+//   JacobianPointFunction (Mesh::T_POINTS & apoints, 
+// 			 const Mesh::T_VOLELEMENTS & aelements);
+  
+//   virtual void SetPointIndex (PointIndex aactpind);
+//   virtual double Func (const Vector & x) const;
+//   virtual double FuncGrad (const Vector & x, Vector & g) const;
+//   virtual double FuncDeriv (const Vector & x, const Vector & dir, double & deriv) const;
+// };
+
+
+JacobianPointFunction :: 
+JacobianPointFunction (Mesh::T_POINTS & apoints, 
+		       const Mesh::T_VOLELEMENTS & aelements)
+  : points(apoints), elements(aelements), elementsonpoint(apoints.Size())
+{
+  INDEX i;
+  int j;
+  
+  for (i = 1; i <= elements.Size(); i++)
+    {
+      for (j = 1; j <= elements.Get(i).NP(); j++)
+	elementsonpoint.Add1 (elements.Get(i).PNum(j), i);  
+    }
+
+  onplane = false;
+}
+
+void JacobianPointFunction :: SetPointIndex (PointIndex aactpind)
+{
+  actpind = aactpind; 
+}  
+
+
+double JacobianPointFunction :: Func (const Vector & v) const
+{
+  int j;
+  double badness = 0;
+
+  Point<3> hp = points.Elem(actpind);
+
+  points.Elem(actpind) = hp + Vec<3> (v.Get(1), v.Get(2), v.Get(3));
+
+  if(onplane)
+    points.Elem(actpind) -= (v.Get(1)*nv(0)+v.Get(2)*nv(1)+v.Get(3)*nv(2)) * nv;
+
+
+  for (j = 1; j <= elementsonpoint.EntrySize(actpind); j++)
+    {
+      int eli = elementsonpoint.Get(actpind, j);
+      badness += elements.Get(eli).CalcJacobianBadness (points);
+    }
+  
+  points.Elem(actpind) = hp; 
+
+  return badness;
+}
+
+
+
+
+
+double JacobianPointFunction :: 
+FuncGrad (const Vector & x, Vector & g) const
+{
+  int j, k;
+  int lpi;
+  double badness = 0;//, hbad;
+
+  Point<3> hp = points.Elem(actpind);
+  points.Elem(actpind) = hp + Vec<3> (x.Get(1), x.Get(2), x.Get(3));
+
+  if(onplane)
+    points.Elem(actpind) -= (x.Get(1)*nv(0)+x.Get(2)*nv(1)+x.Get(3)*nv(2)) * nv;
+
+  Vec<3> hderiv;
+  //Vec3d vdir;
+  g.SetSize(3);
+  g = 0;
+
+  for (j = 1; j <= elementsonpoint.EntrySize(actpind); j++)
+    {
+      int eli = elementsonpoint.Get(actpind, j);
+      const Element & el = elements.Get(eli);
+
+      lpi = 0;
+      for (k = 1; k <= el.GetNP(); k++)
+	if (el.PNum(k) == actpind)
+	  lpi = k;
+      if (!lpi) cerr << "loc point not found" << endl;
+
+      badness += elements.Get(eli).
+	CalcJacobianBadnessGradient (points, lpi, hderiv);
+
+      for(k=0; k<3; k++)
+	g.Elem(k+1) += hderiv(k);
+	
+      /*
+      for (k = 1; k <= 3; k++)
+	{
+	  vdir = Vec3d(0,0,0);
+	  vdir.X(k) = 1;
+
+	  hbad = elements.Get(eli).
+	    CalcJacobianBadnessDirDeriv (points, lpi, vdir, hderiv);
+	  //(*testout) << "hderiv " << k << ": " << hderiv << endl;
+	  g.Elem(k) += hderiv;
+	  if (k == 1)
+	    badness += hbad;
+	}
+      */
+    }
+
+  if(onplane)
+    {
+      double scal = nv(0)*g.Get(1) + nv(1)*g.Get(2) + nv(2)*g.Get(3);
+      g.Elem(1) -= scal*nv(0);
+      g.Elem(2) -= scal*nv(1);
+      g.Elem(3) -= scal*nv(2);
+    }
+
+  //(*testout) << "g = " << g << endl;
+
+  
+  points.Elem(actpind) = hp; 
+
+  return badness;
+}
+
+
+double JacobianPointFunction :: 
+FuncDeriv (const Vector & x, const Vector & dir, double & deriv) const
+{
+  int j, k;
+  int lpi;
+  double badness = 0;
+
+  Point<3> hp = points.Elem(actpind);
+  points.Elem(actpind) = Point<3> (hp + Vec3d (x.Get(1), x.Get(2), x.Get(3)));
+
+  if(onplane)
+    points.Elem(actpind) -= (Vec3d (x.Get(1), x.Get(2), x.Get(3))*nv) * nv;
+
+  double hderiv;
+  deriv = 0;
+  Vec<3> vdir(dir.Get(1), dir.Get(2), dir.Get(3));
+ 
+  if(onplane)
+    {
+      double scal = vdir * nv;
+      vdir -= scal*nv;
+    }
+
+  for (j = 1; j <= elementsonpoint.EntrySize(actpind); j++)
+    {
+      int eli = elementsonpoint.Get(actpind, j);
+      const Element & el = elements.Get(eli);
+
+      lpi = 0;
+      for (k = 1; k <= el.GetNP(); k++)
+	if (el.PNum(k) == actpind)
+	  lpi = k;
+      if (!lpi) cerr << "loc point not found" << endl;
+
+      badness += elements.Get(eli).
+	CalcJacobianBadnessDirDeriv (points, lpi, vdir, hderiv);
+      deriv += hderiv;
+    }
+  
+  points.Elem(actpind) = hp; 
+
+  return badness;
+  
+}
+
+
+
+
+
+
+
+
+
+
+#ifdef SOLIDGEOMxxxx
+void Mesh :: ImproveMesh (const CSGeometry & geometry, OPTIMIZEGOAL goal)
+{
+  INDEX i, eli;
+  int j;
+  int typ = 1;
+
+  if (!&geometry || geometry.GetNSurf() == 0)
+    {
+      ImproveMesh (goal);
+      return;
+    }
+
+  const char * savetask = multithread.task;
+  multithread.task = "Smooth Mesh";
+
+
+  TABLE<INDEX> surfelementsonpoint(points.Size());
+  Vector x(3), xsurf(2), xedge(1);
+  int surf, surf1, surf2, surf3;
+
+  int uselocalh = mparam.uselocalh;
+
+  (*testout).precision(8);
+  (*testout) << "Improve Mesh" << "\n";
+  PrintMessage (3, "ImproveMesh");
+  //  (*mycout) << "Vol = " << CalcVolume (points, volelements) << endl;
+
+
+  for (i = 1; i <= surfelements.Size(); i++)
+    for (j = 1; j <= 3; j++)
+      surfelementsonpoint.Add1 (surfelements.Get(i).PNum(j), i);
+
+
+  PointFunction * pf;
+  if (typ == 1)
+    pf = new PointFunction(points, volelements);
+  else
+    pf = new CheapPointFunction(points, volelements);
+
+  //  pf->SetLocalH (h);
+  
+  Opti3FreeMinFunction freeminf(*pf);
+  Opti3SurfaceMinFunction surfminf(*pf);
+  Opti3EdgeMinFunction edgeminf(*pf);
+  
+  OptiParameters par;
+  par.maxit_linsearch = 20;
+  par.maxit_bfgs = 20;
+
+
+
+  for (i = 1; i <= points.Size(); i++)
+    {
+      //      if (ptyps.Get(i) == FIXEDPOINT) continue;
+      if (ptyps.Get(i) != INNERPOINT) continue;
+
+      if (multithread.terminate)
+	throw NgException ("Meshing stopped");
+      /*
+      if (multithread.terminate)
+	break;
+      */
+      multithread.percent = 100.0 * i /points.Size();
+
+      if (points.Size() < 1000)
+	PrintDot ();
+      else
+	if (i % 10 == 0)
+	  PrintDot ('+');
+      
+      //    (*testout) << "Now point " << i << "\n";
+      //    (*testout) << "Old: " << points.Get(i) << "\n";
+
+      pf->SetPointIndex (i);
+
+      //      if (uselocalh)
+      {
+	double lh = GetH (points.Get(i));
+	pf->SetLocalH (GetH (points.Get(i)));
+	par.typx = lh / 10;
+	//	  (*testout) << "lh(" << points.Get(i) << ") = " << lh << "\n";
+      }
+
+      surf1 = surf2 = surf3 = 0;
+
+      for (j = 1; j <= surfelementsonpoint.EntrySize(i); j++)
+	{
+	  eli = surfelementsonpoint.Get(i, j);
+	  int surfi = surfelements.Get(eli).GetIndex();
+
+	  if (surfi)
+	    {
+	      surf = GetFaceDescriptor(surfi).SurfNr();
+	    
+	      if (!surf1)
+		surf1 = surf;
+	      else if (surf1 != surf)
+		{
+		  if (!surf2)
+		    surf2 = surf;
+		  else if (surf2 != surf)
+		    surf3 = surf;
+		}
+	    }
+	  else
+	    {
+	      surf1 = surf2 = surf3 = 1;   // simulates corner point
+	    }
+	}
+
+
+      if (surf2 && !surf3)
+	{
+	  //      (*testout) << "On Edge" << "\n";
+	  /*
+	    xedge = 0;
+	    edgeminf.SetPoint (geometry.GetSurface(surf1),
+	    geometry.GetSurface(surf2), 
+	    points.Elem(i));
+	    BFGS (xedge, edgeminf, par);
+
+	    edgeminf.CalcNewPoint (xedge, points.Elem(i));
+	  */
+	}
+
+      if (surf1 && !surf2)
+	{
+	  //      (*testout) << "In Surface" << "\n";
+	  /*
+	    xsurf = 0;
+	    surfminf.SetPoint (geometry.GetSurface(surf1),
+	    points.Get(i));
+	    BFGS (xsurf, surfminf, par);
+   
+	    surfminf.CalcNewPoint (xsurf, points.Elem(i));
+	  */
+	}
+ 
+      if (!surf1)
+	{
+	  //      (*testout) << "In Volume" << "\n";
+	  x = 0;
+	  freeminf.SetPoint (points.Elem(i));
+	  //	  par.typx = 
+	  BFGS (x, freeminf, par);
+
+	  points.Elem(i).X() += x.Get(1);
+	  points.Elem(i).Y() += x.Get(2);
+	  points.Elem(i).Z() += x.Get(3);
+	}
+      
+      //    (*testout) << "New Point: " << points.Elem(i) << "\n" << "\n";
+    
+    }
+  PrintDot ('\n');
+  //  (*mycout) << "Vol = " << CalcVolume (points, volelements) << endl;
+
+  multithread.task = savetask;
+
+}
+#endif
+
+
+
+  
+void Mesh :: ImproveMesh (OPTIMIZEGOAL goal)
+{
+  int typ = 1;
+  
+  (*testout) << "Improve Mesh" << "\n";
+  PrintMessage (3, "ImproveMesh");
+
+  int np = GetNP();
+  int ne = GetNE();
+
+
+  ARRAY<double,PointIndex::BASE> perrs(np);
+  perrs = 1.0;
+
+  double bad1 = 0;
+  double badmax = 0;
+
+  if (goal == OPT_QUALITY)
+    {
+      for (int i = 1; i <= ne; i++)
+	{
+	  const Element & el = VolumeElement(i);
+	  if (el.GetType() != TET)
+	    continue;
+	  
+	  double hbad = CalcBad (points, el, 0);
+	  for (int j = 0; j < 4; j++)
+	    perrs[el[j]] += hbad;
+	  
+	  bad1 += hbad;
+	}
+      
+      for (PointIndex i = PointIndex::BASE; i < np+PointIndex::BASE; i++)
+	if (perrs[i] > badmax) 
+	  badmax = perrs[i];
+      badmax = 0;
+    }
+
+  if (goal == OPT_QUALITY)
+    {
+      bad1 = CalcTotalBad (points, volelements);
+      (*testout) << "Total badness = " << bad1 << endl;
+      PrintMessage (5, "Total badness = ", bad1);
+    }
+  
+  Vector x(3);
+  
+  (*testout).precision(8);
+  
+  //int uselocalh = mparam.uselocalh;
+
+
+  PointFunction * pf;
+
+  if (typ == 1)
+    pf = new PointFunction(points, volelements);
+  else
+    pf = new CheapPointFunction(points, volelements);
+
+  //  pf->SetLocalH (h);
+  
+  Opti3FreeMinFunction freeminf(*pf);
+
+  OptiParameters par;
+  par.maxit_linsearch = 20;
+  par.maxit_bfgs = 20;
+
+  ARRAY<double, PointIndex::BASE> pointh (points.Size());
+
+  if(lochfunc)
+    {
+      for(int i=1; i<=points.Size(); i++)
+	pointh[i] = GetH(points.Get(i));
+    }
+  else
+    {
+      pointh = 0;
+      for(int i=0; i<GetNE(); i++)
+	{
+	  const Element & el = VolumeElement(i+1);
+	  double h = pow(el.Volume(points),1./3.);
+	  for(int j=1; j<=el.GetNV(); j++)
+	    if(h > pointh[el.PNum(j)])
+	      pointh[el.PNum(j)] = h;
+	}
+    }
+ 
+
+  const char * savetask = multithread.task;
+  multithread.task = "Smooth Mesh";
+  
+  for (PointIndex i = PointIndex::BASE; 
+       i < points.Size()+PointIndex::BASE; i++)
+    if ( (*this)[i].Type() == INNERPOINT && perrs[i] > 0.01 * badmax)
+      {
+	if (multithread.terminate)
+	  throw NgException ("Meshing stopped");
+
+	multithread.percent = 100.0 * (i+1-PointIndex::BASE) / points.Size();
+
+	if (points.Size() < 1000)
+	  PrintDot ();
+	else
+	  if ( (i+1-PointIndex::BASE) % 10 == 0)
+	    PrintDot ('+');
+
+	double lh = pointh[i];
+	pf->SetLocalH (lh);
+	par.typx = lh;
+
+	freeminf.SetPoint (points[i]);
+	pf->SetPointIndex (i);
+
+	x = 0;
+	int pok;
+	pok = freeminf.Func (x) < 1e10; 
+
+	if (!pok)
+	  {
+	    pok = pf->MovePointToInner ();
+
+	    freeminf.SetPoint (points[i]);
+	    pf->SetPointIndex (i);
+	  }
+
+	if (pok)
+	  {
+            //*testout << "start BFGS, pok" << endl;
+	    BFGS (x, freeminf, par);
+            //*testout << "BFGS complete, pok" << endl;
+	    points[i](0) += x.Get(1);
+	    points[i](1) += x.Get(2);
+	    points[i](2) += x.Get(3);
+	  }
+      }
+  PrintDot ('\n');
+  
+  
+  delete pf;
+
+  multithread.task = savetask;
+
+  if (goal == OPT_QUALITY)
+    {
+      bad1 = CalcTotalBad (points, volelements);
+      (*testout) << "Total badness = " << bad1 << endl;
+      PrintMessage (5, "Total badness = ", bad1);
+    }
+}
+
+
+
+
+// Improve Condition number of Jacobian, any elements  
+void Mesh :: ImproveMeshJacobian (OPTIMIZEGOAL goal, const BitArray * usepoint)
+{
+  int i, j;
+  
+  (*testout) << "Improve Mesh Jacobian" << "\n";
+  PrintMessage (3, "ImproveMesh Jacobian");
+
+  int np = GetNP();
+  int ne = GetNE();
+
+  
+  Vector x(3);
+  
+  (*testout).precision(8);
+  
+  JacobianPointFunction pf(points, volelements);
+  
+
+  OptiParameters par;
+  par.maxit_linsearch = 20;
+  par.maxit_bfgs = 20;
+  
+  BitArray badnodes(np);
+  badnodes.Clear();
+
+  for (i = 1; i <= ne; i++)
+    {
+      const Element & el = VolumeElement(i);
+      double bad = el.CalcJacobianBadness (Points());
+      if (bad > 1)
+	for (j = 1; j <= el.GetNP(); j++)
+	  badnodes.Set (el.PNum(j));
+    }
+
+  ARRAY<double, PointIndex::BASE> pointh (points.Size());
+
+  if(lochfunc)
+    {
+      for(i = 1; i<=points.Size(); i++)
+	pointh[i] = GetH(points.Get(i));
+    }
+  else
+    {
+      pointh = 0;
+      for(i=0; i<GetNE(); i++)
+	{
+	  const Element & el = VolumeElement(i+1);
+	  double h = pow(el.Volume(points),1./3.);
+	  for(j=1; j<=el.GetNV(); j++)
+	    if(h > pointh[el.PNum(j)])
+	      pointh[el.PNum(j)] = h;
+	}
+    }
+ 
+
+
+  const char * savetask = multithread.task;
+  multithread.task = "Smooth Mesh Jacobian";
+  
+  for (i = 1; i <= points.Size(); i++)
+    {
+      if ((*this)[PointIndex(i)].Type() != INNERPOINT)
+	continue;
+
+      if(usepoint && !usepoint->Test(i))
+	continue;
+
+      //(*testout) << "improvejac, p = " << i << endl;
+
+      if (goal == OPT_WORSTCASE && !badnodes.Test(i))
+	continue;
+      //	(*testout) << "smoot p " << i << endl;
+
+      /*
+	if (multithread.terminate)
+	break;
+      */
+      if (multithread.terminate)
+	throw NgException ("Meshing stopped");
+
+      multithread.percent = 100.0 * i / points.Size();
+
+      if (points.Size() < 1000)
+	PrintDot ();
+      else
+	if (i % 10 == 0)
+	  PrintDot ('+');
+
+      double lh = pointh[i];
+      par.typx = lh;
+
+      pf.SetPointIndex (i);
+
+      x = 0;
+      int pok = (pf.Func (x) < 1e10); 
+
+      if (pok)
+	{
+          //*testout << "start BFGS, Jacobian" << endl;
+	  BFGS (x, pf, par);
+          //*testout << "end BFGS, Jacobian" << endl;
+	  points.Elem(i)(0) += x.Get(1);
+	  points.Elem(i)(1) += x.Get(2);
+	  points.Elem(i)(2) += x.Get(3);
+	}
+      else
+	{
+	  cout << "el not ok" << endl;
+	}
+    }
+  PrintDot ('\n');
+  
+
+  multithread.task = savetask;
+}
+
+
+
+
+// Improve Condition number of Jacobian, any elements  
+void Mesh :: ImproveMeshJacobianOnSurface (const BitArray & usepoint, 
+					   const ARRAY< Vec<3>* > & nv,
+					   OPTIMIZEGOAL goal,
+					   const ARRAY< ARRAY<int,PointIndex::BASE>* > * idmaps)
+{
+  int i, j;
+  
+  (*testout) << "Improve Mesh Jacobian" << "\n";
+  PrintMessage (3, "ImproveMesh Jacobian");
+
+  int np = GetNP();
+  int ne = GetNE();
+
+  
+  Vector x(3);
+  
+  (*testout).precision(8);
+  
+  JacobianPointFunction pf(points, volelements);
+
+  ARRAY< ARRAY<int,PointIndex::BASE>* > locidmaps;
+  const ARRAY< ARRAY<int,PointIndex::BASE>* > * used_idmaps;
+
+  if(idmaps)
+    used_idmaps = idmaps;
+  else
+    {
+      used_idmaps = &locidmaps;
+      
+      for(i=1; i<=GetIdentifications().GetMaxNr(); i++)
+	{
+	  if(GetIdentifications().GetType(i) == Identifications::PERIODIC)
+	    {
+	      locidmaps.Append(new ARRAY<int,PointIndex::BASE>);
+	      GetIdentifications().GetMap(i,*locidmaps.Last(),true);
+	    }
+	}
+    }
+
+  
+  bool usesum = (used_idmaps->Size() > 0);
+  MinFunctionSum pf_sum;
+  
+  JacobianPointFunction * pf2ptr = NULL;
+  if(usesum)
+    {
+      pf2ptr = new JacobianPointFunction(points, volelements);
+      pf_sum.AddFunction(pf);
+      pf_sum.AddFunction(*pf2ptr);
+    }
+  
+
+  OptiParameters par;
+  par.maxit_linsearch = 20;
+  par.maxit_bfgs = 20;
+  
+  BitArray badnodes(np);
+  badnodes.Clear();
+
+  for (i = 1; i <= ne; i++)
+    {
+      const Element & el = VolumeElement(i);
+      double bad = el.CalcJacobianBadness (Points());
+      if (bad > 1)
+	for (j = 1; j <= el.GetNP(); j++)
+	  badnodes.Set (el.PNum(j));
+    }
+
+  ARRAY<double, PointIndex::BASE> pointh (points.Size());
+ 
+  if(lochfunc)
+    {
+      for(i=1; i<=points.Size(); i++)
+	pointh[i] = GetH(points.Get(i));
+    }
+  else
+    {
+      pointh = 0;
+      for(i=0; i<GetNE(); i++)
+	{
+	  const Element & el = VolumeElement(i+1);
+	  double h = pow(el.Volume(points),1./3.);
+	  for(j=1; j<=el.GetNV(); j++)
+	    if(h > pointh[el.PNum(j)])
+	      pointh[el.PNum(j)] = h;
+	}
+    }
+
+
+  const char * savetask = multithread.task;
+  multithread.task = "Smooth Mesh Jacobian";
+  
+  for (i = 1; i <= points.Size(); i++)
+    if ( usepoint.Test(i) )
+      {
+	//(*testout) << "improvejac, p = " << i << endl;
+
+	if (goal == OPT_WORSTCASE && !badnodes.Test(i))
+	  continue;
+	//	(*testout) << "smoot p " << i << endl;
+
+	/*
+	if (multithread.terminate)
+	  break;
+	*/
+	if (multithread.terminate)
+	  throw NgException ("Meshing stopped");
+
+	multithread.percent = 100.0 * i / points.Size();
+
+	if (points.Size() < 1000)
+	  PrintDot ();
+	else
+	  if (i % 10 == 0)
+	    PrintDot ('+');
+
+	double lh = pointh[i];//GetH(points.Get(i));
+	par.typx = lh;
+
+	pf.SetPointIndex (i);
+
+	int brother = -1;
+	if(usesum)
+	  {
+	    for(j=0; brother == -1 && j<used_idmaps->Size(); j++)
+	      {
+		if(i < (*used_idmaps)[j]->Size() + PointIndex::BASE)
+		  {
+		    brother = (*(*used_idmaps)[j])[i];
+		    if(brother == i || brother == 0)
+		      brother = -1;
+		  }
+	      }
+	    if(brother >= i)
+	      {
+		pf2ptr->SetPointIndex(brother);
+		pf2ptr->SetNV(*nv[brother-1]);
+	      }
+	  }
+
+	if(usesum && brother < i)
+	  continue;
+
+	//pf.UnSetNV(); x = 0;
+	//(*testout) << "before " << pf.Func(x);
+
+	pf.SetNV(*nv[i-1]);
+
+	x = 0;
+	int pok = (brother == -1) ? (pf.Func (x) < 1e10) : (pf_sum.Func (x) < 1e10);
+
+	if (pok)
+	  {
+	    
+	    if(brother == -1)
+	      BFGS (x, pf, par);
+	    else
+	      BFGS (x, pf_sum, par);
+
+
+	    for(j=1; j<=3; j++)
+	      points.Elem(i)(j-1) += x.Get(j);// - scal*nv[i-1].X(j);
+
+	    if(brother != -1)
+	      for(j=1; j<=3; j++)
+		points.Elem(brother)(j-1) += x.Get(j);// - scal*nv[brother-1].X(j);
+
+
+	  }
+	else
+	  {
+	    cout << "el not ok" << endl;
+	    (*testout) << "el not ok" << endl
+		       << "   func " << ((brother == -1) ? pf.Func(x) : pf_sum.Func (x)) << endl;
+	    if(brother != -1)
+	      (*testout) << "   func1 " << pf.Func(x) << endl
+			 << "   func2 " << pf2ptr->Func(x) << endl;
+	  }
+      }
+  
+  PrintDot ('\n');
+
+  delete pf2ptr;
+  for(i=0; i<locidmaps.Size(); i++)
+    delete locidmaps[i];
+
+  multithread.task = savetask;
+}
+
+
+
+
+}
diff --git a/contrib/Netgen/libsrc/meshing/specials.cpp b/contrib/Netgen/libsrc/meshing/specials.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..e224f4a7e98309164209350c6ebe8e347d6bd88c
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/specials.cpp
@@ -0,0 +1,193 @@
+#include <mystdlib.h>
+#include "meshing.hpp"
+
+
+namespace netgen
+{
+
+// A special function for Hermann Landes, Erlangen
+
+
+void CutOffAndCombine (Mesh & mesh, const Mesh & othermesh)
+{
+  int i, j;
+  int nse = othermesh.GetNSE();
+  int onp = othermesh.GetNP();
+
+  int ne = mesh.GetNE();
+
+  PrintMessage (1, "other mesh has ",
+		othermesh.GetNP(), " points, ",
+		othermesh.GetNSE(), " surface elements.");
+
+  ARRAY<Box3d> otherbounds(nse);  
+  Box3d otherbox;
+
+  double maxh = 0;
+  for (i = 1; i <= nse; i++)
+    {
+      const Element2d & sel = othermesh.SurfaceElement(i);
+      sel.GetBox(othermesh.Points(), otherbounds.Elem(i));
+
+      double loch = othermesh.GetH (othermesh.Point (sel.PNum(1)));
+      otherbounds.Elem(i).Increase(loch);
+      if (loch > maxh) maxh = loch;
+    }
+
+  otherbox.SetPoint (othermesh.Point(1));
+  for (i = 1; i <= othermesh.GetNP(); i++)
+    otherbox.AddPoint (othermesh.Point(i));
+  otherbox.Increase (maxh);
+
+  for (i = 1; i <= ne; i++)
+    {
+      Box3d box;
+      int remove = 0;
+
+      const Element & el = mesh.VolumeElement(i);
+      el.GetBox(mesh.Points(), box);
+
+      if (i % 10000 == 0)
+	cout << "+" << flush;
+
+      if (box.Intersect(otherbox))
+	{
+	  for (j = 1; j <= nse && !remove; j++)
+	    if (box.Intersect(otherbounds.Get(j)))
+	      remove = 1;
+	}
+
+      if (remove)
+	mesh.VolumeElement(i).Delete();
+    }
+  cout << endl;
+
+  BitArray connected(mesh.GetNP());
+  connected.Clear();
+  for (i = 1; i <= mesh.GetNSE(); i++)
+    {
+      const Element2d & el = mesh.SurfaceElement(i);
+      for (j = 1; j <= 3; j++)
+	connected.Set(el.PNum(j));
+    }
+  
+  bool changed;
+  do
+    {
+      changed = 0;
+      for (i = 1; i <= mesh.GetNE(); i++)
+	{
+	  const Element & el = mesh.VolumeElement(i);
+	  int has = 0, hasnot = 0;
+	  if (el[0])
+	    {
+	      for (j = 0; j < 4; j++)
+		{
+		  if (connected.Test(el[j]))
+		    has = 1;
+		  else
+		    hasnot = 1;
+		}
+	      if (has && hasnot)
+		{
+		  changed = 1;
+		  for (j = 0; j < 4; j++)
+		    connected.Set (el[j]);
+		}
+	    }
+	}
+      cout << "." << flush;
+    }
+  while (changed);
+  cout << endl;
+
+  for (i = 1; i <= mesh.GetNE(); i++)
+    {
+      const Element & el = mesh.VolumeElement(i);
+      int hasnot = 0;
+      if (el[0])
+	{
+	  for (j = 0; j < 4; j++)
+	    {
+	      if (!connected.Test(el[j]))
+		hasnot = 1;
+	    }
+	  if (hasnot)
+	    mesh.VolumeElement(i).Delete();
+	}
+    }
+
+  mesh.Compress();
+  
+  mesh.FindOpenElements();
+  BitArray locked(mesh.GetNP());
+  locked.Set();
+  for (i = 1; i <= mesh.GetNOpenElements(); i++)
+    for (j = 1; j <= 3; j++)
+      locked.Clear (mesh.OpenElement(i).PNum(j));
+
+  for (i = 1; i <= locked.Size(); i++)
+    if (locked.Test(i))
+      {
+	mesh.AddLockedPoint (i);
+      }
+
+
+
+  
+  ARRAY<int> pmat(onp);
+
+  for (i = 1; i <= onp; i++)
+    pmat.Elem(i) = mesh.AddPoint (othermesh.Point(i));
+
+  int fnum = 
+    mesh.AddFaceDescriptor (FaceDescriptor(0,0,1,0));
+
+  for (i = 1; i <= othermesh.GetNSE(); i++)
+    {
+      Element2d tri = othermesh.SurfaceElement(i);
+      for (j = 1; j <= 3; j++)
+	tri.PNum(j) = pmat.Get(tri.PNum(j));
+      tri.SetIndex(fnum);
+      mesh.AddSurfaceElement (tri);
+    }
+
+  for (i = 1; i <= onp; i++)
+    mesh.AddLockedPoint (pmat.Elem(i));
+
+  mesh.CalcSurfacesOfNode();
+  mesh.CalcLocalH();
+}
+
+
+
+
+void HelmholtzMesh (Mesh & mesh)
+{
+  int i;
+  double ri, ra, rinf;
+
+  cout << "ri = ";
+  cin >> ri;
+  cout << "ra = ";
+  cin >> ra;
+  cout << "rinf = ";
+  cin >> rinf;
+
+  double det = ri * ra * rinf - ri * ri * rinf;
+  double a = (ri - rinf) / det;
+  double b = (ri*ri - ra * rinf) / det;
+  for (i = 1; i <= mesh.GetNP(); i++)
+    {
+      Point<3> & p = mesh.Point(i);
+      double rold = sqrt (sqr(p(0)) + sqr(p(1)) + sqr(p(2)));
+      if (rold < ri) continue;
+
+      double rnew = 1 / (a * rold - b);
+      double fac = rnew / rold;
+      p(0) *= fac;
+      p(1) *= fac;
+      p(2) *= fac;
+    }
+}
+}
diff --git a/contrib/Netgen/libsrc/meshing/specials.hpp b/contrib/Netgen/libsrc/meshing/specials.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..700ba4596bf705f260ca5d7b355d5bd35c96fe7b
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/specials.hpp
@@ -0,0 +1,16 @@
+#ifndef FILE_SPECIALS
+#define FILE_SPECIALS
+
+/*
+
+  Very special implementations ..
+  
+ */
+
+
+///
+extern void CutOffAndCombine (Mesh & mesh, const Mesh & othermesh);
+
+extern void HelmholtzMesh (Mesh & mesh);
+
+#endif
diff --git a/contrib/Netgen/libsrc/meshing/tetrarls.cpp b/contrib/Netgen/libsrc/meshing/tetrarls.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..cb28648b6a641e8d50527d51dac512f0d9273847
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/tetrarls.cpp
@@ -0,0 +1,1466 @@
+namespace netgen
+{
+const char * tetrules[] = {
+"tolfak 0.5\n",\
+"\n",\
+"rule \"Free Tetrahedron\"\n",\
+"\n",\
+"quality 1\n",\
+"\n",\
+"mappoints\n",\
+"(0, 0, 0);\n",\
+"(1, 0, 0);\n",\
+"(0.5, 0.866, 0);\n",\
+"\n",\
+"mapfaces\n",\
+"(1, 2, 3) del;\n",\
+"\n",\
+"newpoints\n",\
+"(0.5, 0.288, -0.816)\n",\
+"	{ 0.333 X1, 0.333 X2, 0.333 X3 }\n",\
+"	{ 0.333 Y1, 0.333 Y2, 0.333 Y3 } { };\n",\
+"\n",\
+"newfaces\n",\
+"(4, 1, 2);\n",\
+"(4, 2, 3);\n",\
+"(4, 3, 1);\n",\
+"\n",\
+"elements\n",\
+"(1, 2, 3, 4);\n",\
+"\n",\
+"freezone2\n",\
+"{ 1 P1 };\n",\
+"{ 1 P2 };\n",\
+"{ 1 P3 };\n",\
+"{ 1.6 P4, -0.2 P1, -0.2 P2, -0.2 P3 };\n",\
+"{ -0.5 P1, 0.5 P2, 0.5 P3, 0.5 P4 };\n",\
+"{ 0.5 P1, -0.5 P2, 0.5 P3, 0.5 P4 };\n",\
+"{ 0.5 P1, 0.5 P2, -0.5 P3, 0.5 P4 };\n",\
+"endrule\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"rule \"Tetrahedron 60\"\n",\
+"\n",\
+"quality 1\n",\
+"\n",\
+"flags c;\n",\
+"\n",\
+"mappoints\n",\
+"(0, 0, 0);\n",\
+"(1, 0, 0) { 0.5 } ;\n",\
+"(0.5, 0.866, 0) { 0.5 };\n",\
+"(0.5, 0.288, -0.816) { 0.5 };\n",\
+"\n",\
+"mapfaces\n",\
+"(1, 2, 3) del;\n",\
+"(1, 4, 2) del;\n",\
+"\n",\
+"newpoints\n",\
+"\n",\
+"newfaces\n",\
+"(1, 4, 3);\n",\
+"(4, 2, 3);\n",\
+"\n",\
+"elements\n",\
+"(1, 2, 3, 4);\n",\
+"\n",\
+"freezone2\n",\
+"{ 1 P1 };\n",\
+"{ 1 P2 };\n",\
+"{ 1 P3 };\n",\
+"{ 1 P4 };\n",\
+"{ -0.35 P1, 0.45 P2, 0.45 P3, 0.45 P4 };\n",\
+"{ 0.45 P1, -0.35 P2, 0.45 P3, 0.45 P4 };\n",\
+"{ -0.05 P1, -0.05 P2, 0.7 P3, 0.4 P4 };\n",\
+"\n",\
+"\n",\
+"freezonelimit\n",\
+"{ 1 P1 };\n",\
+"{ 1 P2 };\n",\
+"{ 1 P3 };\n",\
+"{ 1 P4 };\n",\
+"{ 0.3333 P2, 0.3333 P3, 0.3334 P4 };\n",\
+"{ 0.3333 P1, 0.3333 P3, 0.3334 P4 };\n",\
+"{ 0.65 P3, 0.35 P4 };\n",\
+"endrule\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"rule \"Tetrahedron 60 with edge(1)\"\n",\
+"\n",\
+"quality 1\n",\
+"\n",\
+"flags c;\n",\
+"\n",\
+"mappoints\n",\
+"(0, 0, 0);\n",\
+"(1, 0, 0) { 0.8 };\n",\
+"(0.5, 0.866, 0) { 0.8 };\n",\
+"(0.5, 0.288, -0.816) { 0.8 };\n",\
+"\n",\
+"mapfaces\n",\
+"(1, 2, 3) del;\n",\
+"(1, 4, 2) del;\n",\
+"\n",\
+"mapedges\n",\
+"(3, 4);\n",\
+"\n",\
+"newpoints\n",\
+"\n",\
+"newfaces\n",\
+"(1, 4, 3);\n",\
+"(4, 2, 3);\n",\
+"\n",\
+"elements\n",\
+"(1, 2, 3, 4);\n",\
+"\n",\
+"\n",\
+"freezone2\n",\
+"{ 1 P1 };\n",\
+"{ 1 P2 };\n",\
+"{ 1 P3 };\n",\
+"{ 1 P4 };\n",\
+"{ 0.4 P1, 0.4 P4, 0.4 P3, -0.2 P2 };\n",\
+"{ 0.4 P2, 0.4 P4, 0.4 P3, -0.2 P1 };\n",\
+"\n",\
+"freezonelimit\n",\
+"{ 1 P1 };\n",\
+"{ 1 P2 };\n",\
+"{ 1 P3 };\n",\
+"{ 1 P4 };\n",\
+"{ 0.3333 P1, 0.3333 P4, 0.3334 P3 };\n",\
+"{ 0.3333 P2, 0.3333 P4, 0.3334 P3 };\n",\
+"endrule\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"rule \"Tetrahedron Vis a Vis Point (1)\"\n",\
+"\n",\
+"quality 100\n",\
+"\n",\
+"mappoints\n",\
+"(0, 0, 0);\n",\
+"(1, 0, 0) { 0.5 };\n",\
+"(0.5, 0.866, 0) { 0.5 };\n",\
+"(0.5, 0.288, -0.816) { 0.5 };\n",\
+"\n",\
+"mapfaces\n",\
+"(1, 2, 3) del;\n",\
+"\n",\
+"newpoints\n",\
+"\n",\
+"newfaces\n",\
+"(4, 3, 1);\n",\
+"(4, 2, 3);\n",\
+"(4, 1, 2);\n",\
+"\n",\
+"elements\n",\
+"(1, 2, 3, 4);\n",\
+"\n",\
+"freezone2\n",\
+"{ 1 P1 };\n",\
+"{ 1 P2 };\n",\
+"{ 1 P3 };\n",\
+"{ 1 P4 };\n",\
+"{ -0.5 P1, 0.5 P2, 0.5 P3, 0.5 P4 };\n",\
+"{ 0.5 P1, -0.5 P2, 0.5 P3, 0.5 P4 };\n",\
+"{ 0.5 P1, 0.5 P2, -0.5 P3, 0.5 P4 };\n",\
+"{ 0.8 P1, -0.1 P2, -0.1 P3, 0.4 P4 };\n",\
+"{ -0.1 P1, 0.8 P2, -0.1 P3, 0.4 P4 };\n",\
+"{ -0.1 P1, -0.1 P2, 0.8 P3, 0.4 P4 };\n",\
+"\n",\
+"freezonelimit\n",\
+"{ 1 P1 };\n",\
+"{ 1 P2 };\n",\
+"{ 1 P3 };\n",\
+"{ 1 P4 };\n",\
+"{ 0.3333 P2, 0.3333 P3, 0.3334 P4 };\n",\
+"{ 0.3333 P1, 0.3333 P3, 0.3334 P4 };\n",\
+"{ 0.3333 P1, 0.3333 P2, 0.3334 P4 };\n",\
+"{ 0.7 P1, 0.3 P4 };\n",\
+"{ 0.7 P2, 0.3 P4 };\n",\
+"{ 0.7 P3, 0.3 P4 };\n",\
+"endrule\n",\
+"\n",\
+"\n",\
+"\n",\
+"rule \"Tetrahedron Vis a Vis Point with edge(1)\"\n",\
+"\n",\
+"quality 1\n",\
+"\n",\
+"\n",\
+"\n",\
+"mappoints\n",\
+"(0, 0, 0);\n",\
+"(1, 0, 0) { 0.5 };\n",\
+"(0.5, 0.866, 0) { 0.5 };\n",\
+"(0.5, 0.288, -0.816) { 0.5 };\n",\
+"\n",\
+"mapfaces\n",\
+"(1, 2, 3) del;\n",\
+"\n",\
+"mapedges\n",\
+"(1, 4);\n",\
+"\n",\
+"newpoints\n",\
+"\n",\
+"newfaces\n",\
+"(4, 3, 1);\n",\
+"(4, 2, 3);\n",\
+"(4, 1, 2);\n",\
+"\n",\
+"elements\n",\
+"(1, 2, 3, 4);\n",\
+"\n",\
+"\n",\
+"freezone2\n",\
+"{ 1 P1 };\n",\
+"{ 1 P2 };\n",\
+"{ 1 P3 };\n",\
+"{ 1 P4 };\n",\
+"{ -0.35 P1, 0.45 P2, 0.45 P3, 0.45 P4 };\n",\
+"{ 0.45 P1, -0.35 P2, 0.45 P3, 0.45 P4 };\n",\
+"{ 0.45 P1, 0.45 P2, -0.35 P3, 0.45 P4 };\n",\
+"{ -0.05 P1, 0.7 P2, -0.05 P3, 0.4 P4 };\n",\
+"{ -0.05 P1, -0.05 P2, 0.7 P3, 0.4 P4 };\n",\
+"\n",\
+"freezonelimit\n",\
+"{ 1 P1 };\n",\
+"{ 1 P2 };\n",\
+"{ 1 P3 };\n",\
+"{ 1 P4 };\n",\
+"{ 0.3333 P2, 0.3333 P3, 0.3334 P4 };\n",\
+"{ 0.3333 P1, 0.3333 P3, 0.3334 P4 };\n",\
+"{ 0.3333 P1, 0.3333 P2, 0.3334 P4 };\n",\
+"{ 0.65 P2, 0.35 P4 };\n",\
+"{ 0.65 P3, 0.35 P4 };\n",\
+"endrule\n",\
+"\n",\
+"\n",\
+"\n",\
+"rule \"Tetrahedron Vis a Vis Point with 2 edges (1)\"\n",\
+"\n",\
+"quality 1\n",\
+"\n",\
+"mappoints\n",\
+"(0, 0, 0);\n",\
+"(1, 0, 0) { 0.5 };\n",\
+"(0.5, 0.866, 0) { 0.5 };\n",\
+"(0.5, 0.288, -0.816) { 0.5 };\n",\
+"\n",\
+"mapfaces\n",\
+"(1, 2, 3) del;\n",\
+"\n",\
+"mapedges\n",\
+"(1, 4);\n",\
+"(2, 4);\n",\
+"\n",\
+"newpoints\n",\
+"\n",\
+"newfaces\n",\
+"(4, 3, 1);\n",\
+"(4, 2, 3);\n",\
+"(4, 1, 2);\n",\
+"\n",\
+"elements\n",\
+"(1, 2, 3, 4);\n",\
+"\n",\
+"\n",\
+"freezone2\n",\
+"{ 1 P1 };\n",\
+"{ 1 P2 };\n",\
+"{ 1 P3 };\n",\
+"{ 1 P4 };\n",\
+"{ -0.35 P1, 0.45 P2, 0.45 P3, 0.45 P4 };\n",\
+"{ 0.45 P1, -0.35 P2, 0.45 P3, 0.45 P4 };\n",\
+"{ 0.45 P1, 0.45 P2, -0.35 P3, 0.45 P4 };\n",\
+"{ -0.05 P1, -0.05 P2, 0.7 P3, 0.4 P4 };\n",\
+"\n",\
+"freezonelimit\n",\
+"{ 1 P1 };\n",\
+"{ 1 P2 };\n",\
+"{ 1 P3 };\n",\
+"{ 1 P4 };\n",\
+"{ 0.3333 P2, 0.3333 P3, 0.3334 P4 };\n",\
+"{ 0.3333 P1, 0.3333 P3, 0.3334 P4 };\n",\
+"{ 0.3333 P1, 0.3333 P2, 0.3334 P4 };\n",\
+"{ 0.65 P3, 0.35 P4 };\n",\
+"endrule\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"rule \"Tetrahedron Vis a Vis Point with 3 edges (1)\"\n",\
+"\n",\
+"quality 1\n",\
+"\n",\
+"mappoints\n",\
+"(0, 0, 0);\n",\
+"(1, 0, 0) { 0.5 };\n",\
+"(0.5, 0.866, 0) { 0.5 };\n",\
+"(0.5, 0.288, -0.816) { 0.5 };\n",\
+"\n",\
+"mapfaces\n",\
+"(1, 2, 3) del;\n",\
+"\n",\
+"mapedges\n",\
+"(1, 4);\n",\
+"(2, 4);\n",\
+"(3, 4);\n",\
+"\n",\
+"newpoints\n",\
+"\n",\
+"newfaces\n",\
+"(4, 3, 1);\n",\
+"(4, 2, 3);\n",\
+"(4, 1, 2);\n",\
+"\n",\
+"elements\n",\
+"(1, 2, 3, 4);\n",\
+"\n",\
+"\n",\
+"freezone2\n",\
+"{ 1 P1 };\n",\
+"{ 1 P2 };\n",\
+"{ 1 P3 };\n",\
+"{ 1 P4 };\n",\
+"{ -0.35 P1, 0.45 P2, 0.45 P3, 0.45 P4 };\n",\
+"{ 0.45 P1, -0.35 P2, 0.45 P3, 0.45 P4 };\n",\
+"{ 0.45 P1, 0.45 P2, -0.35 P3, 0.45 P4 };\n",\
+"\n",\
+"freezonelimit\n",\
+"{ 1 P1 };\n",\
+"{ 1 P2 };\n",\
+"{ 1 P3 };\n",\
+"{ 1 P4 };\n",\
+"{ 0.3333 P2, 0.3333 P3, 0.3334 P4 };\n",\
+"{ 0.3333 P1, 0.3333 P3, 0.3334 P4 };\n",\
+"{ 0.3333 P1, 0.3333 P2, 0.3334 P4 };\n",\
+"endrule\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"rule \"Tetrahedron Vis a Vis Triangle (1)\"\n",\
+"\n",\
+"quality 100\n",\
+"\n",\
+"mappoints\n",\
+"(0, 0, 0);\n",\
+"(1, 0, 0) { 0.5 };\n",\
+"(0.5, 0.866, 0) { 0.5 };\n",\
+"(0, 0, -0.816) { 0.5 };\n",\
+"(1, 0, -0.816) { 0.5 };\n",\
+"(0.5, 0.866, -0.816) { 0.5 };\n",\
+"\n",\
+"mapfaces\n",\
+"(1, 2, 3) del;\n",\
+"(4, 6, 5) del;\n",\
+"\n",\
+"newpoints\n",\
+"\n",\
+"newfaces\n",\
+"(1, 2, 4);\n",\
+"(2, 5, 4);\n",\
+"(2, 3, 6);\n",\
+"(2, 6, 5);\n",\
+"(3, 1, 4);\n",\
+"(3, 4, 6);\n",\
+"\n",\
+"\n",\
+"elements\n",\
+"(1, 2, 3, 4);\n",\
+"(4, 2, 3, 6);\n",\
+"(4, 2, 6, 5);\n",\
+"\n",\
+"freezone2\n",\
+"{ 1 P1 };\n",\
+"{ 1 P2 };\n",\
+"{ 1 P3 };\n",\
+"{ 1 P4 };\n",\
+"{ 1 P5 };\n",\
+"{ 1 P6 };\n",\
+"{ -0.2 P1, 0.35 P2, 0.35 P3, -0.2 P4, 0.35 P5, 0.35 P6 };\n",\
+"{ 0.35 P1, -0.2 P2, 0.35 P3, 0.35 P4, -0.2 P5, 0.35 P6 };\n",\
+"{ 0.35 P1, 0.35 P2, -0.2 P3, 0.35 P4, 0.35 P5, -0.2 P6 };\n",\
+"endrule\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"rule \"Octaeder 1\"\n",\
+"\n",\
+"quality 100\n",\
+"\n",\
+"mappoints\n",\
+"(0, 0, 0);\n",\
+"(1, 0, 0) { 0.95 };\n",\
+"(0.5, 0.866, 0) { 0.95 };\n",\
+"(0.5, -0.288, -0.816) { 0.5 };\n",\
+"\n",\
+"mapfaces\n",\
+"(1, 2, 3) del;\n",\
+"(1, 4, 2) del;\n",\
+"\n",\
+"newpoints\n",\
+"(1, 0.578, -0.816) { 0.5 X3, 0.5 X4 } { 0.5 Y3, 0.5 Y4} { 0.5 Z3, 0.5 Z4 };\n",\
+"(0, 0.578, -0.816) { 0.5 X3, 0.5 X4 } { 0.5 Y3, 0.5 Y4} { 0.5 Z3, 0.5 Z4 };\n",\
+"\n",\
+"newfaces\n",\
+"(2, 3, 5);\n",\
+"(3, 1, 6);\n",\
+"(3, 6, 5);\n",\
+"(2, 5, 4);\n",\
+"(1, 4, 6);\n",\
+"(4, 5, 6);\n",\
+"\n",\
+"elements\n",\
+"(3, 4, 1, 2);\n",\
+"(3, 4, 2, 5);\n",\
+"(3, 4, 5, 6);\n",\
+"(3, 4, 6, 1);\n",\
+"\n",\
+"freezone\n",\
+"(0, 0, 0);\n",\
+"(1, 0, 0) { 1 X2 } { } { };\n",\
+"(0.5, 0.866, 0) { 1 X3 } { 1 Y3 } { };\n",\
+"(0.5, -0.288, -0.816) { 1 X4 } { 1 Y4 } { 1 Z4 };\n",\
+"(-0.5, 1, -1.5) { 0.5 X3, 0.5 X4 } { 0.5 Y3, 0.5 Y4 } { 1 Z4 };\n",\
+"( 1.5, 1, -1.5) { 0.5 X3, 0.5 X4 } { 0.5 Y3, 0.5 Y4 } { 1 Z4 };\n",\
+"\n",\
+"endrule\n",\
+"\n",\
+"\n",\
+"\n",\
+"rule \"Octaeder 2\"\n",\
+"\n",\
+"quality 100\n",\
+"\n",\
+"mappoints\n",\
+"(0, 0, 0);\n",\
+"(1, 0, 0) { 0.95 };\n",\
+"(0.5, 0.866, 0) { 0.95 };\n",\
+"(0.5, -0.288, -0.816) { 0.5 };\n",\
+"(1, 0.578, -0.816) { 0.5 };\n",\
+"\n",\
+"mapfaces\n",\
+"(1, 2, 3) del;\n",\
+"(1, 4, 2) del;\n",\
+"\n",\
+"newpoints\n",\
+"(0, 0.578, -0.816) { 0.5 X3, 0.5 X4 } { 0.5 Y3, 0.5 Y4} { 0.5 Z3, 0.5 Z4 };\n",\
+"\n",\
+"newfaces\n",\
+"(2, 3, 5);\n",\
+"(3, 1, 6);\n",\
+"(3, 6, 5);\n",\
+"(2, 5, 4);\n",\
+"(1, 4, 6);\n",\
+"(4, 5, 6);\n",\
+"\n",\
+"elements\n",\
+"(3, 4, 1, 2);\n",\
+"(3, 4, 2, 5);\n",\
+"(3, 4, 5, 6);\n",\
+"(3, 4, 6, 1);\n",\
+"\n",\
+"freezone\n",\
+"(0, 0, 0);\n",\
+"(1, 0, 0) { 1 X2 } { } { };\n",\
+"(0.5, 0.866, 0) { 1 X3 } { 1 Y3 } { };\n",\
+"(0.5, -0.288, -0.816) { 1 X4 } { 1 Y4 } { 1 Z4 };\n",\
+"(1, 0.578, -0.816) { 1 X5 } { 1 Y5 } { 1 Z5 };\n",\
+"\n",\
+"(0.9, 0.097, -0.544) { 0.333 X2, 0.333 X4, 0.333 X5 }\n",\
+"                     { 0.333 Y2, 0.333 Y4, 0.333 Y5 }\n",\
+"                     { 0.333 Z2, 0.333 Z4, 0.333 Z5 };\n",\
+"(0.9, 0.481, -0.272) { 0.333 X2, 0.333 X3, 0.333 X5 }\n",\
+"                     { 0.333 Y2, 0.333 Y3, 0.333 Y5 }\n",\
+"                     { 0.333 Z2, 0.333 Z3, 0.333 Z5 };\n",\
+"\n",\
+"(-0.5, 1, -1.5) { 0.5 X3, 0.5 X4 } { 0.5 Y3, 0.5 Y4 } { 0.5 Z4, 0.5 Z5 };\n",\
+"\n",\
+"endrule\n",\
+"\n",\
+"\n",\
+"rule \"Octaeder 2a\"\n",\
+"\n",\
+"\n",\
+"quality 100\n",\
+"\n",\
+"mappoints\n",\
+"(0, 0, 0);\n",\
+"(1, 0, 0) { 0.95 };\n",\
+"(0.5, 0.866, 0) { 0.95 };\n",\
+"(0.5, -0.288, -0.816) { 0.5 };\n",\
+"(1, 0.578, -0.816) { 0.5 };\n",\
+"\n",\
+"mapfaces\n",\
+"(1, 2, 3) del;\n",\
+"(3, 2, 5) del;\n",\
+"\n",\
+"newpoints\n",\
+"(0, 0.578, -0.816)\n",\
+"	{ -1 X2, 1 X3, 1 X4 }\n",\
+"	{ -1 Y2, 1 Y3, 1 Y4 }\n",\
+"	{ -1 Z2, 1 Z3, 1 Z4 };\n",\
+"\n",\
+"newfaces\n",\
+"(1, 2, 4);\n",\
+"(3, 1, 6);\n",\
+"(3, 6, 5);\n",\
+"(2, 5, 4);\n",\
+"(1, 4, 6);\n",\
+"(4, 5, 6);\n",\
+"\n",\
+"elements\n",\
+"(3, 4, 1, 2);\n",\
+"(3, 4, 2, 5);\n",\
+"(3, 4, 5, 6);\n",\
+"(3, 4, 6, 1);\n",\
+"\n",\
+"freezone\n",\
+"(0, 0, 0);\n",\
+"(1, 0, 0) { 1 X2 } { } { };\n",\
+"(0.5, 0.866, 0) { 1 X3 } { 1 Y3 } { };\n",\
+"(0.5, -0.288, -0.816) { 1 X4 } { 1 Y4 } { 1 Z4 };\n",\
+"(1, 0.578, -0.816) { 1 X5 } { 1 Y5 } { 1 Z5 };\n",\
+"\n",\
+"(0.9, 0.097, -0.544) { 0.333 X2, 0.333 X4, 0.333 X5 }\n",\
+"                     { 0.333 Y2, 0.333 Y4, 0.333 Y5 }\n",\
+"                     { 0.333 Z2, 0.333 Z4, 0.333 Z5 };\n",\
+"\n",\
+"(0.5, -0.097, -0.272) { 0.333 X2, 0.333 X4, 0.333 X1 }\n",\
+"                     { 0.333 Y2, 0.333 Y4, 0.333 Y1 }\n",\
+"                     { 0.333 Z2, 0.333 Z4, 0.333 Z1 };\n",\
+"\n",\
+"(-0.5, 1, -1.5) { 0.5 X3, 0.5 X4 } { 0.5 Y3, 0.5 Y4 } { 0.5 Z4, 0.5 Z5 };\n",\
+"\n",\
+"endrule\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"rule \"Pyramid 1\"\n",\
+"\n",\
+"quality 100\n",\
+"\n",\
+"mappoints\n",\
+"(0, 0, 0);\n",\
+"(1, 0, 0) { 1 };\n",\
+"(0.5, 0.866, 0) { 1 };\n",\
+"(0.5, -0.288, -0.816) { 1 };\n",\
+"\n",\
+"mapfaces\n",\
+"(1, 2, 3) del;\n",\
+"(1, 4, 2) del;\n",\
+"\n",\
+"newpoints\n",\
+"(1, 0.578, -0.816) { 0.5 X3, 0.5 X4 } { 0.5 Y3, 0.5 Y4} { 0.5 Z3, 0.5 Z4 };\n",\
+"\n",\
+"newfaces\n",\
+"(1, 4, 3);\n",\
+"(2, 3, 5);\n",\
+"(2, 5, 4);\n",\
+"(4, 5, 3);\n",\
+"\n",\
+"elements\n",\
+"(1, 2, 3, 4);\n",\
+"(4, 2, 3, 5);\n",\
+"\n",\
+"\n",\
+"freezone\n",\
+"(0, 0, 0);\n",\
+"(1, 0, 0) { 1 X2 } { } { };\n",\
+"(0.5, 0.866, 0) { 1 X3 } { 1 Y3 } { };\n",\
+"(0.5, -0.288, -0.816) { 1 X4 } { 1 Y4 } { 1 Z4 };\n",\
+"(0, 1, -1) { 0.5 X3, 0.5 X4 } { 1 Y3 } { 1 Z4 };\n",\
+"(1.5, 1, -1.5) { 0.5 X3, 0.5 X4 } { 0.5 Y3, 0.5 Y4} { 0.5 Z3, 0.5 Z4 };\n",\
+"\n",\
+"endrule\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"rule \"Tetrahedron 2 times 60\"\n",\
+"\n",\
+"quality 1\n",\
+"\n",\
+"mappoints\n",\
+"(0, 0, 0);\n",\
+"(1, 0, 0) { 0.3 };\n",\
+"(0.5, 0.866, 0) { 0.3 };\n",\
+"(0.5, 0.288, -0.816) { 0.3 };\n",\
+"\n",\
+"mapfaces\n",\
+"(1, 2, 3) del;\n",\
+"(1, 4, 2) del;\n",\
+"(2, 4, 3) del;\n",\
+"\n",\
+"newpoints\n",\
+"\n",\
+"newfaces\n",\
+"(1, 4, 3);\n",\
+"\n",\
+"elements\n",\
+"(1, 2, 3, 4);\n",\
+"\n",\
+"freezone2\n",\
+"{ 1 P1 };\n",\
+"{ 1 P2 };\n",\
+"{ 1 P3 };\n",\
+"{ 1 P4 };\n",\
+"{ 0.4 P1, 0.4 P4, 0.4 P3, -0.2 P2 };\n",\
+"\n",\
+"freezonelimit\n",\
+"{ 1 P1 };\n",\
+"{ 1 P2 };\n",\
+"{ 1 P3 };\n",\
+"{ 1 P4 };\n",\
+"{ 0.3333 P1, 0.3333 P3, 0.3334 P4 };\n",\
+"endrule\n",\
+"\n",\
+"\n",\
+"\n",\
+"rule \"Fill Tetrahedron (1)\"\n",\
+"\n",\
+"quality 1\n",\
+"\n",\
+"mappoints\n",\
+"(0, 0, 0);\n",\
+"(1, 0, 0) { 0.2 };\n",\
+"(0.5, 0.866, 0) { 0.2 };\n",\
+"(0.5, 0.288, -0.816) { 0.2 };\n",\
+"\n",\
+"mapfaces\n",\
+"(1, 2, 3) del;\n",\
+"(1, 4, 2) del;\n",\
+"(2, 4, 3) del;\n",\
+"(3, 4, 1) del;\n",\
+"\n",\
+"newpoints\n",\
+"\n",\
+"newfaces\n",\
+"\n",\
+"elements\n",\
+"(1, 2, 3, 4);\n",\
+"\n",\
+"freezone2\n",\
+"{ 1 P1 };\n",\
+"{ 1 P2 };\n",\
+"{ 1 P3 };\n",\
+"{ 1 P4 };\n",\
+"endrule\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"rule \"Tetrahedron 120 (1)\"\n",\
+"\n",\
+"quality 1\n",\
+"\n",\
+"mappoints\n",\
+"(0, 0, 0);\n",\
+"(1, 0, 0) { 1 };\n",\
+"(0.5, 0.866, 0) { 1 };\n",\
+"(0.5, -0.674, -0.544) { 1 };\n",\
+"\n",\
+"mapfaces\n",\
+"(1, 2, 3) del;\n",\
+"(1, 4, 2) del;\n",\
+"\n",\
+"newpoints\n",\
+"(0.5, 0.288, -0.816)\n",\
+"	{ -0.5 X1, -0.5 X2, 1 X3, 1 X4 }\n",\
+"	{ -0.5 Y1, -0.5 Y2, 1 Y3, 1 Y4}\n",\
+"	{ -0.5 Z1, -0.5 Z2, 1 Z3, 1 Z4};\n",\
+"\n",\
+"newfaces\n",\
+"(1, 5, 3);\n",\
+"(3, 5, 2);\n",\
+"(1, 4, 5);\n",\
+"(2, 5, 4);\n",\
+"\n",\
+"elements\n",\
+"(1, 2, 3, 5);\n",\
+"(1, 4, 2, 5);\n",\
+"\n",\
+"\n",\
+"freezone2\n",\
+"{ 1 P1 };\n",\
+"{ 1 P2 };\n",\
+"{ 1 P3 };\n",\
+"{ 1 P4 };\n",\
+"{ 1.3 P5, -0.3 P1 };\n",\
+"{ 1.3 P5, -0.3 P2 };\n",\
+"\n",\
+"freezonelimit\n",\
+"{ 1 P1 };\n",\
+"{ 1 P2 };\n",\
+"{ 1 P3 };\n",\
+"{ 1 P4 };\n",\
+"{ 1 P5 };\n",\
+"{ 1 P5 };\n",\
+"endrule\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"rule \"Tetrahedron 2 times 120 (1)\"\n",\
+"\n",\
+"quality 100\n",\
+"\n",\
+"mappoints\n",\
+"(0, 0, 0);\n",\
+"(1, 0, 0) { 1 };\n",\
+"(0.5, 0.866, 0) { 1 };\n",\
+"(0.5, -0.674, -0.544) { 0.8 };\n",\
+"(1.334, 0.77, -0.544) { 0.8 };\n",\
+"\n",\
+"mapfaces\n",\
+"(1, 2, 3) del;\n",\
+"(1, 4, 2) del;\n",\
+"(3, 2, 5) del;\n",\
+"\n",\
+"newpoints\n",\
+"(0.5, 0.288, -0.816) { 0.25 X1, -0.5 X2, 0.25 X3, 0.5 X4, 0.5 X5 }\n",\
+"		 { 0.25 Y1, -0.5 Y2, 0.25 Y3, 0.5 Y4, 0.5 Y5 }\n",\
+"		 { 0.25 Z1, -0.5 Z2, 0.25 Z3, 0.5 Z4, 0.5 Z5 };\n",\
+"\n",\
+"newfaces\n",\
+"(6, 3, 1);\n",\
+"(6, 1, 4);\n",\
+"(6, 4, 2);\n",\
+"(6, 2, 5);\n",\
+"(6, 5, 3);\n",\
+"\n",\
+"elements\n",\
+"(1, 2, 3, 6);\n",\
+"(1, 4, 2, 6);\n",\
+"(2, 5, 3, 6);\n",\
+"\n",\
+"freezone2\n",\
+"{ 1 P1 };\n",\
+"{ 1 P2 };\n",\
+"{ 1 P3 };\n",\
+"{ 1 P4 };\n",\
+"{ 1 P5 };\n",\
+"{ 1.4 P6, -0.4 P2 };\n",\
+"{ 1.4 P6, -0.4 P1 };\n",\
+"{ 1.4 P6, -0.4 P3 };\n",\
+"endrule\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"rule \"four Tetrahedron non convex (4)\"\n",\
+"\n",\
+"quality 4\n",\
+"flags l;\n",\
+"\n",\
+"mappoints\n",\
+"(0, 0, 0);\n",\
+"(1, 0, 0) { 0.1 };\n",\
+"(0.5, 1, 0) { 0.1 };\n",\
+"(0.5, 0, -1) { 0.1 };\n",\
+"(0.5, 0.3, -0.3) { 0.1 };\n",\
+"\n",\
+"mapfaces\n",\
+"(1, 2, 3) del;\n",\
+"(1, 4, 2) del;\n",\
+"(1, 5, 4) del;\n",\
+"(1, 3, 5) del;\n",\
+"\n",\
+"\n",\
+"newpoints\n",\
+"(0.5, 0.1, -0.1)\n",\
+"	 { 0.333 X1, 0.333 X2, 0.334 X5 }\n",\
+"	 { 0.333 Y1, 0.333 Y2, 0.334 Y5 }\n",\
+"	 { 0.333 Z1, 0.333 Z2, 0.334 Z5 };\n",\
+"\n",\
+"newfaces\n",\
+"(6, 2, 3) del;\n",\
+"(6, 4, 2) del;\n",\
+"(6, 5, 4) del;\n",\
+"(6, 3, 5) del;\n",\
+"\n",\
+"\n",\
+"elements\n",\
+"(1, 2, 3, 6);\n",\
+"(1, 4, 2, 6);\n",\
+"(1, 5, 4, 6);\n",\
+"(1, 3, 5, 6);\n",\
+"\n",\
+"\n",\
+"freezone2\n",\
+"{ 1 P1 };\n",\
+"{ 1 P2 };\n",\
+"{ 1 P3 };\n",\
+"{ 1 P4 };\n",\
+"{ 1 P5 };\n",\
+"{ 1.5 P6, -0.5 P1 };\n",\
+"\n",\
+"freezonelimit\n",\
+"{ 1 P1 };\n",\
+"{ 1 P2 };\n",\
+"{ 1 P3 };\n",\
+"{ 1 P4 };\n",\
+"{ 1 P5 };\n",\
+"{ 1 P6 };\n",\
+"\n",\
+"\n",\
+"\n",\
+"freeset\n",\
+"1 6 2 3;\n",\
+"\n",\
+"freeset\n",\
+"1 6 3 5;\n",\
+"\n",\
+"freeset\n",\
+"1 6 5 4;\n",\
+"\n",\
+"freeset\n",\
+"1 6 4 2;\n",\
+"\n",\
+"endrule\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"rule \"five Tetrahedron non convex (4)\"\n",\
+"\n",\
+"quality 4\n",\
+"flags l;\n",\
+"\n",\
+"mappoints\n",\
+"(0, 0, 0);\n",\
+"(1, 0, 0) { 0.5 };\n",\
+"(0.5, 1, 0) { 0.5 };\n",\
+"(0, 0.8, -0.2) { 0.5 };\n",\
+"(0, 0.2, -0.8) { 0.5 };\n",\
+"(0.5, 0, -1) { 0.5 };\n",\
+"\n",\
+"\n",\
+"mapfaces\n",\
+"(1, 2, 3) del;\n",\
+"(1, 3, 4) del;\n",\
+"(1, 4, 5) del;\n",\
+"(1, 5, 6) del;\n",\
+"(1, 6, 2) del;\n",\
+"\n",\
+"newpoints\n",\
+"(0.1, 0.1, -0.1)\n",\
+"	 { 0.75 X1, 0.05 X2, 0.05 X3, 0.05 X4, 0.05 X5, 0.05 X6 }\n",\
+"	 { 0.75 Y1, 0.05 Y2, 0.05 Y3, 0.05 Y4, 0.05 Y5, 0.05 Y6 }\n",\
+"	 { 0.75 Z1, 0.05 Z2, 0.05 Z3, 0.05 Z4, 0.05 Z5, 0.05 Z6 };\n",\
+"\n",\
+"newfaces\n",\
+"(7, 2, 3);\n",\
+"(7, 3, 4);\n",\
+"(7, 4, 5);\n",\
+"(7, 5, 6);\n",\
+"(7, 6, 2);\n",\
+"\n",\
+"\n",\
+"elements\n",\
+"(1, 2, 3, 7);\n",\
+"(1, 3, 4, 7);\n",\
+"(1, 4, 5, 7);\n",\
+"(1, 5, 6, 7);\n",\
+"(1, 6, 2, 7);\n",\
+"\n",\
+"\n",\
+"freezone2\n",\
+"{ 1 P1 };\n",\
+"{ 1 P2 };\n",\
+"{ 1 P3 };\n",\
+"{ 1 P4 };\n",\
+"{ 1 P5 };\n",\
+"{ 1 P6 };\n",\
+"{ 1.5 P7, -0.5 P1 };\n",\
+"\n",\
+"freezonelimit\n",\
+"{ 1 P1 };\n",\
+"{ 1 P2 };\n",\
+"{ 1 P3 };\n",\
+"{ 1 P4 };\n",\
+"{ 1 P5 };\n",\
+"{ 1 P6 };\n",\
+"{ 1 P7 };\n",\
+"\n",\
+"\n",\
+"\n",\
+"freeset\n",\
+"1 7 2 3;\n",\
+"\n",\
+"freeset\n",\
+"1 7 3 4;\n",\
+"\n",\
+"freeset\n",\
+"1 7 4 5;\n",\
+"\n",\
+"freeset\n",\
+"1 7 5 6;\n",\
+"\n",\
+"freeset\n",\
+"1 7 6 2;\n",\
+"\n",\
+"endrule\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"rule \"four Tetrahedron non convex (6)\"\n",\
+"\n",\
+"quality 6\n",\
+"flags l;\n",\
+"\n",\
+"mappoints\n",\
+"(0, 0, 0);\n",\
+"(1, 0, 0) { 0.5 };\n",\
+"(0.5, 1, 0) { 0.5 };\n",\
+"(0.5, 0, -1) { 0.5 };\n",\
+"(0.5, 0.3, -0.3) { 0.5 };\n",\
+"\n",\
+"mapfaces\n",\
+"(1, 2, 3) del;\n",\
+"(1, 4, 2) del;\n",\
+"(1, 5, 4) del;\n",\
+"(1, 3, 5) del;\n",\
+"\n",\
+"\n",\
+"newpoints\n",\
+"(0.095, 0.003, -0.003)\n",\
+"	 { 0.9 X1, 0.09 X2, 0.01 X5 }\n",\
+"	 { 0.9 Y1, 0.09 Y2, 0.01 Y5 }\n",\
+"	 { 0.9 Z1, 0.09 Z2, 0.01 Z5 };\n",\
+"\n",\
+"newfaces\n",\
+"(6, 2, 3) del;\n",\
+"(6, 4, 2) del;\n",\
+"(6, 5, 4) del;\n",\
+"(6, 3, 5) del;\n",\
+"\n",\
+"\n",\
+"elements\n",\
+"(1, 2, 3, 6);\n",\
+"(1, 4, 2, 6);\n",\
+"(1, 5, 4, 6);\n",\
+"(1, 3, 5, 6);\n",\
+"\n",\
+"\n",\
+"freezone2\n",\
+"{ 1 P1 };\n",\
+"{ 1 P2 };\n",\
+"{ 1 P3 };\n",\
+"{ 1 P4 };\n",\
+"{ 1 P5 };\n",\
+"{ 1.499 P6, -0.5 P1, 0.001 P2 };\n",\
+"\n",\
+"freezonelimit\n",\
+"{ 1 P1 };\n",\
+"{ 1 P2 };\n",\
+"{ 1 P3 };\n",\
+"{ 1 P4 };\n",\
+"{ 1 P5 };\n",\
+"{ 1 P6 };\n",\
+"\n",\
+"\n",\
+"\n",\
+"freeset\n",\
+"1 6 2 3;\n",\
+"\n",\
+"freeset\n",\
+"1 6 3 5;\n",\
+"\n",\
+"freeset\n",\
+"1 6 5 4;\n",\
+"\n",\
+"freeset\n",\
+"1 6 4 2;\n",\
+"\n",\
+"endrule\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"rule \"four Tetrahedron non convex (6)\"\n",\
+"\n",\
+"quality 100\n",\
+"\n",\
+"\n",\
+"mappoints\n",\
+"(0, 0, 0);\n",\
+"(1, 0, 0) { 0.5 };\n",\
+"(0.5, 1, 0) { 0.5 };\n",\
+"(0.5, 0, -1) { 0.5 };\n",\
+"(0.5, 0.4, -0.4) { 0.5 };\n",\
+"\n",\
+"mapfaces\n",\
+"(1, 2, 3) del;\n",\
+"(1, 4, 2) del;\n",\
+"(4, 5, 2) del;\n",\
+"(5, 3, 2) del;\n",\
+"\n",\
+"newpoints\n",\
+"(0.925, 0.02, -0.02)\n",\
+"	 { 0.05 X1, 0.9 X2, 0.05 X5 }\n",\
+"	 { 0.05 Y1, 0.9 Y2, 0.05 Y5 }\n",\
+"	 { 0.05 Z1, 0.9 Z2, 0.05 Z5 };\n",\
+"\n",\
+"newfaces\n",\
+"(3, 1, 6);\n",\
+"(1, 4, 6);\n",\
+"(4, 5, 6);\n",\
+"(5, 3, 6);\n",\
+"\n",\
+"elements\n",\
+"(3, 1, 2, 6);\n",\
+"(1, 4, 2, 6);\n",\
+"(4, 5, 2, 6);\n",\
+"(5, 3, 2, 6);\n",\
+"\n",\
+"orientations\n",\
+"(3, 1, 2, 5);\n",\
+"(1, 4, 2, 5);\n",\
+"(2, 4, 5, 1);\n",\
+"(3, 2, 5, 1);\n",\
+"(5, 4, 2, 3);\n",\
+"\n",\
+"freezone2\n",\
+"{ 1 P1 };\n",\
+"{ 1 P2 };\n",\
+"{ 1 P3 };\n",\
+"{ 1 P4 };\n",\
+"{ 1 P5 };\n",\
+"{ 1.5 P6, -0.5 P2 };\n",\
+"\n",\
+"freezonelimit\n",\
+"{ 1 P1 };\n",\
+"{ 1 P2 };\n",\
+"{ 1 P3 };\n",\
+"{ 1 P4 };\n",\
+"{ 1 P5 };\n",\
+"{ 1 P6 };\n",\
+"\n",\
+"freeset\n",\
+"3 1 2 6;\n",\
+"\n",\
+"freeset\n",\
+"1 4 2 6;\n",\
+"\n",\
+"freeset\n",\
+"4 5 2 6;\n",\
+"\n",\
+"freeset\n",\
+"5 3 2 6;\n",\
+"\n",\
+"endrule\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"rule \"three Tetrahedron non convex (4)\"\n",\
+"\n",\
+"quality 4\n",\
+"flags l;\n",\
+"\n",\
+"mappoints\n",\
+"(0, 0, 0);\n",\
+"(1, 0, 0) { 0.5 };\n",\
+"(0.5, 1, 0) { 0.5 };\n",\
+"(0.5, 0, -1) { 0.5 };\n",\
+"\n",\
+"mapfaces\n",\
+"(1, 2, 3) del;\n",\
+"(1, 4, 2) del;\n",\
+"(1, 3, 4) del;\n",\
+"\n",\
+"newpoints\n",\
+"(0.5, 0.25, -0.25)\n",\
+"	 { 0.25 X1, 0.25 X2, 0.25 X3, 0.25 X4 }\n",\
+"	 { 0.25 Y1, 0.25 Y2, 0.25 Y3, 0.25 Y4 }\n",\
+"	 { 0.25 Z1, 0.25 Z2, 0.25 Z3, 0.25 Z4 };\n",\
+"\n",\
+"newfaces\n",\
+"(5, 2, 3);\n",\
+"(5, 4, 2);\n",\
+"(5, 3, 4);\n",\
+"\n",\
+"elements\n",\
+"(2, 3, 1, 5);\n",\
+"(3, 4, 1, 5);\n",\
+"(4, 2, 1, 5;\n",\
+"\n",\
+"orientations\n",\
+"(1, 2, 4, 3);\n",\
+"\n",\
+"freezone2\n",\
+"{ 1 P1 };\n",\
+"{ 1 P2 };\n",\
+"{ 1 P3 };\n",\
+"{ 1 P4 };\n",\
+"{ 1.5 P5, -0.5 P1 };\n",\
+"\n",\
+"freezonelimit\n",\
+"{ 1 P1 };\n",\
+"{ 1 P2 };\n",\
+"{ 1 P3 };\n",\
+"{ 1 P4 };\n",\
+"{ 1 P5 };\n",\
+"\n",\
+"freeset\n",\
+"1 2 3 5;\n",\
+"\n",\
+"freeset\n",\
+"1 3 4 5;\n",\
+"\n",\
+"freeset\n",\
+"1 4 2 5;\n",\
+"\n",\
+"endrule\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"rule \"three Tetrahedron non convex (6)\"\n",\
+"\n",\
+"quality 100\n",\
+"\n",\
+"\n",\
+"mappoints\n",\
+"(0, 0, 0);\n",\
+"(1, 0, 0) { 0.5 };\n",\
+"(0.5, 1, 0) { 0.5 };\n",\
+"(0.5, 0, -1) { 0.5 };\n",\
+"\n",\
+"mapfaces\n",\
+"(1, 2, 3) del;\n",\
+"(1, 4, 2) del;\n",\
+"(1, 3, 4) del;\n",\
+"\n",\
+"newpoints\n",\
+"(0.2, 0.1, -0.1)\n",\
+"	 { 0.7 X1, 0.1 X2, 0.1 X3, 0.1 X4 }\n",\
+"	 { 0.7 Y1, 0.1 Y2, 0.1 Y3, 0.1 Y4 }\n",\
+"	 { 0.7 Z1, 0.1 Z2, 0.1 Z3, 0.1 Z4 };\n",\
+"\n",\
+"newfaces\n",\
+"(5, 2, 3);\n",\
+"(5, 4, 2);\n",\
+"(5, 3, 4);\n",\
+"\n",\
+"elements\n",\
+"(2, 3, 1, 5);\n",\
+"(3, 4, 1, 5);\n",\
+"(4, 2, 1, 5;\n",\
+"\n",\
+"orientations\n",\
+"(1, 2, 3, 4);\n",\
+"\n",\
+"freezone2\n",\
+"{ 1 P1 };\n",\
+"{ 1 P2 };\n",\
+"{ 1 P3 };\n",\
+"{ 1 P4 };\n",\
+"{ 1.5 P5, -0.5 P1 };\n",\
+"\n",\
+"freezonelimit\n",\
+"{ 1 P1 };\n",\
+"{ 1 P2 };\n",\
+"{ 1 P3 };\n",\
+"{ 1 P4 };\n",\
+"{ 1 P5 };\n",\
+"\n",\
+"freeset\n",\
+"1 2 3 5;\n",\
+"\n",\
+"freeset\n",\
+"1 3 4 5;\n",\
+"\n",\
+"freeset\n",\
+"1 4 2 5;\n",\
+"\n",\
+"endrule\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"rule \"four Tetrahedron non convex (6)\"\n",\
+"\n",\
+"quality 100\n",\
+"\n",\
+"\n",\
+"mappoints\n",\
+"(0, 0, 0);\n",\
+"(1, 0, 0) { 0.5 };\n",\
+"(0.5, 1, 0) { 0.5 };\n",\
+"(0.5, 0, -1) { 0.5 };\n",\
+"(0.5, 0.4, -0.4) { 0.5 };\n",\
+"\n",\
+"mapfaces\n",\
+"(1, 2, 3) del;\n",\
+"(1, 4, 2) del;\n",\
+"(4, 5, 2) del;\n",\
+"(5, 3, 2) del;\n",\
+"\n",\
+"newpoints\n",\
+"(0.7, 0.08, -0.08) { 0.6 X2, 0.2 X5 } { 0.2 Y5 } { 0.2 Z5 };\n",\
+"\n",\
+"newfaces\n",\
+"(3, 1, 6);\n",\
+"(1, 4, 6);\n",\
+"(4, 5, 6);\n",\
+"(5, 3, 6);\n",\
+"\n",\
+"elements\n",\
+"(3, 1, 2, 6);\n",\
+"(1, 4, 2, 6);\n",\
+"(4, 5, 2, 6);\n",\
+"(5, 3, 2, 6);\n",\
+"\n",\
+"\n",\
+"orientations\n",\
+"(3, 1, 2, 5);\n",\
+"(5, 1, 2, 4);\n",\
+"\n",\
+"freezone\n",\
+"(0, 0, 0);\n",\
+"(1, 0, 0) { 1 X2 } { } { };\n",\
+"(0.5, 1, 0) { 1 X3 } { 1 Y3 } { };\n",\
+"(0.5, 0, -1) { 1 X4 } { 1 Y4 } { 1 Z4 };\n",\
+"(0.5, 0.4, -0.4) { 1 X5 } { 1 Y5 } { 1 Z5 };\n",\
+"(0.55, 0.12, -0.12) { 0.4 X2, 0.3 X5 } { 0.3 Y5 } { 0.3 Z5 };\n",\
+"\n",\
+"freeset\n",\
+"3 1 2 6;\n",\
+"\n",\
+"freeset\n",\
+"1 4 2 6;\n",\
+"\n",\
+"freeset\n",\
+"4 5 2 6;\n",\
+"\n",\
+"freeset\n",\
+"5 3 2 6;\n",\
+"\n",\
+"endrule\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"rule \"Tetrahedron 2 in 60 (12)\"\n",\
+"\n",\
+"quality 100\n",\
+"\n",\
+"mappoints\n",\
+"(0, 0, 0);\n",\
+"(1, 0, 0) { 0.5 };\n",\
+"(0.5, 1, 0) { 0.5 };\n",\
+"(0.5, 0, -1) { 0.5 };\n",\
+"\n",\
+"mapfaces\n",\
+"(1, 2, 3) del;\n",\
+"(1, 4, 2) del;\n",\
+"\n",\
+"newpoints\n",\
+"(0.5, 0.1, -0.1)\n",\
+"	{ 0.4 X1, 0.4 X2, 0.1 X3, 0.1 X4 }\n",\
+"	{ 0.4 Y1, 0.4 Y2, 0.1 Y3, 0.1 Y4 }\n",\
+"	{ 0.4 Z1, 0.4 Z2, 0.1 Z3, 0.1 Z4 };\n",\
+"\n",\
+"newfaces\n",\
+"(5, 2, 3);\n",\
+"(5, 3, 1);\n",\
+"(5, 4, 2);\n",\
+"(5, 1, 4);\n",\
+"\n",\
+"elements\n",\
+"(1, 2, 3, 5);\n",\
+"(1, 2, 5, 4);\n",\
+"\n",\
+"freezone2\n",\
+"{ 1 P1 };\n",\
+"{ 1 P2 };\n",\
+"{ 1 P3 };\n",\
+"{ 1 P4 };\n",\
+"{ 1.5 P5, -0.25 P1, -0.25 P2 };\n",\
+"\n",\
+"freezonelimit\n",\
+"{ 1 P1 };\n",\
+"{ 1 P2 };\n",\
+"{ 1 P3 };\n",\
+"{ 1 P4 };\n",\
+"{ 1 P5 };\n",\
+"\n",\
+"freeset\n",\
+"1 2 3 5;\n",\
+"\n",\
+"freeset\n",\
+"1 2 4 5;\n",\
+"\n",\
+"endrule\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"rule \"Tetrahedron 120, but more than 180 (13)\"\n",\
+"\n",\
+"quality 100\n",\
+"\n",\
+"mappoints\n",\
+"(0, 0, 0);\n",\
+"(1, 0, 0) { 1 };\n",\
+"(0.5, 0.866, 0) { 1 };\n",\
+"(0.5, -0.866, 0) { 1 };\n",\
+"\n",\
+"mapfaces\n",\
+"(1, 2, 3) del;\n",\
+"(1, 4, 2);\n",\
+"\n",\
+"newpoints\n",\
+"(0.5, 0, -0.3) { 0.5 X3, 0.5 X4 } { 0.5 Y3, 0.5 Y4} { 0.5 Z3, 0.5 Z4 };\n",\
+"\n",\
+"newfaces\n",\
+"(1, 5, 3);\n",\
+"(3, 5, 2);\n",\
+"(2, 5, 1);\n",\
+"\n",\
+"elements\n",\
+"(1, 2, 3, 5);\n",\
+"\n",\
+"\n",\
+"freezone\n",\
+"(0, 0, 0);\n",\
+"(1, 0, 0) { 1 X2 } { } { };\n",\
+"(0.5, 0.866, 0) { 1 X3 } { 1 Y3 } { };\n",\
+"(0.5, -0.1, -0.4)  { 0.5 X3, 0.5 X4 } { 0.5 Y3, 0.5 Y4} { 0.5 Z3, 0.5 Z4 };\n",\
+"\n",\
+"endrule\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"rule \"Free Tetrahedron (14)\"\n",\
+"\n",\
+"quality 100\n",\
+"\n",\
+"mappoints\n",\
+"(0, 0, 0);\n",\
+"(1, 0, 0) { 1.0 };\n",\
+"(0.5, 0.866, 0) { 1.0 };\n",\
+"\n",\
+"mapfaces\n",\
+"(1, 2, 3) del;\n",\
+"\n",\
+"newpoints\n",\
+"(0.5, 0.288, -0.2) { 0.333 X2, 0.333 X3 } { 0.333 Y3 } { };\n",\
+"\n",\
+"newfaces\n",\
+"(4, 1, 2);\n",\
+"(4, 2, 3);\n",\
+"(4, 3, 1);\n",\
+"\n",\
+"elements\n",\
+"(1, 2, 3, 4);\n",\
+"\n",\
+"freezone\n",\
+"(0, 0, 0);\n",\
+"(1, 0, 0) { 1 X2 } { } { };\n",\
+"(0.5, 0.866, 0) { 1 X3 } { 1 Y3 } { };\n",\
+"(0.5, 0.288, -0.25) { 0.333 X2, 0.333 X3 } { 0.333 Y3 } { };\n",\
+"\n",\
+"endrule\n",\
+"\n",\
+"\n",\
+"\n",\
+"rule \"Free Tetrahedron (15)\"\n",\
+"\n",\
+"quality 100\n",\
+"\n",\
+"mappoints\n",\
+"(0, 0, 0);\n",\
+"(1, 0, 0) { 1.0 };\n",\
+"(0.5, 0.866, 0) { 1.0 };\n",\
+"\n",\
+"mapfaces\n",\
+"(1, 2, 3) del;\n",\
+"\n",\
+"newpoints\n",\
+"(0.5, 0.288, -0.1) { 0.333 X2, 0.333 X3 } { 0.333 Y3 } { };\n",\
+"\n",\
+"newfaces\n",\
+"(4, 1, 2);\n",\
+"(4, 2, 3);\n",\
+"(4, 3, 1);\n",\
+"\n",\
+"elements\n",\
+"(1, 2, 3, 4);\n",\
+"\n",\
+"freezone\n",\
+"(0, 0, 0);\n",\
+"(1, 0, 0) { 1 X2 } { } { };\n",\
+"(0.5, 0.866, 0) { 1 X3 } { 1 Y3 } { };\n",\
+"(0.5, 0.288, -0.15) { 0.333 X2, 0.333 X3 } { 0.333 Y3 } { };\n",\
+"\n",\
+"endrule\n",
+0};
+}
diff --git a/contrib/Netgen/libsrc/meshing/topology.cpp b/contrib/Netgen/libsrc/meshing/topology.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..a5c860cdb249f77f71c9704a754e351c963ee145
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/topology.cpp
@@ -0,0 +1,1464 @@
+#include <mystdlib.h>
+
+#include "meshing.hpp"
+
+#ifdef PARALLEL
+#include <parallel.hpp>
+#endif
+
+namespace netgen
+{
+
+MeshTopology ::  MeshTopology (const Mesh & amesh)
+  : mesh(amesh)
+{
+  buildedges = 1;
+  buildfaces = 1;
+  vert2element = 0;
+  vert2surfelement = 0;
+  vert2segment = 0;
+  timestamp = -1;
+
+  edge2vert.SetName ("edge2vert");
+  face2vert.SetName ("face2vert");
+  edges.SetName ("el2edge");
+  faces.SetName ("el2face");
+  surfedges.SetName ("surfel2edge");
+  segedges.SetName ("segment2edge");
+  surffaces.SetName ("surfel2face");
+  surf2volelement.SetName ("surfel2el");
+  face2surfel.SetName ("face2surfel");
+}
+
+MeshTopology :: ~MeshTopology ()
+{
+  delete vert2element;
+  delete vert2surfelement;
+  delete vert2segment;
+}
+
+void MeshTopology :: Update()
+{
+  static int timer = NgProfiler::CreateTimer ("topology");
+  NgProfiler::RegionTimer reg (timer);
+
+#ifdef PARALLEL
+  ParallelMeshTopology & paralleltop = mesh.GetParallelTopology();
+
+  bool isparallel = 0;
+#endif
+
+  
+  if (timestamp > mesh.GetTimeStamp()) return;
+  
+  int ne = mesh.GetNE();
+  int nse = mesh.GetNSE();
+  int nseg = mesh.GetNSeg();
+  int np = mesh.GetNP();
+  int nv = mesh.GetNV(); 
+  int nfa = 0;
+  int ned = edge2vert.Size();
+
+  PrintMessage (3, "Update mesh topology");
+
+   (*testout) << " UPDATE MESH TOPOLOGY " << endl; 
+   (*testout) << "ne   = " << ne << endl;
+   (*testout) << "nse  = " << nse << endl;
+   (*testout) << "nseg = " << nseg << endl;
+   (*testout) << "np   = " << np << endl;
+   (*testout) << "nv   = " << nv << endl;
+  
+  delete vert2element;
+  delete vert2surfelement;
+  delete vert2segment;
+  
+  ARRAY<int,PointIndex::BASE> cnt(nv);
+  ARRAY<int> vnums;
+
+  /*
+    generate:
+    vertex to element 
+    vertex to surface element
+    vertex to segment 
+   */
+
+
+  cnt = 0;
+  for (ElementIndex ei = 0; ei < ne; ei++)
+    {
+      const Element & el = mesh[ei];
+      int nelv = el.GetNV();
+      for (int j = 0; j < nelv; j++)
+	cnt[el[j]]++;
+    }
+
+  vert2element = new TABLE<int,PointIndex::BASE> (cnt);
+  for (ElementIndex ei = 0; ei < ne; ei++)
+    {
+      const Element & el = mesh[ei];
+      int nelv = el.GetNV();
+      for (int j = 0; j < nelv; j++)
+	vert2element->AddSave (el[j], ei+1);
+    }
+
+  cnt = 0;
+  for (SurfaceElementIndex sei = 0; sei < nse; sei++)
+    {
+      const Element2d & el = mesh[sei];
+      int nelv = el.GetNV();
+      for (int j = 0; j < nelv; j++)
+	cnt[el[j]]++;
+    }
+
+  vert2surfelement = new TABLE<int,PointIndex::BASE> (cnt);
+  for (SurfaceElementIndex sei = 0; sei < nse; sei++)
+    {
+      const Element2d & el = mesh[sei];
+      int nelv = el.GetNV();
+      for (int j = 0; j < nelv; j++)
+	vert2surfelement->AddSave (el[j], sei+1);
+    }
+
+  cnt = 0;
+  for (int i = 1; i <= nseg; i++)
+    {
+      const Segment & seg = mesh.LineSegment(i);
+      cnt[seg.p1]++;
+      cnt[seg.p2]++;
+    }
+ 
+  vert2segment = new TABLE<int,PointIndex::BASE> (cnt);
+  for (int i = 1; i <= nseg; i++)
+    {
+      const Segment & seg = mesh.LineSegment(i);
+      vert2segment->AddSave (seg.p1, i);
+      vert2segment->AddSave (seg.p2, i);
+    }
+
+  if (buildedges)
+    {
+      static int timer1 = NgProfiler::CreateTimer ("topology::buildedges");
+      NgProfiler::RegionTimer reg1 (timer1);
+
+      PrintMessage (5, "Update edges ");
+      
+      edges.SetSize(ne);
+      surfedges.SetSize(nse); 
+      segedges.SetSize(nseg);
+
+      for (int i = 0; i < ne; i++)
+	for (int j = 0; j < 12; j++)
+	  edges[i][j] = 0;
+      for (int i = 0; i < nse; i++)
+	for (int j = 0; j < 4; j++)
+	  surfedges[i][j] = 0;
+
+      // keep existing edges
+      cnt = 0;
+      for (int i = 0; i < edge2vert.Size(); i++)
+	cnt[edge2vert[i][0]]++;
+      TABLE<int,PointIndex::BASE> vert2edge (cnt);
+      for (int i = 0; i < edge2vert.Size(); i++)
+	vert2edge.AddSave (edge2vert[i][0], i+1);
+
+      // ensure all coarse grid and intermediate level edges
+      cnt = 0;
+      for (int i = mesh.mlbetweennodes.Begin(); i < mesh.mlbetweennodes.End(); i++)
+	{
+	  int pa[2];
+	  pa[0] = mesh.mlbetweennodes[i].I1();
+	  pa[1] = mesh.mlbetweennodes[i].I2();
+	  if (pa[0] > pa[1]) Swap (pa[0], pa[1]);
+	  if (pa[0] > 0)
+	    cnt.Elem(pa[0])++;
+	}
+      TABLE<int,PointIndex::BASE> vert2vertcoarse (cnt);
+      for (int i = mesh.mlbetweennodes.Begin(); i < mesh.mlbetweennodes.End(); i++)
+	{
+	  int pa[2];
+	  pa[0] = mesh.mlbetweennodes[i].I1();
+	  pa[1] = mesh.mlbetweennodes[i].I2();
+	  if (pa[0] > pa[1]) swap (pa[0], pa[1]);
+	  if (pa[0] > 0)
+	    vert2vertcoarse.AddSave1 (pa[0], pa[1]);
+	}
+
+
+      ARRAY<int,PointIndex::BASE> edgenr(nv);
+      ARRAY<int,PointIndex::BASE> edgeflag(nv);
+      edgeflag = 0;
+
+      ned = edge2vert.Size();
+      ARRAY<INDEX_3> missing;
+
+      for (int i = 1; i <= nv; i++)
+	{
+	  for (int j = 1; j <= vert2edge.EntrySize(i); j++)
+	    {
+	      int ednr = vert2edge.Get(i,j);
+	      int i2 = edge2vert.Get(ednr)[1];
+	      edgeflag[i2] = i;
+	      edgenr[i2] = ednr;
+	    }
+	  for (int j = 1; j <= vert2vertcoarse.EntrySize(i); j++)
+	    {
+	      int v2 = vert2vertcoarse.Get(i,j);
+	      if (edgeflag[v2] < i)
+		{
+		  ned++;
+		  edgenr[v2] = ned;
+		  edgeflag[v2] = i;
+		  missing.Append (INDEX_3(i,v2,ned));
+		}
+	    }
+
+	  for (int j = 1; j <= vert2element->EntrySize(i); j++)
+	    {
+	      int elnr = vert2element->Get(i,j);
+	      const Element & el = mesh.VolumeElement (elnr);
+
+	      int neledges = GetNEdges (el.GetType());
+	      const ELEMENT_EDGE * eledges = GetEdges (el.GetType());
+	  
+	      for (int k = 0; k < neledges; k++)
+		{
+		  INDEX_2 edge(el.PNum(eledges[k][0]),
+			       el.PNum(eledges[k][1]));
+	      
+		  int edgedir = (edge.I1() > edge.I2());
+		  if (edgedir) swap (edge.I1(), edge.I2());
+	     
+		  if (edge.I1() != i)
+		    continue;
+	     
+		  if (edgeflag[edge.I2()] < i)
+		    {
+		      ned++;
+		      edgenr[edge.I2()] = ned;
+		      edgeflag[edge.I2()] = i;
+		    }
+
+		  int edgenum = edgenr[edge.I2()];
+		  if (edgedir) edgenum *= -1;
+		  edges.Elem(elnr)[k] = edgenum;
+		}
+	    }
+
+	  for (int j = 1; j <= vert2surfelement->EntrySize(i); j++)
+	    {
+	      int elnr = vert2surfelement->Get(i,j);
+	      const Element2d & el = mesh.SurfaceElement (elnr);
+
+	      int neledges = GetNEdges (el.GetType());
+	      const ELEMENT_EDGE * eledges = GetEdges (el.GetType());
+	  
+	      for (int k = 0; k < neledges; k++)
+		{
+		  INDEX_2 edge(el.PNum(eledges[k][0]),
+			       el.PNum(eledges[k][1]));
+	      
+		  int edgedir = (edge.I1() > edge.I2());
+		  if (edgedir) swap (edge.I1(), edge.I2());
+	     
+		  if (edge.I1() != i)
+		    continue;
+	     
+		  if (edgeflag[edge.I2()] < i)
+		    {
+		      ned++;
+		      edgenr[edge.I2()] = ned;
+		      edgeflag[edge.I2()] = i;
+		    }
+	      
+		  int edgenum = edgenr[edge.I2()];
+		  if (edgedir) edgenum *= -1;
+		  surfedges.Elem(elnr)[k] = edgenum;
+		}
+	    }
+
+	  for (int j = 1; j <= vert2segment->EntrySize(i); j++)
+	    {
+	      int elnr = vert2segment->Get(i,j);
+	      const Segment & el = mesh.LineSegment (elnr);
+
+	      INDEX_2 edge(el.p1, el.p2);
+	      
+	      int edgedir = (edge.I1() > edge.I2());
+	      if (edgedir) swap (edge.I1(), edge.I2());
+	      
+	      if (edge.I1() != i)
+		continue;
+	     
+	      if (edgeflag[edge.I2()] < i)
+		{
+		  ned++;
+		  edgenr[edge.I2()] = ned;
+		  edgeflag[edge.I2()] = i;
+		}   
+ 	      int edgenum = edgenr[edge.I2()];
+
+	      if (edgedir) edgenum *= -1;
+	      segedges.Elem(elnr) = edgenum;
+	    }
+	}
+
+
+      edge2vert.SetSize (ned);
+      for (int i = 1; i <= ne; i++)
+	{
+	  const Element & el = mesh.VolumeElement (i);
+      
+	  int neledges = GetNEdges (el.GetType());
+	  const ELEMENT_EDGE * eledges = GetEdges (el.GetType());
+	  
+	  for (int k = 0; k < neledges; k++)
+	    {
+	      INDEX_2 edge(el.PNum(eledges[k][0]),
+			   el.PNum(eledges[k][1]));
+	  
+	      int edgedir = (edge.I1() > edge.I2());
+	      if (edgedir) swap (edge.I1(), edge.I2());
+
+	      int edgenum = abs (edges.Elem(i)[k]);
+
+	      edge2vert.Elem(edgenum)[0] = edge.I1();
+	      edge2vert.Elem(edgenum)[1] = edge.I2();
+	    }
+	}
+      for (int i = 1; i <= nse; i++)
+	{
+	  const Element2d & el = mesh.SurfaceElement (i);
+      
+	  int neledges = GetNEdges (el.GetType());
+	  const ELEMENT_EDGE * eledges = GetEdges (el.GetType());
+	  
+	  for (int k = 0; k < neledges; k++)
+	    {
+	      INDEX_2 edge(el.PNum(eledges[k][0]),
+			   el.PNum(eledges[k][1]));
+	  
+	      int edgedir = (edge.I1() > edge.I2());
+	      if (edgedir) swap (edge.I1(), edge.I2());
+
+	      int edgenum = abs (surfedges.Elem(i)[k]);
+
+	      edge2vert.Elem(edgenum)[0] = edge.I1();
+	      edge2vert.Elem(edgenum)[1] = edge.I2();
+	    }
+	}
+
+      for (int i = 1; i <= nseg; i++)
+	{
+	  const Segment & el = mesh.LineSegment (i);
+      
+	  INDEX_2 edge(el.p1, el.p2);
+	  int edgedir = (edge.I1() > edge.I2());
+	  if (edgedir) swap (edge.I1(), edge.I2());
+	  
+	  int edgenum = abs (segedges.Elem(i));
+	  
+	  edge2vert.Elem(edgenum)[0] = edge.I1();
+	  edge2vert.Elem(edgenum)[1] = edge.I2();
+	}
+
+      for (int i = 1; i <= missing.Size(); i++)
+	{
+	  INDEX_3 i3 = missing.Get(i);
+	  edge2vert.Elem(i3.I3())[0] = i3.I1();
+	  edge2vert.Elem(i3.I3())[1] = i3.I2();
+	}
+	
+      
+      /*
+	(*testout) << "edge table:" << endl;
+	(*testout) << "edge2vert:" << endl;
+	for (int i = 1; i <= edge2vert.Size(); i++)
+	(*testout) << "edge " << i << ", v1,2 = " << edge2vert.Elem(i)[0] << ", " << edge2vert.Elem(i)[1] << endl;
+	(*testout) << "surfedges:" << endl;
+	for (int i = 1; i <= surfedges.Size(); i++)
+	(*testout) << "el " << i << ", edges = " 
+	<< surfedges.Elem(i)[0] << ", "
+	<< surfedges.Elem(i)[1] << ", "
+	<< surfedges.Elem(i)[2] << endl;
+      */ 
+     
+    
+    }
+
+
+  //  cout << "build edges done" << endl;
+
+  // generate faces
+  if (buildfaces) //  && mesh.GetDimension() == 3)
+    {
+      int i, j;
+
+      static int timer2 = NgProfiler::CreateTimer ("topology::buildfaces");
+      NgProfiler::RegionTimer reg2 (timer2);
+
+      PrintMessage (5, "Update faces ");
+
+      faces.SetSize(ne);
+      surffaces.SetSize(nse);
+      
+      // face2vert.SetSize(0);  // keep old faces
+      nfa = face2vert.Size();
+      // INDEX_3_HASHTABLE<int> vert2face(ne+nse+1);
+      INDEX_3_CLOSED_HASHTABLE<int> vert2face(8*ne+2*nse+nfa+2);
+
+      for (i = 1; i <= face2vert.Size(); i++)
+	{
+	  INDEX_3 f;
+	  f.I1() = face2vert.Get(i)[0];
+	  f.I2() = face2vert.Get(i)[1];
+	  f.I3() = face2vert.Get(i)[2];
+	  vert2face.Set (f, i);
+	}
+     
+      for (i = 1; i <= ne; i++)
+	{
+	  const Element & el = mesh.VolumeElement (i);
+	  
+	  int nelfaces = GetNFaces (el.GetType());
+	  const ELEMENT_FACE * elfaces = GetFaces (el.GetType());
+	  
+	  for (j = 0; j < 6; j++)
+	    faces.Elem(i)[j] = 0;
+	  for (j = 0; j < nelfaces; j++)
+	    if (elfaces[j][3] == 0)
+	      
+	      { // triangle
+		
+		int facenum;
+		int facedir;
+		
+		INDEX_3 face(el.PNum(elfaces[j][0]),
+			     el.PNum(elfaces[j][1]),
+			     el.PNum(elfaces[j][2]));
+		
+		facedir = 0;
+		if (face.I1() > face.I2())
+		  {
+		    swap (face.I1(), face.I2());
+		    facedir += 1;
+		  }
+		if (face.I2() > face.I3())
+		  {
+		    swap (face.I2(), face.I3());
+		    facedir += 2;
+		  }
+		if (face.I1() > face.I2())
+		  {
+		    swap (face.I1(), face.I2());
+		    facedir += 4;
+		  }
+		
+		if (vert2face.Used (face))
+		  facenum = vert2face.Get(face);
+		else
+		  {
+		    nfa++;
+		    vert2face.Set (face, nfa);
+		    facenum = nfa;
+		    
+		    INDEX_4 hface(face.I1(),face.I2(),face.I3(),0);
+		    face2vert.Append (hface);
+		    // face2vert.SetSize(face2vert.Size()+1);
+		  }
+		
+		faces.Elem(i)[j] = 8*(facenum-1)+facedir+1;
+	      }
+	  
+	    else
+	      
+	      {
+		// quad
+		int facenum;
+		int facedir;
+		INDEX_4Q face4(el.PNum(elfaces[j][0]),
+			       el.PNum(elfaces[j][1]),
+			       el.PNum(elfaces[j][2]),
+			       el.PNum(elfaces[j][3]));
+		
+		facedir = 0;
+		if (min2 (face4.I1(), face4.I2()) > 
+		    min2 (face4.I4(), face4.I3())) 
+		  {  // z - flip
+		    facedir += 1; 
+		    swap (face4.I1(), face4.I4());
+		    swap (face4.I2(), face4.I3());
+		  }
+		if (min2 (face4.I1(), face4.I4()) >
+		    min2 (face4.I2(), face4.I3())) 
+		  {  // x - flip
+		    facedir += 2; 
+		    swap (face4.I1(), face4.I2());
+		    swap (face4.I3(), face4.I4());
+		  }
+		if (face4.I2() > face4.I4())
+		  {  // diagonal flip
+		    facedir += 4; 
+		    swap (face4.I2(), face4.I4());
+		  }
+		//		face4.Sort();
+		
+		INDEX_3 face(face4.I1(), face4.I2(), face4.I3());
+		
+		if (vert2face.Used (face))
+		  {
+		    facenum = vert2face.Get(face);
+		  }
+		else
+		  {
+		    nfa++;
+		    vert2face.Set (face, nfa);
+		    facenum = nfa;
+
+		    // face2vert.SetSize(face2vert.Size()+1);
+
+		    INDEX_4 hface(face4.I1(),face4.I2(),face4.I3(),face4.I4());
+		    face2vert.Append (hface);
+		  }
+		
+		faces.Elem(i)[j] = 8*(facenum-1)+facedir+1;
+	      }
+	}
+
+      face2surfel.SetSize(nfa+nse);
+      for (i = 1; i <= face2surfel.Size(); i++)
+	face2surfel.Elem(i) = 0;
+
+      for (i = 1; i <= nse; i++)
+	{
+	  const Element2d & el = mesh.SurfaceElement (i);
+	  
+	  const ELEMENT_FACE * elfaces = GetFaces (el.GetType());
+	  
+	  if (elfaces[0][3] == 0)
+	    
+	    { // triangle
+	      
+	      int facenum;
+	      int facedir;
+	      
+	      INDEX_3 face(el.PNum(elfaces[0][0]),
+			   el.PNum(elfaces[0][1]),
+			   el.PNum(elfaces[0][2]));
+	      
+	      facedir = 0;
+	      if (face.I1() > face.I2())
+		{
+		  swap (face.I1(), face.I2());
+		  facedir += 1;
+		}
+	      if (face.I2() > face.I3())
+		{
+		  swap (face.I2(), face.I3());
+		  facedir += 2;
+		}
+	      if (face.I1() > face.I2())
+		{
+		  swap (face.I1(), face.I2());
+		  facedir += 4;
+		}
+	      
+	      if (vert2face.Used (face))
+		facenum = vert2face.Get(face);
+	      else
+		{
+		  nfa++;
+		  vert2face.Set (face, nfa);
+		  facenum = nfa;
+		  
+		  // face2vert.SetSize(face2vert.Size()+1);
+		  INDEX_4 hface(face.I1(),face.I2(),face.I3(),0);
+		  face2vert.Append (hface);
+		}
+	      
+	      surffaces.Elem(i) = 8*(facenum-1)+facedir+1;
+	      face2surfel.Elem(facenum) = i;
+	    }
+	  
+	  else
+	    
+	    {
+	      // quad
+	      int facenum;
+	      int facedir;
+	      
+	      INDEX_4Q face4(el.PNum(elfaces[0][0]),
+			     el.PNum(elfaces[0][1]),
+			     el.PNum(elfaces[0][2]),
+			     el.PNum(elfaces[0][3]));
+
+	      facedir = 0;
+	      if (min2 (face4.I1(), face4.I2()) > 
+		  min2 (face4.I4(), face4.I3())) 
+		{  // z - orientation
+		  facedir += 1; 
+		  swap (face4.I1(), face4.I4());
+		  swap (face4.I2(), face4.I3());
+		}
+	      if (min2 (face4.I1(), face4.I4()) >
+		  min2 (face4.I2(), face4.I3())) 
+		{  // x - orientation
+		  facedir += 2; 
+		  swap (face4.I1(), face4.I2());
+		  swap (face4.I3(), face4.I4());
+		}
+	      if (face4.I2() > face4.I4())
+		{ 
+		  facedir += 4; 
+		  swap (face4.I2(), face4.I4());
+		}
+	      
+	      INDEX_3 face(face4.I1(), face4.I2(), face4.I3());
+	      
+	      if (vert2face.Used (face))
+		facenum = vert2face.Get(face);
+	      else
+		{
+		  nfa++;
+		  vert2face.Set (face, nfa);
+		  facenum = nfa;
+		  
+		  // face2vert.SetSize(face2vert.Size()+1);
+		  INDEX_4 hface(face4.I1(),face4.I2(),face4.I3(),face4.I3());
+		  face2vert.Append (hface);
+		  /*
+		  face2vert.Last()[0] = face4.I1();
+		  face2vert.Last()[1] = face4.I2();
+		  face2vert.Last()[2] = face4.I3();
+		  face2vert.Last()[3] = face4.I3();
+		  */
+		}
+	      
+	      surffaces.Elem(i) = 8*(facenum-1)+facedir+1;
+	      face2surfel.Elem(facenum) = i;
+	    }
+	}
+
+
+      surf2volelement.SetSize (nse);
+      for (i = 1; i <= nse; i++)
+	{
+	  surf2volelement.Elem(i)[0] = 0;
+	  surf2volelement.Elem(i)[1] = 0;
+	}
+      for (i = 1; i <= ne; i++)
+	for (j = 0; j < 6; j++)
+	  {
+            int fnum = (faces.Get(i)[j]+7) / 8;
+	    if (fnum > 0 && face2surfel.Elem(fnum))
+	      {
+		int sel = face2surfel.Elem(fnum);
+		surf2volelement.Elem(sel)[1] = 
+		  surf2volelement.Elem(sel)[0];
+		surf2volelement.Elem(sel)[0] = i;
+	      }
+	  }
+
+      face2vert.SetAllocSize (face2vert.Size());
+
+      /*
+	*testout << "face2vert: ";
+	face2vert.PrintMemInfo(cout);
+	*testout  << "faces: ";
+	faces.PrintMemInfo(cout);
+	*testout << "hashtable: ";
+	vert2face.PrintMemInfo(cout);
+      */
+
+#ifdef PARALLEL
+  (*testout) << " RESET Paralleltop" << endl;
+
+      paralleltop.Reset ();
+#endif
+
+      ARRAY<char> face_els(nfa), face_surfels(nfa);
+      face_els = 0;
+      face_surfels = 0;
+      ARRAY<int> hfaces;
+      for (i = 1; i <= ne; i++)
+	{
+	  GetElementFaces (i, hfaces);
+	  for (j = 0; j < hfaces.Size(); j++)
+	    face_els[hfaces[j]-1]++;
+	}
+      for (i = 1; i <= nse; i++)
+	face_surfels[GetSurfaceElementFace (i)-1]++;
+
+      if (ne)
+	{
+	  int cnt_err = 0;
+	  for (i = 0; i < nfa; i++)
+	    {
+	      /*
+	      (*testout) << "face " << i << " has " << int(face_els[i]) << " els, " 
+ 			 << int(face_surfels[i]) << " surfels, tot = "
+ 			 << face_els[i] + face_surfels[i] << endl; 
+	      */
+	      if (face_els[i] + face_surfels[i] == 1)
+		{
+		  cnt_err++;
+#ifdef PARALLEL
+		  if ( ntasks > 1 )
+		    {
+		  if ( !paralleltop.DoCoarseUpdate() ) continue;
+		  // "illegal" faces are exchange faces
+		  /*
+		  (*testout) << "exchange face : " << i << endl;
+		  (*testout) << "points = " << face2vert[i] << endl;
+		  */
+// 		  (*testout) << "global points = ";
+// 		  for ( int j = 0; j < 3; j++ )
+// // 		    (*testout) << face2vert[i].I(j+1) << " -> " 
+// // 			       << paralleltop.GetLoc2Glob_Vert( face2vert[i].I(j+1) ) << ",  ";
+// 		  (*testout) << endl;
+// 		  if ( !paralleltop.IsExchangeFace (i+1) )
+// 		    paralleltop.SetRefinementFace (i+1);
+
+		  paralleltop.SetExchangeFace (i+1);
+		  
+		  for (int j = 0; j < 4; j++)		    
+		    {
+		      if ( face2vert[i].I(j+1) > 0 )
+			paralleltop.SetExchangeVert(face2vert[i].I(j+1));
+		    }
+		  
+		  ARRAY<int> faceedges;
+		  GetFaceEdges (i+1, faceedges);
+		  for ( int j = 0; j < faceedges.Size(); j++)
+		    {
+		      paralleltop.SetExchangeEdge ( faceedges[j] );
+		      int v1, v2;
+		      GetEdgeVertices(faceedges[j], v1, v2 );
+		    }
+		  
+		  /*
+		  (*testout) << "pos = ";
+		  for (int j = 0; j < 4; j++)
+		    if (face2vert[i].I(j+1) >= 1)
+		      (*testout) << mesh[(PointIndex)face2vert[i].I(j+1)] << " ";
+		  (*testout) << endl;
+		  */
+		    }
+		  else
+		    {
+#endif
+		  (*testout) << "illegal face : " << i << endl;
+		  (*testout) << "points = " << face2vert[i] << endl;
+		  (*testout) << "pos = ";
+		  for (j = 0; j < 4; j++)
+		    if (face2vert[i].I(j+1) >= 1)
+		      (*testout) << mesh[(PointIndex)face2vert[i].I(j+1)] << " ";
+		  (*testout) << endl;
+
+		  FlatArray<int> vertels = GetVertexElements (face2vert[i].I(1));
+		  for (int k = 0; k < vertels.Size(); k++)
+		    {
+		      int elfaces[10], orient[10];
+		      int nf = GetElementFaces (vertels[k], elfaces, orient);
+		      for (int l = 0; l < nf; l++)
+			if (elfaces[l] == i)
+			  {
+			    (*testout) << "is face of element " << vertels[k] << endl;
+			    
+			    if (mesh.coarsemesh && mesh.hpelements->Size() == mesh.GetNE() )
+			      {
+				const HPRefElement & hpref_el =
+				  (*mesh.hpelements) [ mesh.VolumeElement (vertels[k]).hp_elnr];
+				(*testout) << "coarse eleme = " << hpref_el.coarse_elnr << endl;
+			      }
+
+			  }
+		    }
+#ifdef PARALLEL
+		    }
+#endif
+		}
+	    }
+
+#ifndef PARALLEL
+	  if (cnt_err)
+	    cout << cnt_err << " elements are not matching !!!" << endl;
+#else
+	  if (cnt_err && ntasks == 1)
+	    cout << cnt_err << " elements are not matching !!!" << endl;
+	  else if (cnt_err && ntasks > 1)
+	    {
+	      cout << "p" << id << ":  " << cnt_err << " elements are not local" << endl;
+	      isparallel = 1;
+	    }
+	  else if ( ntasks > 1 )
+	    cout << "p" << id << ":  " << "Partition " << id << " is totally local" << endl;
+#endif
+
+	}
+
+#ifdef PARALLEL
+     
+      if ( isparallel )
+	{
+ 	  paralleltop.Update();
+	  if ( paralleltop.DoCoarseUpdate() )
+	    {
+	      paralleltop.UpdateCoarseGrid();
+	    }
+	  else
+	    {
+	      //  paralleltop.UpdateRefinement();
+	    }
+	  // paralleltop.Print();
+	}
+
+ 
+#endif
+
+
+
+
+    }
+ 
+ 
+  
+  /* 
+for (i = 1; i <= ne; i++)
+    {
+    (*testout) << "Element " << i << endl;
+    (*testout) << "PNums " << endl; 
+    for( int l=1;l<=8;l++) *testout << mesh.VolumeElement(i).PNum(l) << "\t"; 
+    *testout << endl; 
+    (*testout) << "edges: " << endl;
+    for (j = 0; j < 9; j++)
+    (*testout) << edges.Elem(i)[j] << " ";
+    (*testout) << "faces: " << endl;
+    for (j = 0; j < 6; j++)m
+    (*testout) << faces.Elem(i)[j] << " ";
+    }
+
+    for (i = 1; i <= nse; i++)
+    {
+    (*testout) << "SElement " << i << endl;
+    (*testout) << "PNums " << endl; 
+    for( int l=1;l<=4;l++) *testout << mesh.SurfaceElement(i).PNum(l) << "\t"; 
+    *testout << endl; 
+    }
+  */
+  timestamp = NextTimeStamp();
+}
+
+  
+
+
+int MeshTopology :: GetNVertices (ELEMENT_TYPE et)
+{
+  switch (et)
+    {
+    case SEGMENT:
+    case SEGMENT3:
+      return 2;
+
+    case TRIG:
+    case TRIG6:
+      return 3;
+
+    case QUAD:
+    case QUAD6:
+    case QUAD8:
+      return 4;
+
+    case TET:
+    case TET10:
+      return 4;
+
+    case PYRAMID:
+      return 5;
+
+    case PRISM:
+    case PRISM12:
+      return 6;
+
+    case HEX:
+      return 8;
+
+    default:
+      cerr << "Ng_ME_GetNVertices, illegal element type " << et << endl;
+    }
+  return 0;
+}
+
+int MeshTopology :: GetNEdges (ELEMENT_TYPE et)
+{
+  switch (et)
+    {
+    case SEGMENT:
+    case SEGMENT3:
+      return 1;
+
+    case TRIG:
+    case TRIG6:
+      return 3;
+
+    case QUAD:
+    case QUAD6:
+    case QUAD8:
+      return 4;
+
+    case TET:
+    case TET10:
+      return 6;
+
+    case PYRAMID:
+      return 8;
+
+    case PRISM:
+    case PRISM12:
+      return 9;
+
+    case HEX:
+      return 12;
+
+    default:
+      cerr << "Ng_ME_GetNEdges, illegal element type " << et << endl;
+    }
+  return 0;
+}
+
+
+int MeshTopology :: GetNFaces (ELEMENT_TYPE et)
+{
+  switch (et)
+    {
+    case SEGMENT:
+    case SEGMENT3:
+      return 0;
+
+    case TRIG:
+    case TRIG6:
+      return 1;
+
+    case QUAD:
+    case QUAD6:
+    case QUAD8:
+      return 1;
+
+    case TET:
+    case TET10:
+      return 4;
+
+    case PYRAMID:
+      return 5;
+
+    case PRISM:
+    case PRISM12:
+      return 5;
+
+    case HEX:
+      return 6;
+
+    default:
+      cerr << "Ng_ME_GetNVertices, illegal element type " << et << endl;
+    }
+  return 0;
+}
+
+
+
+
+const Point3d * MeshTopology :: GetVertices (ELEMENT_TYPE et)
+{
+  static Point3d segm_points [] = 
+    { Point3d (1, 0, 0),
+      Point3d (0, 0, 0) };
+  
+  static Point3d trig_points [] = 
+    { Point3d ( 1, 0, 0 ),
+      Point3d ( 0, 1, 0 ),
+      Point3d ( 0, 0, 0 ) };
+
+  static Point3d quad_points [] = 
+    { Point3d ( 0, 0, 0 ),
+      Point3d ( 1, 0, 0 ),
+      Point3d ( 1, 1, 0 ),
+      Point3d ( 0, 1, 0 ) };
+
+  static Point3d tet_points [] = 
+    { Point3d ( 1, 0, 0 ),
+      Point3d ( 0, 1, 0 ),
+      Point3d ( 0, 0, 1 ),
+      Point3d ( 0, 0, 0 ) };
+
+  static Point3d pyramid_points [] =
+    {
+      Point3d ( 0, 0, 0 ),
+      Point3d ( 1, 0, 0 ),
+      Point3d ( 1, 1, 0 ),
+      Point3d ( 0, 1, 0 ),
+      Point3d ( 0, 0, 1-1e-7 ),
+    };    
+  
+  static Point3d prism_points[] = 
+    {
+      Point3d ( 1, 0, 0 ),
+      Point3d ( 0, 1, 0 ),
+      Point3d ( 0, 0, 0 ),
+      Point3d ( 1, 0, 1 ),
+      Point3d ( 0, 1, 1 ),
+      Point3d ( 0, 0, 1 )
+    };
+
+
+  static Point3d hex_points [] = 
+    { Point3d ( 0, 0, 0 ),
+      Point3d ( 1, 0, 0 ),
+      Point3d ( 1, 1, 0 ),
+      Point3d ( 0, 1, 0 ),
+      Point3d ( 0, 0, 1 ),
+      Point3d ( 1, 0, 1 ),
+      Point3d ( 1, 1, 1 ),
+      Point3d ( 0, 1, 1 ) };
+
+
+  switch (et)
+    {
+    case SEGMENT:
+    case SEGMENT3:
+      return segm_points;
+
+    case TRIG:
+    case TRIG6:
+      return trig_points;
+
+    case QUAD:
+    case QUAD6:
+    case QUAD8:
+      return quad_points;
+
+    case TET:
+    case TET10:
+      return tet_points;
+
+    case PYRAMID:
+      return pyramid_points;
+
+    case PRISM:
+    case PRISM12:
+      return prism_points;
+
+    case HEX:
+      return hex_points;
+    default:
+      cerr << "Ng_ME_GetVertices, illegal element type " << et << endl;
+    }
+  return 0;
+}
+
+
+
+
+
+
+
+
+void MeshTopology :: GetElementEdges (int elnr, ARRAY<int> & eledges) const
+{
+  int ned = GetNEdges (mesh.VolumeElement(elnr).GetType());
+  eledges.SetSize (ned);
+  for (int i = 0; i < ned; i++)
+    eledges[i] = abs (edges.Get(elnr)[i]);
+}
+void MeshTopology :: GetElementFaces (int elnr, ARRAY<int> & elfaces, bool withorientation) const
+{
+  int i;
+  int nfa = GetNFaces (mesh.VolumeElement(elnr).GetType());
+  elfaces.SetSize (nfa);
+  for (i = 1; i <= nfa; i++)
+    {
+      elfaces.Elem(i) = (faces.Get(elnr)[i-1]-1) / 8 + 1;
+      if(withorientation)
+	{
+	  int orient = (faces.Get(elnr)[i-1]-1) % 8;
+	  if(orient == 1 || orient == 2 || orient == 4 || orient == 7)
+	    elfaces.Elem(i) *= -1;
+	}
+    }
+}
+
+void MeshTopology :: GetElementEdgeOrientations (int elnr, ARRAY<int> & eorient) const
+{
+  int i;
+  int ned = GetNEdges (mesh.VolumeElement(elnr).GetType());
+  eorient.SetSize (ned);
+  for (i = 1; i <= ned; i++)
+    eorient.Elem(i) = (edges.Get(elnr)[i-1] > 0) ? 1 : -1;
+}
+
+void MeshTopology :: GetElementFaceOrientations (int elnr, ARRAY<int> & forient) const
+{
+  int i;
+  int nfa = GetNFaces (mesh.VolumeElement(elnr).GetType());
+  forient.SetSize (nfa);
+  for (i = 1; i <= nfa; i++)
+    forient.Elem(i) = (faces.Get(elnr)[i-1]-1) % 8;
+}
+
+
+
+int MeshTopology :: GetElementEdges (int elnr, int * eledges, int * orient) const
+{
+  int i;
+  //  int ned = GetNEdges (mesh.VolumeElement(elnr).GetType());
+
+  if (mesh.GetDimension()==3 || 1)
+    {
+      if (orient)
+	{
+	  for (i = 0; i < 12; i++)
+	    {
+	      if (!edges.Get(elnr)[i]) return i;
+	      eledges[i] = abs (edges.Get(elnr)[i]);
+	      orient[i] = (edges.Get(elnr)[i] > 0 ) ? 1 : -1;
+	    }
+	}
+      else
+	{
+	  for (i = 0; i < 12; i++)
+	    {
+	      if (!edges.Get(elnr)[i]) return i;
+	      eledges[i] = abs (edges.Get(elnr)[i]);
+	    }
+	}
+      return 12;
+    }
+  else
+    {
+		throw NgException("rethink implementation");
+		/*
+      if (orient)
+	{
+	  for (i = 0; i < 4; i++)
+	    {
+	      if (!surfedges.Get(elnr)[i]) return i;
+	      eledges[i] = abs (surfedges.Get(elnr)[i]);
+	      orient[i] = (surfedges.Get(elnr)[i] > 0 ) ? 1 : -1;
+	    }
+	}
+      else
+	{
+	  if (!surfedges.Get(elnr)[i]) return i;
+	  for (i = 0; i < 4; i++)
+	    eledges[i] = abs (surfedges.Get(elnr)[i]);
+	}
+	*/
+      return 4;
+      //      return GetSurfaceElementEdges (elnr, eledges, orient);
+    }
+}
+
+int MeshTopology :: GetElementFaces (int elnr, int * elfaces, int * orient) const
+{
+  int i;
+  //  int nfa = GetNFaces (mesh.VolumeElement(elnr).GetType());
+  if (orient)
+    {
+      for (i = 0; i < 6; i++)
+	{
+	  if (!faces.Get(elnr)[i]) return i;
+	  elfaces[i] = (faces.Get(elnr)[i]-1) / 8 + 1;
+	  orient[i] = (faces.Get(elnr)[i]-1) % 8;
+	}
+    }
+  else
+    {
+      for (i = 0; i < 6; i++)
+	{
+	  if (!faces.Get(elnr)[i]) return i;
+	  elfaces[i] = (faces.Get(elnr)[i]-1) / 8 + 1;
+	}
+    }
+  return 6;
+}
+
+void MeshTopology :: GetSurfaceElementEdges (int elnr, ARRAY<int> & eledges) const
+{
+  int i;
+  if (mesh.GetDimension()==3 || 1)
+    {
+      int ned = GetNEdges (mesh.SurfaceElement(elnr).GetType());
+      eledges.SetSize (ned);
+      for (i = 1; i <= ned; i++)
+	eledges.Elem(i) = abs (surfedges.Get(elnr)[i-1]);
+    }
+  else
+    {
+      cout << "surfeledge(" << elnr << ") = " << flush;
+      eledges.SetSize(1); 
+      eledges.Elem(1) = abs (segedges.Get(elnr));
+      cout << eledges.Elem(1) << endl;
+    }
+}
+
+int MeshTopology :: GetSurfaceElementFace (int elnr) const
+{
+  return (surffaces.Get(elnr)-1) / 8 + 1;  
+}
+
+void MeshTopology :: 
+GetSurfaceElementEdgeOrientations (int elnr, ARRAY<int> & eorient) const
+{
+  int ned = GetNEdges (mesh.SurfaceElement(elnr).GetType());
+  eorient.SetSize (ned);
+  for (int i = 1; i <= ned; i++)
+    eorient.Elem(i) = (surfedges.Get(elnr)[i-1] > 0) ? 1 : -1;
+}
+
+int MeshTopology :: GetSurfaceElementFaceOrientation (int elnr) const
+{
+  return (surffaces.Get(elnr)-1) % 8;
+}
+
+int MeshTopology :: GetSurfaceElementEdges (int elnr, int * eledges, int * orient) const
+{
+  int i;
+  if (mesh.GetDimension() == 3 || 1)
+    {
+      if (orient)
+	{
+	  for (i = 0; i < 4; i++)
+	    {
+	      if (!surfedges.Get(elnr)[i]) return i;
+	      eledges[i] = abs (surfedges.Get(elnr)[i]);
+	      orient[i] = (surfedges.Get(elnr)[i] > 0 ) ? 1 : -1;
+	    }
+	}
+      else
+	{
+	  for (i = 0; i < 4; i++)
+	    {
+	      if (!surfedges.Get(elnr)[i]) return i;
+	      eledges[i] = abs (surfedges.Get(elnr)[i]);
+	    }
+	}
+      return 4;
+    }
+  else
+    {
+      eledges[0] = abs (segedges.Get(elnr));
+      if (orient)
+	orient[0] = segedges.Get(elnr) > 0 ? 1 : -1;
+    }
+  return 1;
+}
+
+
+void MeshTopology :: GetFaceVertices (int fnr, ARRAY<int> & vertices) const
+{
+  vertices.SetSize(4);
+  int i;
+  for (i = 1; i <= 4; i++)
+    vertices.Elem(i) = face2vert.Get(fnr)[i-1];
+  if (vertices.Elem(4) == 0)
+    vertices.SetSize(3);
+}
+
+void MeshTopology :: GetFaceVertices (int fnr, int * vertices) const
+{
+  for (int i = 0; i <= 3; i++)
+    vertices[i] = face2vert.Get(fnr)[i];
+}
+
+
+void MeshTopology :: GetEdgeVertices (int ednr, int & v1, int & v2) const
+{
+  v1 = edge2vert.Get(ednr)[0];
+  v2 = edge2vert.Get(ednr)[1];
+}
+
+
+void MeshTopology :: GetFaceEdges (int fnr, ARRAY<int> & fedges, bool withorientation) const
+{
+  ArrayMem<int,4> pi(4);
+  ArrayMem<int,12> eledges;
+  
+  fedges.SetSize (0);
+  GetFaceVertices(fnr, pi);
+
+  // Sort Edges according to global vertex numbers 
+  // e1 = fmax, f2 
+  // e2 = fmax, f1 
+  // e3 = op e1(f2,f3) 
+  // e4 = op e2(f1,f3) 
+
+  /*  ArrayMem<int,4> fp; 
+  fp[0] = pi[0]; 
+  for(int k=1;k<pi.Size();k++) 
+    if(fp[k]>fp[0]) swap(fp[k],fp[0]); 
+  
+    fp[1] = fp[0]+ */ 
+  
+
+  //  GetVertexElements (pi[0], els);
+  FlatArray<int> els= GetVertexElements (pi[0]);
+
+  // find one element having all vertices of the face
+  for (int i = 0; i < els.Size(); i++)
+    {
+      const Element & el = mesh.VolumeElement(els[i]);
+      int nref_faces = GetNFaces (el.GetType());
+      const ELEMENT_FACE * ref_faces = GetFaces (el.GetType());
+      int nfa_ref_edges = GetNEdges (GetFaceType(fnr));
+      
+      int cntv = 0,fa=-1; 
+      for(int m=0;m<nref_faces;m++)
+	{ 
+	  cntv=0;
+	  for(int j=0;j<nfa_ref_edges && ref_faces[m][j]>0;j++)
+	    for(int k=0;k<pi.Size();k++)
+	      {
+		if(el[ref_faces[m][j]-1] == pi[k])
+		  cntv++;
+	      }
+	  if (cntv == pi.Size())
+	    {
+	      fa=m;
+	      break;
+	    }
+	}
+     
+      if(fa>=0)
+	{
+	  const ELEMENT_EDGE * fa_ref_edges = GetEdges(GetFaceType(fnr)); 
+	  fedges.SetSize(nfa_ref_edges);
+	  GetElementEdges (els[i], eledges);
+	  
+	  for (int j = 0; j < eledges.Size(); j++)
+	    {
+	      int vi1, vi2;
+	      GetEdgeVertices (eledges[j], vi1, vi2);
+	    
+	      bool has1 = 0;
+	      bool has2 = 0;
+	      for (int k = 0; k < pi.Size(); k++)
+		{
+		  if (vi1 == pi[k]) has1 = 1;
+		  if (vi2 == pi[k]) has2 = 1;
+		  
+		}
+	      
+	      if (has1 && has2) // eledges[j] is on face 
+		{
+		  // fedges.Append (eledges[j]);
+		  for(int k=0;k<nfa_ref_edges;k++)
+		    {
+		      int w1 = el[ref_faces[fa][fa_ref_edges[k][0]-1]-1]; 
+		      int w2 = el[ref_faces[fa][fa_ref_edges[k][1]-1]-1]; 
+
+		      if(withorientation)
+			{
+			  if(w1==vi1 && w2==vi2)
+			    fedges[k] = eledges[j];
+			  if(w1==vi2 && w2==vi1)
+			    fedges[k] = -eledges[j];
+			}
+		      else
+			if((w1==vi1 && w2==vi2) || (w1==vi2 && w2==vi1))
+			  fedges[k] = eledges[j];
+		    }
+		}
+	    }
+	  
+	  // *testout << " Face " << fnr << endl; 
+	  // *testout << " GetFaceEdges " << fedges << endl;
+	  
+	  return;
+	}
+    }   
+}
+
+
+ELEMENT_TYPE MeshTopology :: GetFaceType (int fnr) const
+{
+  if (face2vert.Get(fnr)[3] == 0) return TRIG; else return QUAD;
+}
+
+
+void MeshTopology :: GetVertexElements (int vnr, ARRAY<int> & elements) const
+{
+  if (vert2element)
+    {
+      int i; 
+      int ne = vert2element->EntrySize(vnr);
+      elements.SetSize(ne);
+      for (i = 1; i <= ne; i++)
+	elements.Elem(i) = vert2element->Get(vnr, i);
+    }
+}
+
+
+FlatArray<int> MeshTopology :: GetVertexElements (int vnr) const
+{
+  if (vert2element)
+    return (*vert2element)[vnr];
+  return FlatArray<int> (0,0);
+}
+
+FlatArray<int> MeshTopology :: GetVertexSurfaceElements (int vnr) const
+{
+  if (vert2surfelement)
+    return (*vert2surfelement)[vnr];
+  return FlatArray<int> (0,0);
+}
+
+
+void MeshTopology :: GetVertexSurfaceElements( int vnr, 
+					       ARRAY<int>& elements ) const
+{
+  if (vert2surfelement)
+    {
+      int i;
+      int ne = vert2surfelement->EntrySize(vnr);
+      elements.SetSize(ne);
+      for (i = 1; i <= ne; i++)
+	elements.Elem(i) = vert2surfelement->Get(vnr, i);
+    }
+}
+
+
+int MeshTopology :: GetVerticesEdge ( int v1, int v2 ) const
+{
+  ARRAY<int> elements_v1, elementedges;
+  GetVertexElements ( v1, elements_v1);
+  int edv1, edv2;
+
+  for ( int i = 0; i < elements_v1.Size(); i++ )
+    {
+      GetElementEdges( elements_v1[i], elementedges );
+      for ( int ed = 0; ed < elementedges.Size(); ed ++)
+	{
+	  GetEdgeVertices( elementedges[ed], edv1, edv2 );
+	  if ( ( edv1 == v1 && edv2 == v2 ) || ( edv1 == v2 && edv2 == v1 ) )
+	    return elementedges[ed];
+	}
+    }
+
+  return -1;
+}
+
+
+
+void MeshTopology :: GetSegmentVolumeElements ( int segnr, ARRAY<int> & volels ) const
+{
+  int v1, v2;
+  GetEdgeVertices ( GetSegmentEdge (segnr), v1, v2 );
+  ARRAY<int> volels1, volels2;
+  GetVertexElements ( v1, volels1 );
+  GetVertexElements ( v2, volels2 );
+  volels.SetSize(0);
+
+  for ( int eli1=1; eli1 <= volels1.Size(); eli1++)
+    if ( volels2.Contains( volels1.Elem(eli1) ) )
+      volels.Append ( volels1.Elem(eli1) );
+
+}
+}
diff --git a/contrib/Netgen/libsrc/meshing/topology.hpp b/contrib/Netgen/libsrc/meshing/topology.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..be1a3456dcfc099a441a4d3de907a9c724b404ac
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/topology.hpp
@@ -0,0 +1,325 @@
+#ifndef TOPOLOGY
+#define TOPOLOGY
+
+/**************************************************************************/
+/* File:   topology.hh                                                    */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   27. Apr. 01                                                    */
+/**************************************************************************/
+
+/*
+    Mesh topology
+    (Elements, Faces, Edges, Vertices
+*/
+
+
+class MeshTopology
+{
+  const Mesh & mesh;
+  bool buildedges;
+  bool buildfaces;
+
+  MoveableArray<INDEX_2> edge2vert;
+  MoveableArray<INDEX_4> face2vert;
+  MoveableArray<int[12]> edges;
+  MoveableArray<int[6]> faces;
+  MoveableArray<int[4]> surfedges;
+  MoveableArray<int> segedges;
+  MoveableArray<int> surffaces;
+  MoveableArray<INDEX_2> surf2volelement;
+  MoveableArray<int> face2surfel;
+  TABLE<int,PointIndex::BASE> *vert2element;
+  TABLE<int,PointIndex::BASE> *vert2surfelement;
+  TABLE<int,PointIndex::BASE> *vert2segment;
+  int timestamp;
+public:
+  int GetNSurfedges() const {return surfedges.Size();}
+
+  MeshTopology (const Mesh & amesh);
+  ~MeshTopology ();
+
+  void SetBuildEdges (bool be)
+  { buildedges = be; }
+  void SetBuildFaces (bool bf)
+  { buildfaces = bf; }
+
+  bool HasEdges () const
+  { return buildedges; }
+  bool HasFaces () const
+  { return buildfaces; }
+
+  void Update();
+
+
+  int GetNEdges () const
+  { return edge2vert.Size(); }
+  int GetNFaces () const
+  { return face2vert.Size(); }
+
+  static int GetNVertices (ELEMENT_TYPE et);
+  static int GetNEdges (ELEMENT_TYPE et);
+  static int GetNFaces (ELEMENT_TYPE et);
+
+  static const Point3d * GetVertices (ELEMENT_TYPE et);
+  inline static const ELEMENT_EDGE * GetEdges (ELEMENT_TYPE et);
+  inline static const ELEMENT_FACE * GetFaces (ELEMENT_TYPE et);
+
+  
+  int GetSegmentEdge (int segnr) const { return abs(segedges[segnr-1]); }
+  int GetSegmentEdgeOrientation (int segnr) const { return sgn(segedges[segnr-1]); }
+
+  void GetSegmentEdge (int segnr, int & enr, int & orient) const
+  {
+    enr = abs(segedges.Get(segnr));
+    orient = segedges.Get(segnr) > 0 ? 1 : -1;
+  }
+
+  void GetElementEdges (int elnr, ARRAY<int> & edges) const;
+  void GetElementFaces (int elnr, ARRAY<int> & faces, bool withorientation = false) const;
+  void GetElementEdgeOrientations (int elnr, ARRAY<int> & eorient) const;
+  void GetElementFaceOrientations (int elnr, ARRAY<int> & forient) const;
+
+  int GetElementEdges (int elnr, int * edges, int * orient) const;
+  int GetElementFaces (int elnr, int * faces, int * orient) const;
+
+  void GetFaceVertices (int fnr, ARRAY<int> & vertices) const;
+  void GetFaceVertices (int fnr, int * vertices) const;
+  void GetEdgeVertices (int fnr, int & v1, int & v2) const;
+  void GetFaceEdges (int fnr, ARRAY<int> & edges, bool withorientation = false) const;
+
+  ELEMENT_TYPE GetFaceType (int fnr) const;
+
+  void GetSurfaceElementEdges (int elnr, ARRAY<int> & edges) const;
+  int GetSurfaceElementFace (int elnr) const;
+  void GetSurfaceElementEdgeOrientations (int elnr, ARRAY<int> & eorient) const;
+  int GetSurfaceElementFaceOrientation (int elnr) const;
+
+  int GetSurfaceElementEdges (int elnr, int * edges, int * orient) const;
+
+  void GetSurface2VolumeElement (int selnr, int & elnr1, int & elnr2) const
+  { 
+    elnr1 = surf2volelement.Get(selnr)[0];
+    elnr2 = surf2volelement.Get(selnr)[1];
+  }
+
+  int GetFace2SurfaceElement (int fnr) const { return face2surfel[fnr-1]; }
+  
+  void GetVertexElements (int vnr, ARRAY<int> & elements) const;
+  FlatArray<int> GetVertexElements (int vnr) const;
+
+  void GetVertexSurfaceElements( int vnr, ARRAY<int>& elements ) const;
+  FlatArray<int> GetVertexSurfaceElements (int vnr) const;
+
+
+  
+  int GetVerticesEdge ( int v1, int v2) const;
+  void GetSegmentVolumeElements ( int segnr, ARRAY<int> & surfels ) const;
+};
+
+
+
+
+
+
+
+
+
+
+
+
+
+const ELEMENT_EDGE * MeshTopology :: GetEdges (ELEMENT_TYPE et)
+{
+  static int segm_edges[1][2] =
+    { { 1, 2 }};
+
+  static int trig_edges[3][2] =
+    { { 3, 1 },
+      { 2, 3 },        
+      { 1, 2 }};
+
+  static int quad_edges[4][2] =
+    { { 1, 2 },
+      { 3, 4 },
+      { 4, 1 },
+      { 2, 3 }};
+
+
+  static int tet_edges[6][2] =
+    { { 4, 1 },
+      { 4, 2 },
+      { 4, 3 }, 
+      { 1, 2 },
+      { 1, 3 },
+      { 2, 3 }};
+
+  static int prism_edges[9][2] =
+    { { 3, 1 },
+      { 1, 2 },
+      { 3, 2 },
+      { 6, 4 },
+      { 4, 5 },
+      { 6, 5 },
+      { 3, 6 },
+      { 1, 4 },
+      { 2, 5 }};
+
+  static int pyramid_edges[8][2] =
+    { { 1, 2 },
+      { 2, 3 },
+      { 1, 4 },
+      { 4, 3 },
+      { 1, 5 },
+      { 2, 5 },
+      { 3, 5 },
+      { 4, 5 }};
+
+  static int hex_edges[12][2] =
+    {
+      { 1, 2 },
+      { 3, 4 },
+      { 4, 1 },
+      { 2, 3 },
+      { 5, 6 },
+      { 7, 8 },
+      { 8, 5 },
+      { 6, 7 },
+      { 1, 5 },
+      { 2, 6 },
+      { 3, 7 },
+      { 4, 8 },
+    };
+
+  switch (et)
+    {
+    case SEGMENT:
+    case SEGMENT3:
+      return segm_edges;
+
+    case TRIG:
+    case TRIG6:
+      return trig_edges;
+
+    case QUAD:
+    case QUAD6:
+    case QUAD8:
+      return quad_edges;
+
+    case TET:
+    case TET10:
+      return tet_edges;
+
+    case PYRAMID:
+      return pyramid_edges;
+
+    case PRISM:
+    case PRISM12:
+      return prism_edges;
+
+    case HEX:
+      return hex_edges;
+    default:
+      cerr << "Ng_ME_GetEdges, illegal element type " << et << endl;
+    }
+   return 0;  
+}
+
+
+const ELEMENT_FACE * MeshTopology :: GetFaces (ELEMENT_TYPE et)
+{
+  static const int trig_faces[1][4] = 
+    { { 1, 2, 3, 0 } };
+  static const int quad_faces[1][4] = 
+    { { 1, 2, 3, 4 } };
+
+  static const int tet_faces[4][4] =
+    { { 4, 2, 3, 0 },
+      { 4, 3, 1, 0 },
+      { 4, 1, 2, 0 },
+      { 1, 3, 2, 0 } };
+  
+  static const int prism_faces[5][4] =
+    {
+      { 1, 3, 2, 0 },
+      { 4, 5, 6, 0 },
+      { 3, 1, 4, 6 },
+      { 1, 2, 5, 4 },
+      { 2, 3, 6, 5 } 
+    };
+
+  static const int pyramid_faces[5][4] =
+    {
+      { 1, 2, 5, 0 },
+      { 2, 3, 5, 0 },
+      { 3, 4, 5, 0 },
+      { 4, 1, 5, 0 },
+      { 1, 4, 3, 2 } 
+    };
+
+  static const int hex_faces[6][4] =
+    {
+      { 1, 4, 3, 2 },
+      { 5, 6, 7, 8 },
+      { 1, 2, 6, 5 },
+      { 2, 3, 7, 6 },
+      { 3, 4, 8, 7 },
+      { 4, 1, 5, 8 }
+    };
+
+
+  
+  switch (et)
+    {
+    case TRIG:
+    case TRIG6:
+      return trig_faces;
+
+    case QUAD:
+    case QUAD6:
+    case QUAD8:
+      return quad_faces;
+
+
+    case TET:
+    case TET10:
+      return tet_faces;
+
+    case PRISM:
+    case PRISM12:
+      return prism_faces;
+
+    case PYRAMID:
+      return pyramid_faces;
+
+    case SEGMENT:
+    case SEGMENT3:
+
+    case HEX:
+      return hex_faces;
+
+    default:
+      cerr << "Ng_ME_GetVertices, illegal element type " << et << endl;
+    }
+  return 0;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#endif
diff --git a/contrib/Netgen/libsrc/meshing/triarls.cpp b/contrib/Netgen/libsrc/meshing/triarls.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..d82806e9bcbd9cf9f5b8a90306e1cee23c0bf4bc
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/triarls.cpp
@@ -0,0 +1,468 @@
+namespace netgen
+{
+const char * triarules[] = {
+"rule \"Free Triangle (1)\"\n",\
+"\n",\
+"quality 1\n",\
+"\n",\
+"mappoints\n",\
+"(0, 0);\n",\
+"(1, 0) { 1.0, 0, 1.0 };\n",\
+"\n",\
+"maplines\n",\
+"(1, 2) del;\n",\
+"\n",\
+"newpoints\n",\
+"(0.5, 0.866) { 0.5 X2 } { };\n",\
+"\n",\
+"newlines\n",\
+"(1, 3);\n",\
+"(3, 2);\n",\
+"\n",\
+"freearea\n",\
+"(0, 0);\n",\
+"(1, 0) { 1 X2 } { };\n",\
+"(1.5, 0.7) { 0.5 X2 } { };\n",\
+"(0.5, 1.5) { 0.5 X2 } { };\n",\
+"(-0.5, 0.7) { 0.5 X2 } { };\n",\
+"\n",\
+"freearea2\n",\
+"(0, 0);\n",\
+"(1, 0) { 1 X2 } { };\n",\
+"(0.5, 0.866) { 0.5 X2 } { };\n",\
+"(0.5, 0.866) { 0.5 X2 } { };\n",\
+"(0.5, 0.866) { 0.5 X2 } { };\n",\
+"\n",\
+"\n",\
+"elements\n",\
+"(1, 2, 3);\n",\
+"\n",\
+"endrule\n",\
+"\n",\
+"\n",\
+"rule \"Free Triangle (5)\"\n",\
+"\n",\
+"quality 5\n",\
+"\n",\
+"mappoints\n",\
+"(0, 0);\n",\
+"(1, 0) { 1.0, 0, 1.0 };\n",\
+"\n",\
+"maplines\n",\
+"(1, 2) del;\n",\
+"\n",\
+"newpoints\n",\
+"(0.5, 0.5) { 0.5 X2 } { };\n",\
+"\n",\
+"newlines\n",\
+"(1, 3);\n",\
+"(3, 2);\n",\
+"\n",\
+"freearea\n",\
+"(0, 0);\n",\
+"(1, 0) { 1 X2 } { };\n",\
+"(1, 0.7) { 1 X2 } { };\n",\
+"(0, 0.7) { } { };\n",\
+"\n",\
+"freearea2\n",\
+"(0, 0);\n",\
+"(1, 0) { 1 X2 } { };\n",\
+"(0.5, 0.5) { 0.5 X2 } { };\n",\
+"(0.5, 0.5) { 0.5 X2 } { };\n",\
+"\n",\
+"\n",\
+"elements\n",\
+"(1, 2, 3);\n",\
+"\n",\
+"endrule\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"rule \"Free Triangle (10)\"\n",\
+"\n",\
+"quality 10\n",\
+"\n",\
+"mappoints\n",\
+"(0, 0);\n",\
+"(1, 0) { 1.0, 0, 1.0 };\n",\
+"\n",\
+"maplines\n",\
+"(1, 2) del;\n",\
+"\n",\
+"newpoints\n",\
+"(0.5, 0.3) { 0.5 X2 } { };\n",\
+"\n",\
+"newlines\n",\
+"(1, 3);\n",\
+"(3, 2);\n",\
+"\n",\
+"freearea\n",\
+"(0, 0);\n",\
+"(1, 0) { 1 X2 } { };\n",\
+"(1, 0.5) { 1 X2 } { };\n",\
+"(0, 0.5) { } { };\n",\
+"\n",\
+"freearea2\n",\
+"(0, 0);\n",\
+"(1, 0) { 1 X2 } { };\n",\
+"(0.5, 0.3) { 0.5 X2 } { };\n",\
+"(0.5, 0.3) { 0.5 X2 } { };\n",\
+"\n",\
+"\n",\
+"elements\n",\
+"(1, 2, 3);\n",\
+"\n",\
+"endrule\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"rule \"Free Triangle (20)\"\n",\
+"\n",\
+"quality 20\n",\
+"\n",\
+"mappoints\n",\
+"(0, 0);\n",\
+"(1, 0) { 1.0, 0, 1.0 };\n",\
+"\n",\
+"maplines\n",\
+"(1, 2) del;\n",\
+"\n",\
+"newpoints\n",\
+"(0.5, 0.1) { 0.5 X2 } { };\n",\
+"\n",\
+"newlines\n",\
+"(1, 3);\n",\
+"(3, 2);\n",\
+"\n",\
+"freearea\n",\
+"(0, 0);\n",\
+"(1, 0) { 1 X2 } { };\n",\
+"(1, 0.2) { 1 X2 } { };\n",\
+"(0, 0.2) { } { };\n",\
+"\n",\
+"freearea2\n",\
+"(0, 0);\n",\
+"(1, 0) { 1 X2 } { };\n",\
+"(0.5, 0.1) { 0.5 X2 } { };\n",\
+"(0.5, 0.1) { 0.5 X2 } { };\n",\
+"\n",\
+"\n",\
+"elements\n",\
+"(1, 2, 3);\n",\
+"\n",\
+"endrule\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"rule \"Right 60 (1)\"\n",\
+"\n",\
+"quality 1\n",\
+"\n",\
+"mappoints\n",\
+"(0, 0);\n",\
+"(1, 0) { 0.5, 0, 1.0 };\n",\
+"(0.5, 0.866) { 0.6, 0, 0.8 };\n",\
+"\n",\
+"maplines\n",\
+"(1, 2) del;\n",\
+"(2, 3) del;\n",\
+"\n",\
+"newpoints\n",\
+"\n",\
+"newlines\n",\
+"(1, 3);\n",\
+"\n",\
+"freearea\n",\
+"(0, 0);\n",\
+"(1, 0) { 1 X2 } { };\n",\
+"(0.5, 0.866) { 1 X3 } { 1 Y3 };\n",\
+"(-0.125, 0.6495) { -0.5 X2, 0.75 X3 } { -0.5 Y2, 0.75 Y3 };\n",\
+"\n",\
+"freearea2\n",\
+"(0, 0);\n",\
+"(1, 0) { 1 X2 } { };\n",\
+"(0.5, 0.866) { 1 X3 } { 1 Y3 };\n",\
+"(0.25, 0.433) { 0.5 X3 } { 0.5 Y3 };\n",\
+"\n",\
+"elements\n",\
+"(1, 2, 3);\n",\
+"\n",\
+"endrule\n",\
+"\n",\
+"\n",\
+"\n",\
+"rule \"Left 60 (1)\"\n",\
+"\n",\
+"quality 1\n",\
+"\n",\
+"mappoints\n",\
+"(0, 0);\n",\
+"(1, 0);\n",\
+"(0.5, 0.866);\n",\
+"\n",\
+"maplines\n",\
+"(1, 2) del;\n",\
+"(3, 1) del;\n",\
+"\n",\
+"newpoints\n",\
+"\n",\
+"newlines\n",\
+"(3, 2);\n",\
+"\n",\
+"freearea\n",\
+"(0, 0);\n",\
+"(1, 0) { 1 X2 } { };\n",\
+"(1.125, 0.6495) { 0.75 X2, 0.75 X3 } { 0.75 Y3 };\n",\
+"(0.5, 0.866) { 1 X3 } { 1 Y3 };\n",\
+"\n",\
+"freearea2\n",\
+"(0, 0);\n",\
+"(1, 0) { 1 X2 } { };\n",\
+"(0.75, 0.433) { 0.5 X2, 0.5 X3 } { 0.5 Y2, 0.5 Y3 };\n",\
+"(0.5, 0.866) { 1 X3 } { 1 Y3 };\n",\
+"\n",\
+"elements\n",\
+"(1, 2, 3);\n",\
+"\n",\
+"endrule\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"rule \"Right 120 (1)\"\n",\
+"\n",\
+"quality 1\n",\
+"\n",\
+"mappoints\n",\
+"(0, 0);\n",\
+"(1, 0);\n",\
+"(1.5, 0.866);\n",\
+"\n",\
+"maplines\n",\
+"(1, 2) del;\n",\
+"(2, 3) del;\n",\
+"\n",\
+"newpoints\n",\
+"(0.5, 0.866) { 1 X3, -1 X2 } { 1 Y3 };\n",\
+"\n",\
+"newlines\n",\
+"(1, 4);\n",\
+"(4, 3);\n",\
+"\n",\
+"freearea\n",\
+"(0, 0);\n",\
+"(1, 0) { 1 X2 } { };\n",\
+"(1.5, 0.866) { 1 X3 } { 1 Y3 };\n",\
+"(1, 1.732) { -2 X2, 2 X3 } { 2 Y3 };\n",\
+"(0, 1.732) { -3 X2, 2 X3 } { 2 Y3 };\n",\
+"(-0.5, 0.866) { -2 X2, 1 X3 } {1 Y3 };\n",\
+"\n",\
+"elements\n",\
+"(1, 2, 4);\n",\
+"(2, 3, 4);\n",\
+"\n",\
+"endrule\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"rule \"Left 120 (1)\"\n",\
+"\n",\
+"quality 1\n",\
+"\n",\
+"mappoints\n",\
+"(0, 0);\n",\
+"(1, 0);\n",\
+"(-0.5, 0.866);\n",\
+"\n",\
+"maplines\n",\
+"(1, 2) del;\n",\
+"(3, 1) del;\n",\
+"\n",\
+"newpoints\n",\
+"(0.5, 0.866) { 1 X3, 1 X2 } { 1 Y3 };\n",\
+"\n",\
+"newlines\n",\
+"(3, 4);\n",\
+"(4, 2);\n",\
+"\n",\
+"freearea\n",\
+"(0, 0);\n",\
+"(1, 0) { 1 X2 } { };\n",\
+"(1.5, 0.866) { 2 X2, 1 X3 } { 1 Y3 };\n",\
+"(1, 1.732) { 2 X2, 2 X3 } { 2 Y3 };\n",\
+"(0, 1.732) { -1 X2, 2 X3 } { 2 Y3 };\n",\
+"(-0.5, 0.866) { 1 X3 } {1 Y3 };\n",\
+"\n",\
+"elements\n",\
+"(1, 2, 4);\n",\
+"(2, 3, 4);\n",\
+"\n",\
+"endrule\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"rule \"Left Right 120 (1)\"\n",\
+"\n",\
+"quality 1\n",\
+"\n",\
+"mappoints\n",\
+"(0, 0);\n",\
+"(1, 0);\n",\
+"(-0.5, 0.866);\n",\
+"(1.5, 0.866);\n",\
+"\n",\
+"maplines\n",\
+"(1, 2) del;\n",\
+"(3, 1) del;\n",\
+"(2, 4) del;\n",\
+"\n",\
+"newpoints\n",\
+"(0.5, 0.866) { 0.5 X3, 0.5 X4 } { 0.5 Y3, 0.5 Y4 };\n",\
+"\n",\
+"newlines\n",\
+"(3, 5);\n",\
+"(5, 4);\n",\
+"\n",\
+"freearea\n",\
+"(0, 0);\n",\
+"(1, 0) { 1 X2 } { };\n",\
+"(1.5, 0.866) { 1 X4 } { 1 Y4 };\n",\
+"(1, 1.299) { -0.5 X2, 0.375 X3, 1.125 X4 } { -0.5 Y2, 0.375 Y3, 1.125 Y4 };\n",\
+"(0, 1.299) { 1.125 X3, 0.375 X4 } { 1.125 Y3, 0.375 Y4 };\n",\
+"(-0.5, 0.866) { 1 X3 } { 1 Y3 };\n",\
+"\n",\
+"elements\n",\
+"(1, 2, 5);\n",\
+"(3, 1, 5);\n",\
+"(2, 4, 5);\n",\
+"\n",\
+"endrule\n",\
+"\n",\
+"\n",\
+"rule \"Fill Triangle\"\n",\
+"\n",\
+"quality 1\n",\
+"\n",\
+"mappoints\n",\
+"(0, 0);\n",\
+"(1, 0);\n",\
+"(0.5, 0.866);\n",\
+"\n",\
+"maplines\n",\
+"(1, 2) del;\n",\
+"(2, 3) del;\n",\
+"(3, 1) del;\n",\
+"\n",\
+"newpoints\n",\
+"\n",\
+"newlines\n",\
+"\n",\
+"freearea\n",\
+"(0, 0);\n",\
+"(1, 0) { 1 X2 } { 1 Y2 };\n",\
+"(0.5, 0.866) { 1 X3 } { 1 Y3 };\n",\
+"\n",\
+"elements\n",\
+"(1, 2, 3);\n",\
+"\n",\
+"endrule\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"rule \"Vis A Vis (1)\"\n",\
+"\n",\
+"quality 1\n",\
+"\n",\
+"mappoints\n",\
+"(0, 0);\n",\
+"(1, 0);\n",\
+"(0.5, 0.866);\n",\
+"\n",\
+"maplines\n",\
+"(1, 2) del;\n",\
+"\n",\
+"newpoints\n",\
+"\n",\
+"newlines\n",\
+"(1, 3);\n",\
+"(3, 2);\n",\
+"\n",\
+"freearea\n",\
+"(0, 0);\n",\
+"(1, 0) { 1 X2 } { };\n",\
+"(1.2, 0.693) { 0.8 X2, 0.8 X3 } { 0.8 Y2, 0.8 Y3 };\n",\
+"(0.5, 0.866) { 1 X3 } { 1 Y3 };\n",\
+"(-0.2, 0.693) { -0.6 X2, 0.8 X3 } { -0.6 Y2, 0.8 Y3 };\n",\
+"\n",\
+"freearea2\n",\
+"(0, 0);\n",\
+"(1, 0) { 1 X2 } { };\n",\
+"(0.75, 0.433) { 0.5 X2, 0.5 X3 } { 0.5 Y2, 0.5 Y3 };\n",\
+"(0.5, 0.866) { 1 X3 } { 1 Y3 };\n",\
+"(0.25, 0.433) { 0.5 X3 } { 0.5 Y3 };\n",\
+"\n",\
+"elements\n",\
+"(1, 2, 3);\n",\
+"\n",\
+"endrule\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"rule \"2 h Vis A Vis (1)\"\n",\
+"\n",\
+"quality 3\n",\
+"\n",\
+"mappoints\n",\
+"(0, 0);\n",\
+"(1, 0);\n",\
+"(1, 1.732);\n",\
+"(0, 1.732);\n",\
+"\n",\
+"maplines\n",\
+"(1, 2) del;\n",\
+"(3, 4) del;\n",\
+"\n",\
+"newpoints\n",\
+"(0.5, 0.866) { 0.25 X2, 0.25 X3, 0.25 X4 } { 0.25 Y2, 0.25 Y3, 0.25 Y4 };\n",\
+"\n",\
+"newlines\n",\
+"(1, 5);\n",\
+"(5, 4);\n",\
+"(3, 5);\n",\
+"(5, 2);\n",\
+"\n",\
+"freearea\n",\
+"(0, 0);\n",\
+"(1, 0) { 1 X2 } { 1 Y2 };\n",\
+"(1.5, 0.866) { 0.75 X2, 0.75 X3, -0.25 X4 } { 0.75 Y2, 0.75 Y3, -0.25 Y4 };\n",\
+"(1, 1.732) { 1 X3 } { 1 Y3 };\n",\
+"(0, 1.732) { 1 X4 } { 1 Y4 };\n",\
+"(-0.5, 0.866) { 0.75 X4, -0.25 X2, -0.25 X3 } { 0.75 Y4, -0.25 Y3 };\n",\
+"\n",\
+"elements\n",\
+"(1, 2, 5);\n",\
+"(3, 4, 5);\n",\
+"\n",\
+"endrule\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+"\n",\
+0};
+}
diff --git a/contrib/Netgen/libsrc/meshing/validate.cpp b/contrib/Netgen/libsrc/meshing/validate.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..d519e27c25d58a8779a7e9a00b2784b5624f30f6
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/validate.cpp
@@ -0,0 +1,587 @@
+
+#include <mystdlib.h>
+#include "meshing.hpp"
+
+
+namespace netgen
+{
+  void GetPureBadness(Mesh & mesh, ARRAY<double> & pure_badness,
+		      const BitArray & isnewpoint)
+  {
+    //const int ne = mesh.GetNE();
+    const int np = mesh.GetNP();
+
+    pure_badness.SetSize(np+PointIndex::BASE+1);
+    pure_badness = -1;
+
+    ARRAY< Point<3>* > backup(np);
+
+    for(int i=0; i<np; i++)
+      {
+	backup[i] = new Point<3>(mesh.Point(i+1));
+
+	if(isnewpoint.Test(i+PointIndex::BASE) &&
+	   mesh.mlbetweennodes[i+PointIndex::BASE][0] > 0)
+	  {
+	    mesh.Point(i+1) = Center(mesh.Point(mesh.mlbetweennodes[i+PointIndex::BASE][0]),
+				     mesh.Point(mesh.mlbetweennodes[i+PointIndex::BASE][1]));
+	  }
+      }
+    for (ElementIndex i = 0; i < mesh.GetNE(); i++)
+      {
+	double bad = mesh[i].CalcJacobianBadness (mesh.Points());
+	for(int j=0; j<mesh[i].GetNP(); j++)
+	  if(bad > pure_badness[mesh[i][j]])
+	    pure_badness[mesh[i][j]] = bad;
+
+	// save maximum
+	if(bad > pure_badness.Last())
+	  pure_badness.Last() = bad; 
+      }
+    
+    for(int i=0; i<np; i++)
+      {
+	mesh.Point(i+1) = *backup[i];
+	delete backup[i];
+      }
+  }
+
+
+  double Validate(const Mesh & mesh, ARRAY<ElementIndex> & bad_elements,
+		  const ARRAY<double> & pure_badness,
+		  double max_worsening, const bool uselocalworsening,
+		  ARRAY<double> * quality_loss)
+  {
+    PrintMessage(3,"!!!! Validating !!!!");
+    //if(max_worsening > 0)
+    //  (*testout) << "badness " << counter++ << endl;
+
+    bad_elements.SetSize(0);
+
+    double loc_pure_badness = -1;
+
+    if(!uselocalworsening)
+      loc_pure_badness = pure_badness.Last(); // maximum is saved at last position
+
+
+    double worsening = -1;
+    ElementIndex ind;
+
+    if(quality_loss != NULL)
+      quality_loss->SetSize(mesh.GetNE());
+
+    for (ElementIndex i = 0; i < mesh.GetNE(); i++)
+      {
+	if(uselocalworsening)
+	  {
+	    loc_pure_badness = -1;
+	    for(int j=0; j<mesh[i].GetNP(); j++)
+	      if(pure_badness[mesh[i][j]] > loc_pure_badness)
+		loc_pure_badness = pure_badness[mesh[i][j]];
+	  }
+
+
+	double bad = mesh[i].CalcJacobianBadness (mesh.Points());
+	if (bad > 1e10 || 
+	    (max_worsening > 0 && bad > loc_pure_badness*max_worsening))
+	  bad_elements.Append(i);
+	  
+
+	if(max_worsening > 0)
+	  {
+	    double actw = bad/loc_pure_badness;
+	    if(quality_loss != NULL)
+	      (*quality_loss)[i] = actw;
+
+	    if(actw > worsening)
+	      {
+		worsening = actw;
+		ind = i;
+	      }
+	  }
+      }
+    return worsening;
+  }
+
+
+  void GetWorkingArea(BitArray & working_elements, BitArray & working_points,
+		      const Mesh & mesh, const ARRAY<ElementIndex> & bad_elements,
+		      const int width)
+  {
+    working_elements.Clear();
+    working_points.Clear();
+
+    for(int i=0; i<bad_elements.Size(); i++)
+      {
+	working_elements.Set(bad_elements[i]);
+	const Element & el = mesh[bad_elements[i]];
+	for(int j=1; j<=el.GetNP(); j++)
+	  working_points.Set(el.PNum(j));
+      }
+    
+
+    for(int i=0; i<width; i++)
+      {
+	for(ElementIndex j=0; j<mesh.GetNE(); j++)
+	  {
+	    if(!working_elements.Test(j))
+	      {  
+		const Element & el = mesh[j];
+		bool set_active = false;
+		
+		for(int k=1; !set_active && k<=el.GetNP(); k++)
+		  set_active = working_points.Test(el.PNum(k));
+		
+		if(set_active)
+		  working_elements.Set(j);
+	      }
+	  }
+
+	for(ElementIndex j=0; j<mesh.GetNE(); j++)
+	  {
+	    if(working_elements.Test(j))
+	      {
+		const Element & el = mesh[j];
+		for(int k=1; k<=el.GetNP(); k++)
+		  working_points.Set(el.PNum(k));
+	      }
+	  }
+      }
+  }
+
+
+
+  void RepairBisection(Mesh & mesh, ARRAY<ElementIndex> & bad_elements, 
+		       const BitArray & isnewpoint, Refinement & refinement,
+		       const ARRAY<double> & pure_badness, 
+		       double max_worsening, const bool uselocalworsening,
+		       const ARRAY< ARRAY<int,PointIndex::BASE>* > & idmaps)
+  {
+    ostringstream ostrstr;
+
+    const int maxtrials = 100;
+
+    //bool doit;
+    //cout << "DOIT: " << flush;
+    //cin >> doit;
+
+    int ne = mesh.GetNE();
+    int np = mesh.GetNP();
+
+    int numbadneighbours = 3;
+    const int numtopimprove = 3;
+
+    PrintMessage(1,"repairing");
+
+    PushStatus("Repair Bisection");
+
+    ARRAY<Point<3>* > should(np);
+    ARRAY<Point<3>* > can(np);
+    ARRAY<Vec<3>* > nv(np);
+    for(int i=0; i<np; i++)
+      {
+	nv[i] = new Vec<3>;
+	should[i] = new Point<3>;
+	can[i] = new Point<3>;
+      }
+    
+    BitArray isboundarypoint(np),isedgepoint(np);
+    isboundarypoint.Clear();
+    isedgepoint.Clear();
+
+    for(int i = 1; i <= mesh.GetNSeg(); i++)
+      {
+	const Segment & seg = mesh.LineSegment(i);
+	isedgepoint.Set(seg.p1);
+	isedgepoint.Set(seg.p2);
+      }
+
+    ARRAY<int> surfaceindex(np);
+    surfaceindex = -1;
+    
+    for (int i = 1; i <= mesh.GetNSE(); i++)
+      {
+	const Element2d & sel = mesh.SurfaceElement(i);
+	for (int j = 1; j <= sel.GetNP(); j++)
+	  if(!isedgepoint.Test(sel.PNum(j)))
+	    {
+	      isboundarypoint.Set(sel.PNum(j));
+	      surfaceindex[sel.PNum(j) - PointIndex::BASE] = 
+		mesh.GetFaceDescriptor(sel.GetIndex()).SurfNr();
+	    }
+      }
+
+
+
+    Validate(mesh,bad_elements,pure_badness,
+	     ((uselocalworsening) ?  (0.8*(max_worsening-1.) + 1.) : (0.1*(max_worsening-1.) + 1.)),
+	     uselocalworsening); // -> larger working area
+    BitArray working_elements(ne);
+    BitArray working_points(np);
+
+    GetWorkingArea(working_elements,working_points,mesh,bad_elements,numbadneighbours);
+    //working_elements.Set();
+    //working_points.Set();
+
+    ostrstr.str("");
+    ostrstr << "worsening: " <<
+      Validate(mesh,bad_elements,pure_badness,max_worsening,uselocalworsening);
+    PrintMessage(4,ostrstr.str());
+
+    
+
+    int auxnum=0;
+    for(int i=1; i<=np; i++)
+      if(working_points.Test(i))
+	auxnum++;
+    
+    ostrstr.str("");
+    ostrstr << "Percentage working points: " << 100.*double(auxnum)/np;
+    PrintMessage(5,ostrstr.str());
+    
+
+    BitArray isworkingboundary(np);
+    for(int i=1; i<=np; i++)
+      if(working_points.Test(i) && isboundarypoint.Test(i))
+	isworkingboundary.Set(i);
+      else
+	isworkingboundary.Clear(i);
+
+
+    for(int i=0; i<np; i++)
+      *should[i] = mesh.Point(i+1);
+
+    
+    for(int i=0; i<np; i++)
+      {
+	if(isnewpoint.Test(i+PointIndex::BASE) && 
+	   //working_points.Test(i+PointIndex::BASE) && 
+	   mesh.mlbetweennodes[i+PointIndex::BASE][0] > 0)
+	  *can[i] = Center(*can[mesh.mlbetweennodes[i+PointIndex::BASE][0]-PointIndex::BASE],
+			   *can[mesh.mlbetweennodes[i+PointIndex::BASE][1]-PointIndex::BASE]);
+	else
+	  *can[i] = mesh.Point(i+1);
+      }
+
+
+    int cnttrials = 1;
+    
+    double lamedge = 0.5;
+    double lamface = 0.5;
+    
+    double facokedge = 0;
+    double facokface = 0;
+    double factryedge;
+    double factryface = 0;
+
+    double oldlamedge,oldlamface;
+
+    MeshOptimize2d * optimizer2d = refinement.Get2dOptimizer();
+    if(!optimizer2d)
+      {
+	cerr << "No 2D Optimizer!" << endl;
+	return;
+      }    
+
+    while ((facokedge < 1.-1e-8 || facokface < 1.-1e-8) && 
+	   cnttrials < maxtrials &&
+	   multithread.terminate != 1)
+      {
+	(*testout) << "   facokedge " << facokedge << " facokface " << facokface << " cnttrials " << cnttrials << endl
+		   << " perc. " << 95. * max2( min2(facokedge,facokface),
+					       double(cnttrials)/double(maxtrials)) << endl;
+
+	SetThreadPercent(95. * max2( min2(facokedge,facokface),
+				     double(cnttrials)/double(maxtrials)));
+
+	ostrstr.str("");
+	ostrstr << "max. worsening " << max_worsening;
+	PrintMessage(5,ostrstr.str());
+	oldlamedge = lamedge;
+	lamedge *= 6;
+	if (lamedge > 2)
+	  lamedge = 2;
+	   
+	if(1==1 || facokedge < 1.-1e-8)
+	  {
+	    for(int i=0; i<nv.Size(); i++)
+	      *nv[i] = Vec<3>(0,0,0);
+	    for (int i = 1; i <= mesh.GetNSE(); i++)
+	      {
+		const Element2d & sel = mesh.SurfaceElement(i);
+		Vec<3> auxvec = Cross(mesh.Point(sel.PNum(2))-mesh.Point(sel.PNum(1)),
+                                      mesh.Point(sel.PNum(3))-mesh.Point(sel.PNum(1)));
+		auxvec.Normalize();
+		for (int j = 1; j <= sel.GetNP(); j++)
+		  if(!isedgepoint.Test(sel.PNum(j)))
+		    *nv[sel.PNum(j) - PointIndex::BASE] += auxvec;
+	      }
+	    for(int i=0; i<nv.Size(); i++)
+	      nv[i]->Normalize();
+	    
+	    
+	    do  // move edges
+	      {
+		lamedge *= 0.5;
+		cnttrials++;
+		if(cnttrials % 10 == 0)
+		  max_worsening *= 1.1;
+		
+		
+		factryedge = lamedge + (1.-lamedge) * facokedge;
+
+		ostrstr.str("");
+		ostrstr << "lamedge = " << lamedge << ", trying: " << factryedge;
+		PrintMessage(5,ostrstr.str());
+		
+
+		for (int i = 1; i <= np; i++)
+		  {
+		    if (isedgepoint.Test(i))
+		      {
+			for (int j = 0; j < 3; j++)
+			  mesh.Point(i)(j) = 
+			    lamedge * (*should.Get(i))(j) +
+			    (1.-lamedge) * (*can.Get(i))(j);
+		      }
+		    else
+		      mesh.Point(i) = *can.Get(i);
+		  }
+		if(facokedge < 1.-1e-8)
+		  {
+		    ostrstr.str("");
+		    ostrstr << "worsening: " <<
+		      Validate(mesh,bad_elements,pure_badness,max_worsening,uselocalworsening);
+
+		    PrintMessage(5,ostrstr.str());
+		  }
+		else
+		  Validate(mesh,bad_elements,pure_badness,-1,uselocalworsening);
+
+
+		ostrstr.str("");
+		ostrstr << bad_elements.Size() << " bad elements";
+		PrintMessage(5,ostrstr.str());
+	      }
+	    while (bad_elements.Size() > 0 && 
+		   cnttrials < maxtrials &&
+		   multithread.terminate != 1);
+	  }
+
+	if(cnttrials < maxtrials &&
+	   multithread.terminate != 1)
+	  {
+	    facokedge = factryedge;
+	    
+	    // smooth faces
+	    mesh.CalcSurfacesOfNode();
+	    
+	    mesh.ImproveMeshJacobianOnSurface(isworkingboundary,nv,OPT_QUALITY,&idmaps);
+	    
+	    for (int i = 1; i <= np; i++)
+	      *can.Elem(i) = mesh.Point(i);
+	    
+	    if(optimizer2d)
+	      optimizer2d->ProjectBoundaryPoints(surfaceindex,can,should);
+	  }
+
+
+	oldlamface = lamface;
+	lamface *= 6;
+	if (lamface > 2)
+	  lamface = 2;
+
+
+	if(cnttrials < maxtrials &&
+	   multithread.terminate != 1)
+	  {
+
+	    do  // move faces
+	      {
+		lamface *= 0.5;
+		cnttrials++;
+		if(cnttrials % 10 == 0)
+		  max_worsening *= 1.1;
+		factryface = lamface + (1.-lamface) * facokface;
+
+		ostrstr.str("");
+		ostrstr << "lamface = " << lamface << ", trying: " << factryface;
+		PrintMessage(5,ostrstr.str());
+		
+		
+		for (int i = 1; i <= np; i++)
+		  {
+		    if (isboundarypoint.Test(i))
+		      {
+			for (int j = 0; j < 3; j++)
+			  mesh.Point(i)(j) = 
+			    lamface * (*should.Get(i))(j) +
+			    (1.-lamface) * (*can.Get(i))(j);
+		      }
+		    else
+		      mesh.Point(i) = *can.Get(i);
+		  }
+
+		ostrstr.str("");
+		ostrstr << "worsening: " <<
+		  Validate(mesh,bad_elements,pure_badness,max_worsening,uselocalworsening);
+		PrintMessage(5,ostrstr.str());
+	
+
+		ostrstr.str("");
+		ostrstr << bad_elements.Size() << " bad elements";
+		PrintMessage(5,ostrstr.str());
+	      }
+	    while (bad_elements.Size() > 0 && 
+		   cnttrials < maxtrials &&
+		   multithread.terminate != 1);
+	  }
+
+
+
+	if(cnttrials < maxtrials &&
+	   multithread.terminate != 1)
+	  {
+	    facokface = factryface;
+	    // smooth interior
+	    
+	    mesh.CalcSurfacesOfNode();
+	    
+	    mesh.ImproveMeshJacobian (OPT_QUALITY,&working_points);
+	    //mesh.ImproveMeshJacobian (OPT_WORSTCASE,&working_points);
+	  
+
+	    for (int i = 1; i <= np; i++)
+	      *can.Elem(i) = mesh.Point(i);
+	  }
+	  
+	//!
+	if((facokedge < 1.-1e-8 || facokface < 1.-1e-8) && 
+	   cnttrials < maxtrials &&
+	   multithread.terminate != 1)
+	  {
+	    MeshOptimize3d optmesh;
+	    for(int i=0; i<numtopimprove; i++)
+	      {
+		optmesh.SwapImproveSurface(mesh,OPT_QUALITY,&working_elements,&idmaps);
+		optmesh.SwapImprove(mesh,OPT_QUALITY,&working_elements);
+		
+	      }	    
+
+	    //	    mesh.mglevels = 1;
+	    
+		
+	    ne = mesh.GetNE();
+	    working_elements.SetSize(ne);
+	    
+	    
+	    for (int i = 1; i <= np; i++)
+	      mesh.Point(i) = *should.Elem(i);
+	    
+	    Validate(mesh,bad_elements,pure_badness,
+		     ((uselocalworsening) ?  (0.8*(max_worsening-1.) + 1.) : (0.1*(max_worsening-1.) + 1.)),
+		     uselocalworsening);
+	    
+	    if(lamedge < oldlamedge || lamface < oldlamface)
+	      numbadneighbours++;
+	    GetWorkingArea(working_elements,working_points,mesh,bad_elements,numbadneighbours);
+	    for(int i=1; i<=np; i++)
+	      if(working_points.Test(i) && isboundarypoint.Test(i))
+		isworkingboundary.Set(i);
+	      else
+		isworkingboundary.Clear(i);
+	    auxnum=0;
+	    for(int i=1; i<=np; i++)
+	      if(working_points.Test(i))
+		auxnum++;
+
+	    
+	    ostrstr.str("");
+	    ostrstr << "Percentage working points: " << 100.*double(auxnum)/np;
+	    PrintMessage(5,ostrstr.str());
+	    
+	    for (int i = 1; i <= np; i++)
+	      mesh.Point(i) = *can.Elem(i);
+	  }
+	//!
+
+      }
+
+    MeshOptimize3d optmesh;
+    for(int i=0; i<numtopimprove && multithread.terminate != 1; i++)
+      {
+	optmesh.SwapImproveSurface(mesh,OPT_QUALITY,NULL,&idmaps);
+	optmesh.SwapImprove(mesh,OPT_QUALITY);
+	//mesh.UpdateTopology();
+      }
+    mesh.UpdateTopology();
+    /*
+    if(cnttrials < 100)
+      {
+	nv = Vec3d(0,0,0);
+	for (int i = 1; i <= mesh.GetNSE(); i++)
+	  {
+	    const Element2d & sel = mesh.SurfaceElement(i);
+	    Vec3d auxvec = Cross(mesh.Point(sel.PNum(2))-mesh.Point(sel.PNum(1)),
+				 mesh.Point(sel.PNum(3))-mesh.Point(sel.PNum(1)));
+	    auxvec.Normalize();
+	    for (int j = 1; j <= sel.GetNP(); j++)
+	      if(!isedgepoint.Test(sel.PNum(j)))
+		nv[sel.PNum(j) - PointIndex::BASE] += auxvec;
+	  }
+	for(int i=0; i<nv.Size(); i++)
+	  nv[i].Normalize();
+	
+
+	mesh.ImproveMeshJacobianOnSurface(isboundarypoint,nv,OPT_QUALITY);
+	mesh.CalcSurfacesOfNode();
+	    // smooth interior
+	    
+	
+	for (int i = 1; i <= np; i++)
+	  if(isboundarypoint.Test(i))
+	    can.Elem(i) = mesh.Point(i);
+	    
+	if(optimizer2d)
+	  optimizer2d->ProjectBoundaryPoints(surfaceindex,can,should);
+
+	
+	for (int i = 1; i <= np; i++)
+	  if(isboundarypoint.Test(i))
+	    for(int j=1; j<=3; j++)
+	      mesh.Point(i).X(j) = should.Get(i).X(j);
+      }
+    */
+
+
+    if(cnttrials == maxtrials)
+      {
+	for (int i = 1; i <= np; i++)
+	  mesh.Point(i) = *should.Get(i);
+
+	Validate(mesh,bad_elements,pure_badness,max_worsening,uselocalworsening);
+	
+	for(int i=0; i<bad_elements.Size(); i++)
+	  {
+	    ostrstr.str("");
+	    ostrstr << "bad element:" << endl
+		    << mesh[bad_elements[i]][0] << ": " << mesh.Point(mesh[bad_elements[i]][0]) << endl
+		    << mesh[bad_elements[i]][1] << ": " << mesh.Point(mesh[bad_elements[i]][1]) << endl
+		    << mesh[bad_elements[i]][2] << ": " << mesh.Point(mesh[bad_elements[i]][2]) << endl
+		    << mesh[bad_elements[i]][3] << ": " << mesh.Point(mesh[bad_elements[i]][3]);
+	    PrintMessage(5,ostrstr.str());
+	  }
+	for (int i = 1; i <= np; i++)
+	  mesh.Point(i) = *can.Get(i);
+      }
+
+    for(int i=0; i<np; i++)
+      {
+	delete nv[i];
+	delete can[i];
+	delete should[i];
+      }
+
+    PopStatus();
+  }
+}
diff --git a/contrib/Netgen/libsrc/meshing/validate.hpp b/contrib/Netgen/libsrc/meshing/validate.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..5f898c179db6cb9105660b4cf637c8982eec9320
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/validate.hpp
@@ -0,0 +1,17 @@
+#ifndef VALIDATE_HPP
+#define VALIDATE_HPP
+
+
+
+void GetPureBadness(Mesh & mesh, ARRAY<double> & pure_badness,
+		    const BitArray & isnewpoint);
+double Validate(const Mesh & mesh, ARRAY<ElementIndex> & bad_elements,
+		const ARRAY<double> & pure_badness, 
+		double max_worsening, const bool uselocalworsening,
+		ARRAY<double> * quality_loss = NULL);
+void RepairBisection(Mesh & mesh, ARRAY<ElementIndex> & bad_elements, const BitArray & isnewpoint, Refinement & refinement,
+		     const ARRAY<double> & pure_badness, 
+		     double max_worsening, const bool uselocalworsening,
+		     const ARRAY< ARRAY<int,PointIndex::BASE>* > & idmaps);
+
+#endif // VALIDATE_HPP
diff --git a/contrib/Netgen/libsrc/meshing/zrefine.cpp b/contrib/Netgen/libsrc/meshing/zrefine.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..13e02bbaf955b4ce5a1b084a10f01d261c6435be
--- /dev/null
+++ b/contrib/Netgen/libsrc/meshing/zrefine.cpp
@@ -0,0 +1,742 @@
+#include <mystdlib.h>
+#include "meshing.hpp"
+
+#include <csg.hpp>
+
+
+namespace netgen
+{
+
+  // find singular edges
+  void SelectSingularEdges (const Mesh & mesh, const CSGeometry & geom, 
+			    INDEX_2_HASHTABLE<int> & singedges,
+			    ZRefinementOptions & opt)
+  {
+    int i, j;
+
+    // edges selected in csg input file
+    for (i = 1; i <= geom.singedges.Size(); i++)
+      {
+	//if(geom.singedges.Get(i)->maxhinit > 0)
+	//  continue; //!!!!
+
+	const SingularEdge & se = *geom.singedges.Get(i);
+	for (j = 1; j <= se.segms.Size(); j++)
+	  {
+	    INDEX_2 i2 = se.segms.Get(j);
+	    singedges.Set (i2, 1);
+	  }
+      }
+
+    // edges interactively selected
+    for (i = 1; i <= mesh.GetNSeg(); i++)
+      {
+	const Segment & seg = mesh.LineSegment(i);
+	if (seg.singedge_left || seg.singedge_right)
+	  {
+	    INDEX_2 i2(seg.p1, seg.p2);
+	    i2.Sort();
+	    singedges.Set (i2, 1);
+	  }
+      }
+  }
+
+
+  /**
+     Convert elements (vol-tets, surf-trigs) into prisms/quads
+  */
+  void MakePrismsSingEdge (Mesh & mesh, INDEX_2_HASHTABLE<int> & singedges)
+  {
+    int i, j, k;
+
+    // volume elements
+    for (i = 1; i <= mesh.GetNE(); i++)
+      {
+	Element & el = mesh.VolumeElement(i);
+	if (el.GetType() != TET) continue;
+
+	for (j = 1; j <= 3; j++)
+	  for (k = j+1; k <= 4; k++)
+	    {
+	      INDEX_2 edge(el.PNum(j), el.PNum(k));
+	      edge.Sort();
+	      if (singedges.Used (edge))
+		{
+		  int pi3 = 1, pi4 = 1;
+		  while (pi3 == j || pi3 == k) pi3++;
+		  pi4 = 10 - j - k - pi3;
+		
+		  int p3 = el.PNum(pi3);
+		  int p4 = el.PNum(pi4);
+
+		  el.SetType(PRISM);
+		  el.PNum(1) = edge.I1();
+		  el.PNum(2) = p3;
+		  el.PNum(3) = p4;
+		  el.PNum(4) = edge.I2();
+		  el.PNum(5) = p3;
+		  el.PNum(6) = p4;
+		}
+	    }
+      }
+
+    // surface elements
+    for (i = 1; i <= mesh.GetNSE(); i++)
+      {
+	Element2d & el = mesh.SurfaceElement(i);
+	if (el.GetType() != TRIG) continue;
+
+	for (j = 1; j <= 3; j++)
+	  {
+	    k = (j % 3) + 1;
+	    INDEX_2 edge(el.PNum(j), el.PNum(k));
+	    edge.Sort();
+
+	    if (singedges.Used (edge))
+	      {
+		int pi3 = 6-j-k;
+		int p3 = el.PNum(pi3);
+		int p1 = el.PNum(j);
+		int p2 = el.PNum(k);
+
+		el.SetType(QUAD);
+		el.PNum(1) = p2;
+		el.PNum(2) = p3;
+		el.PNum(3) = p3;
+		el.PNum(4) = p1;
+	      }
+	  }
+      }
+  }
+
+
+  /*
+    Convert tets and pyramids next to close (identified) points into prisms
+  */
+  void MakePrismsClosePoints (Mesh & mesh)
+  {
+    int i, j, k;
+    for (i = 1; i <= mesh.GetNE(); i++)
+      {
+	Element & el = mesh.VolumeElement(i);
+	if (el.GetType() == TET)
+	  {
+	    for (j = 1; j <= 3; j++)
+	      for (k = j+1; k <= 4; k++)
+		{
+		  INDEX_2 edge(el.PNum(j), el.PNum(k));
+		  edge.Sort();
+		  if (mesh.GetIdentifications().GetSymmetric (el.PNum(j), el.PNum(k)))
+		    {
+		      int pi3 = 1, pi4 = 1;
+		      while (pi3 == j || pi3 == k) pi3++;
+		      pi4 = 10 - j - k - pi3;
+		    
+		      int p3 = el.PNum(pi3);
+		      int p4 = el.PNum(pi4);
+		    
+		      el.SetType(PRISM);
+		      el.PNum(1) = edge.I1();
+		      el.PNum(2) = p3;
+		      el.PNum(3) = p4;
+		      el.PNum(4) = edge.I2();
+		      el.PNum(5) = p3;
+		      el.PNum(6) = p4;
+		    }
+		}
+	  }
+
+	if (el.GetType() == PYRAMID)
+	  {
+	    // pyramid, base face = 1,2,3,4
+	  
+	    for (j = 0; j <= 1; j++)
+	      {
+		int pi1 = el.PNum( (j+0) % 4 + 1);
+		int pi2 = el.PNum( (j+1) % 4 + 1);
+		int pi3 = el.PNum( (j+2) % 4 + 1);
+		int pi4 = el.PNum( (j+3) % 4 + 1);
+		int pi5 = el.PNum(5);
+
+		INDEX_2 edge1(pi1, pi4);
+		INDEX_2 edge2(pi2, pi3);
+		edge1.Sort();
+		edge2.Sort();
+		if (mesh.GetIdentifications().GetSymmetric (pi1, pi4) &&
+		    mesh.GetIdentifications().GetSymmetric (pi2, pi3))
+		  {
+		    //int p3 = el.PNum(pi3);
+		    //int p4 = el.PNum(pi4);
+		  
+		    el.SetType(PRISM);
+		    el.PNum(1) = pi1;
+		    el.PNum(2) = pi2;
+		    el.PNum(3) = pi5;
+		    el.PNum(4) = pi4;
+		    el.PNum(5) = pi3;
+		    el.PNum(6) = pi5;
+		  }
+	      }
+	  }
+      }
+  
+    for (i = 1; i <= mesh.GetNSE(); i++)
+      {
+	Element2d & el = mesh.SurfaceElement(i);
+	if (el.GetType() != TRIG) continue;
+
+	for (j = 1; j <= 3; j++)
+	  {
+	    k = (j % 3) + 1;
+	    INDEX_2 edge(el.PNum(j), el.PNum(k));
+	    edge.Sort();
+
+	    if (mesh.GetIdentifications().GetSymmetric (el.PNum(j), el.PNum(k)))
+	      {
+		int pi3 = 6-j-k;
+		int p3 = el.PNum(pi3);
+		int p1 = el.PNum(j);
+		int p2 = el.PNum(k);
+
+		el.SetType(QUAD);
+		el.PNum(1) = p2;
+		el.PNum(2) = p3;
+		el.PNum(3) = p3;
+		el.PNum(4) = p1;
+	      }
+	  }
+      }
+  }
+
+
+
+#ifdef OLD
+  void MakeCornerNodes (Mesh & mesh,
+			INDEX_HASHTABLE<int> & cornernodes)
+  {
+    int i, j;
+    int nseg = mesh.GetNSeg();
+    ARRAY<int> edgesonpoint(mesh.GetNP());
+    for (i = 1; i <= mesh.GetNP(); i++)
+      edgesonpoint.Elem(i) = 0;
+
+    for (i = 1; i <= nseg; i++)
+      {
+	for (j = 1; j <= 2; j++)
+	  {
+	    int pi = (j == 1) ? 
+	      mesh.LineSegment(i).p1 :
+	      mesh.LineSegment(i).p2;
+	    edgesonpoint.Elem(pi)++;
+	  }
+      }
+
+    /*
+      cout << "cornernodes: ";
+      for (i = 1; i <= edgesonpoint.Size(); i++)
+      if (edgesonpoint.Get(i) >= 6)
+      {
+      cornernodes.Set (i, 1);
+      cout << i << " ";
+      }
+      cout << endl;
+    */
+    //  cornernodes.Set (5, 1);
+  }
+#endif
+
+
+  void RefinePrisms (Mesh & mesh, const CSGeometry * geom, 
+		     ZRefinementOptions & opt)
+  {
+    int i, j;
+    bool found, change;
+    int cnt = 0;
+
+
+    // markers for z-refinement:  p1, p2, levels  
+    // p1-p2 is an edge to be refined
+    ARRAY<INDEX_3> ref_uniform;
+    ARRAY<INDEX_3> ref_singular;
+    ARRAY<INDEX_4 > ref_slices;
+
+    BitArray first_id(geom->identifications.Size());
+    first_id.Set();
+
+  
+    INDEX_2_HASHTABLE<int> & identpts = 
+      mesh.GetIdentifications().GetIdentifiedPoints ();
+
+    if (&identpts)
+      {
+	for (i = 1; i <= identpts.GetNBags(); i++)
+	  for (j = 1; j <= identpts.GetBagSize(i); j++)
+	    {
+	      INDEX_2 pair;
+	      int idnr;
+	      identpts.GetData(i, j, pair, idnr);
+	      const CloseSurfaceIdentification * csid = 
+		dynamic_cast<const CloseSurfaceIdentification*> 
+		(geom->identifications.Get(idnr));
+	      if (csid)
+		{
+		  if (!csid->GetSlices().Size())
+		    {
+		      if (first_id.Test (idnr))
+			{
+			  first_id.Clear(idnr);
+			  ref_uniform.Append (INDEX_3 (pair.I1(), pair.I2(), csid->RefLevels()));
+			  ref_singular.Append (INDEX_3 (pair.I1(), pair.I2(), csid->RefLevels1()));
+			  ref_singular.Append (INDEX_3 (pair.I2(), pair.I1(), csid->RefLevels2()));
+			}
+		    }
+		  else
+		    {   
+		      //const ARRAY<double> & slices = csid->GetSlices();
+		      INDEX_4 i4;
+		      i4[0] = pair.I1();
+		      i4[1] = pair.I2();
+		      i4[2] = idnr;
+		      i4[3] = csid->GetSlices().Size();
+		      ref_slices.Append (i4);
+		    }
+		}
+	    }
+      }
+
+  
+  
+    ARRAY<EdgePointGeomInfo> epgi;
+
+    while (1)
+      {
+	cnt++;
+	PrintMessage (3, "Z-Refinement, level = ", cnt);
+	INDEX_2_HASHTABLE<int> refedges(mesh.GetNSE()+1);
+
+
+	found = 0;
+	// mark prisms due to close surface flags:
+	int oldsize = ref_uniform.Size();
+	for (i = 1; i <= oldsize; i++)
+	  {
+	    int pi1 = ref_uniform.Get(i).I1();
+	    int pi2 = ref_uniform.Get(i).I2();
+	    int levels = ref_uniform.Get(i).I3();
+
+	    if (levels > 0)
+	      {
+		const Point3d & p1 = mesh.Point(pi1);
+		const Point3d & p2 = mesh.Point(pi2);
+		int npi(0);
+	      
+		INDEX_2 edge(pi1, pi2);
+		edge.Sort();
+		if (!refedges.Used(edge))
+		  {
+		    Point3d np = Center (p1, p2);
+		    npi = mesh.AddPoint (np);
+		    refedges.Set (edge, npi);
+		    found = 1;
+		  }
+
+		ref_uniform.Elem(i) = INDEX_3(pi1, npi, levels-1);
+		ref_uniform.Append (INDEX_3(pi2, npi, levels-1));
+	      }
+	  }
+	for (i = 1; i <= ref_singular.Size(); i++)
+	  {
+	    int pi1 = ref_singular.Get(i).I1();
+	    int pi2 = ref_singular.Get(i).I2();
+	    int levels = ref_singular.Get(i).I3();
+
+	    if (levels > 0)
+	      {
+		const Point3d & p1 = mesh.Point(pi1);
+		const Point3d & p2 = mesh.Point(pi2);
+		int npi;
+	      
+		INDEX_2 edge(pi1, pi2);
+		edge.Sort();
+		if (!refedges.Used(edge))
+		  {
+		    Point3d np = Center (p1, p2);
+		    npi = mesh.AddPoint (np);
+		    refedges.Set (edge, npi);
+		    found = 1;
+		  }
+		else
+		  npi = refedges.Get (edge);
+
+		ref_singular.Elem(i) = INDEX_3(pi1, npi, levels-1);
+	      }
+	  }
+
+	for (i = 1; i <= ref_slices.Size(); i++)
+	  {
+	    int pi1 = ref_slices.Get(i)[0];
+	    int pi2 = ref_slices.Get(i)[1];
+	    int idnr = ref_slices.Get(i)[2];
+	    int slicenr = ref_slices.Get(i)[3];
+
+	    if (slicenr > 0)
+	      {
+		const Point3d & p1 = mesh.Point(pi1);
+		const Point3d & p2 = mesh.Point(pi2);
+		int npi;
+
+		const CloseSurfaceIdentification * csid = 
+		  dynamic_cast<const CloseSurfaceIdentification*> 
+		  (geom->identifications.Get(idnr));
+
+	      
+		INDEX_2 edge(pi1, pi2);
+		edge.Sort();
+		if (!refedges.Used(edge))
+		  {
+		    const ARRAY<double> & slices = csid->GetSlices();
+		    //(*testout) << "idnr " << idnr << " i " << i << endl;
+		    //(*testout) << "slices " << slices << endl;
+		    double slicefac = slices.Get(slicenr);
+		    double slicefaclast = 
+		      (slicenr == slices.Size()) ? 1 : slices.Get(slicenr+1);
+		    
+		    Point3d np = p1 + (slicefac / slicefaclast) * (p2-p1);
+		    //(*testout) << "slicenr " << slicenr << " slicefac " << slicefac << " quot " << (slicefac / slicefaclast) << " np " << np << endl;
+		    npi = mesh.AddPoint (np);
+		    refedges.Set (edge, npi);
+		    found = 1;
+		  }
+		else
+		  npi = refedges.Get (edge);
+		
+		ref_slices.Elem(i)[1] = npi;
+		ref_slices.Elem(i)[3] --;
+	      }
+	  }
+
+
+
+
+	for (i = 1; i <= mesh.GetNE(); i++)
+	  {
+	    Element & el = mesh.VolumeElement (i);
+	    if (el.GetType() != PRISM)
+	      continue;
+
+	    for (j = 1; j <= 3; j++)
+	      {
+		int pi1 = el.PNum(j);
+		int pi2 = el.PNum(j+3);
+		const Point3d & p1 = mesh.Point(pi1);
+		const Point3d & p2 = mesh.Point(pi2);
+
+		bool ref = 0;
+
+		/*
+		  if (Dist (p1, p2) > mesh.GetH (Center (p1, p2)))
+		  ref = 1;
+		*/
+
+		/*
+		  if (cnt <= opt.minref)
+		  ref = 1;
+		*/
+
+		/*
+		  if ((pi1 == 460 || pi2 == 460 ||
+		  pi1 == 461 || pi2 == 461) && cnt <= 8) ref = 1;
+		*/
+		if (ref == 1)
+		  {
+		    INDEX_2 edge(pi1, pi2);
+		    edge.Sort();
+		    if (!refedges.Used(edge))
+		      {
+			Point3d np = Center (p1, p2);
+			int npi = mesh.AddPoint (np);
+			refedges.Set (edge, npi);
+			found = 1;
+		      }
+		  }
+	      }
+	  }
+      
+	if (!found) break;
+
+	// build closure:
+	PrintMessage (5, "start closure");
+	do
+	  {
+	    PrintMessage (5, "start loop");
+	    change = 0;
+	    for (i = 1; i <= mesh.GetNE(); i++)
+	      {
+		Element & el = mesh.VolumeElement (i);
+		if (el.GetType() != PRISM)
+		  continue;
+	      
+		bool hasref = 0, hasnonref = 0;
+		for (j = 1; j <= 3; j++)
+		  {
+		    int pi1 = el.PNum(j);
+		    int pi2 = el.PNum(j+3);
+		    if (pi1 != pi2)
+		      {
+			INDEX_2 edge(pi1, pi2);
+			edge.Sort();
+			if (refedges.Used(edge))
+			  hasref = 1;
+			else 
+			  hasnonref = 1;
+		      }
+		  }
+
+		if (hasref && hasnonref)
+		  {
+		    //		  cout << "el " << i << " in closure" << endl;
+		    change = 1;
+		    for (j = 1; j <= 3; j++)
+		      {
+			int pi1 = el.PNum(j);
+			int pi2 = el.PNum(j+3);
+			const Point3d & p1 = mesh.Point(pi1);
+			const Point3d & p2 = mesh.Point(pi2);
+		      
+			INDEX_2 edge(pi1, pi2);
+			edge.Sort();
+			if (!refedges.Used(edge))
+			  {
+			    Point3d np = Center (p1, p2);
+			    int npi = mesh.AddPoint (np);
+			    refedges.Set (edge, npi);
+			  }
+		      }
+		  }
+	      }
+	  }
+	while (change);
+
+	PrintMessage (5, "Do segments");
+
+	//      (*testout) << "closure formed, np = " << mesh.GetNP() << endl;
+
+	int oldns = mesh.GetNSeg();
+
+	for (i = 1; i <= oldns; i++)
+	  {
+	    const Segment & el = mesh.LineSegment(i);
+
+	    INDEX_2 i2(el.p1, el.p2);
+	    i2.Sort();
+	  
+	    int pnew;
+	    EdgePointGeomInfo ngi;
+      
+	    if (refedges.Used(i2))
+	      {
+		pnew = refedges.Get(i2);
+		//	      ngi = epgi.Get(pnew);
+	      }
+	    else
+	      {
+		continue;
+
+		// 	      Point3d pb;
+
+		// 	      /*
+		// 	      geom->PointBetween (mesh.Point (el.p1),
+		// 				  mesh.Point (el.p2),
+		// 				  el.surfnr1, el.surfnr2,
+		// 				  el.epgeominfo[0], el.epgeominfo[1],
+		// 				  pb, ngi);
+		// 	      */
+		// 	      pb = Center (mesh.Point (el.p1), mesh.Point (el.p2));
+
+		// 	      pnew = mesh.AddPoint (pb);
+	      
+		// 	      refedges.Set (i2, pnew);
+	      
+		// 	      if (pnew > epgi.Size())
+		// 		epgi.SetSize (pnew);
+		// 	      epgi.Elem(pnew) = ngi;
+	      }
+	  
+	    Segment ns1 = el;
+	    Segment ns2 = el;
+	    ns1.p2 = pnew;
+	    ns1.epgeominfo[1] = ngi;
+	    ns2.p1 = pnew;
+	    ns2.epgeominfo[0] = ngi;
+
+	    mesh.LineSegment(i) = ns1;
+	    mesh.AddSegment (ns2);
+	  }
+      
+	PrintMessage (5, "Segments done, NSeg = ", mesh.GetNSeg());
+
+	// do refinement
+	int oldne = mesh.GetNE();
+	for (i = 1; i <= oldne; i++)
+	  {
+	    Element & el = mesh.VolumeElement (i);
+	    if (el.GetNP() != 6)
+	      continue;
+
+	    int npi[3];
+	    for (j = 1; j <= 3; j++)
+	      {
+		int pi1 = el.PNum(j);
+		int pi2 = el.PNum(j+3);
+
+		if (pi1 == pi2)
+		  npi[j-1] = pi1;
+		else
+		  {
+		    INDEX_2 edge(pi1, pi2);
+		    edge.Sort();
+		    if (refedges.Used (edge))
+		      npi[j-1] = refedges.Get(edge);
+		    else
+		      {
+			/*
+			  (*testout) << "ERROR: prism " << i << " has hanging node !!" 
+			  << ", edge = " << edge << endl;
+			  cerr << "ERROR: prism " << i << " has hanging node !!" << endl;
+			*/
+			npi[j-1] = 0;
+		      }
+		  }
+	      }
+
+	    if (npi[0])
+	      {
+		Element nel1(6), nel2(6);
+		for (j = 1; j <= 3; j++)
+		  {
+		    nel1.PNum(j) = el.PNum(j);
+		    nel1.PNum(j+3) = npi[j-1];
+		    nel2.PNum(j) = npi[j-1];
+		    nel2.PNum(j+3) = el.PNum(j+3);
+		  }
+		nel1.SetIndex (el.GetIndex());
+		nel2.SetIndex (el.GetIndex());
+		mesh.VolumeElement (i) = nel1;
+		mesh.AddVolumeElement (nel2);
+	      }
+	  }
+
+      
+	PrintMessage (5, "Elements done, NE = ", mesh.GetNE());
+
+
+	// do surface elements
+	int oldnse = mesh.GetNSE();
+	//      cout << "oldnse = " << oldnse << endl;
+	for (i = 1; i <= oldnse; i++)
+	  {
+	    Element2d & el = mesh.SurfaceElement (i);
+	    if (el.GetType() != QUAD)
+	      continue;
+
+	    int index = el.GetIndex();
+	    int npi[2];
+	    for (j = 1; j <= 2; j++)
+	      {
+		int pi1, pi2;
+
+		if (j == 1)
+		  {
+		    pi1 = el.PNum(1);
+		    pi2 = el.PNum(4);
+		  }
+		else
+		  {
+		    pi1 = el.PNum(2);
+		    pi2 = el.PNum(3);
+		  }
+
+		if (pi1 == pi2)
+		  npi[j-1] = pi1;
+		else
+		  {
+		    INDEX_2 edge(pi1, pi2);
+		    edge.Sort();
+		    if (refedges.Used (edge))
+		      npi[j-1] = refedges.Get(edge);
+		    else
+		      {
+			npi[j-1] = 0;
+		      }
+		  }
+	      }
+
+	    if (npi[0])
+	      {
+		Element2d nel1(QUAD), nel2(QUAD);
+		for (j = 1; j <= 4; j++)
+		  {
+		    nel1.PNum(j) = el.PNum(j);
+		    nel2.PNum(j) = el.PNum(j);
+		  }
+		nel1.PNum(3) = npi[1];
+		nel1.PNum(4) = npi[0];
+		nel2.PNum(1) = npi[0];
+		nel2.PNum(2) = npi[1];
+		/*
+		  for (j = 1; j <= 2; j++)
+		  {
+		  nel1.PNum(j) = el.PNum(j);
+		  nel1.PNum(j+2) = npi[j-1];
+		  nel2.PNum(j) = npi[j-1];
+		  nel2.PNum(j+2) = el.PNum(j+2);
+		  }
+		*/
+		nel1.SetIndex (el.GetIndex());
+		nel2.SetIndex (el.GetIndex());
+
+		mesh.SurfaceElement (i) = nel1;
+		mesh.AddSurfaceElement (nel2);
+
+		int si = mesh.GetFaceDescriptor (index).SurfNr();
+
+		Point<3> hp = mesh.Point(npi[0]);
+		geom->GetSurface(si)->Project (hp);
+		mesh.Point (npi[0]).SetPoint (hp);
+
+		hp = mesh.Point(npi[1]);
+		geom->GetSurface(si)->Project (hp);
+		mesh.Point (npi[1]).SetPoint (hp);
+
+		//	      geom->GetSurface(si)->Project (mesh.Point(npi[0]));
+		//	      geom->GetSurface(si)->Project (mesh.Point(npi[1]));
+	      }
+	  }
+
+	PrintMessage (5, "Surface elements done, NSE = ", mesh.GetNSE());
+
+      }
+  }
+
+
+
+  void ZRefinement (Mesh & mesh, const CSGeometry * geom,
+		    ZRefinementOptions & opt)
+  {
+    INDEX_2_HASHTABLE<int> singedges(mesh.GetNSeg());
+
+    SelectSingularEdges (mesh, *geom, singedges, opt);
+    //MakePrismsSingEdge (mesh, singedges);
+    MakePrismsClosePoints (mesh);
+
+    RefinePrisms (mesh, geom, opt);
+  }
+
+
+
+  ZRefinementOptions :: ZRefinementOptions()
+  {
+    minref = 0;
+  }
+
+}
diff --git a/contrib/Netgen/libsrc/opti/Makefile b/contrib/Netgen/libsrc/opti/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..d73441553f5d206679559512e4d7c50af8b21e15
--- /dev/null
+++ b/contrib/Netgen/libsrc/opti/Makefile
@@ -0,0 +1,10 @@
+#
+# Makefile for optimisation library
+#
+src = bfgs.cpp linsearch.cpp linopt.cpp 
+#
+lib = opti
+libpath = libsrc/opti
+#
+#
+include ../makefile.inc
diff --git a/contrib/Netgen/libsrc/opti/bfgs.cpp b/contrib/Netgen/libsrc/opti/bfgs.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..d106b6f1c0421d5fde9ae5068ee7468d22aafd24
--- /dev/null
+++ b/contrib/Netgen/libsrc/opti/bfgs.cpp
@@ -0,0 +1,410 @@
+/***************************************************************************/
+/*                                                                         */
+/* Vorlesung Optimierung I, Gfrerer, WS94/95                               */
+/* BFGS-Verfahren zur L�sung freier nichtlinearer Optimierungsprobleme     */
+/*                                                                         */
+/* Programmautor:  Joachim Sch�berl                                        */
+/* Matrikelnummer: 9155284                                                 */
+/*                                                                         */
+/***************************************************************************/
+
+#include <mystdlib.h>
+#include <myadt.hpp> 
+
+#include <linalg.hpp>
+#include "opti.hpp"
+
+
+namespace netgen
+{
+
+void Cholesky (const DenseMatrix & a,
+	       DenseMatrix & l, Vector & d)
+{
+  // Factors   A = L D L^T
+
+  double x;
+
+  int i, j, k;
+  int n = a.Height();
+  
+  //  (*testout) << "a = " << a << endl;
+
+  l = a;
+
+  for (i = 1; i <= n; i++)
+    {
+      for (j = i; j <= n; j++)
+	{
+	  x = l.Get(i, j);
+
+	  for (k = 1; k < i; k++)
+	    x -= l.Get(i, k) * l.Get(j, k) * d.Get(k); 
+	  
+	  if (i == j)
+	    {
+	      d.Elem(i) = x;
+	    }
+	  else
+	    {
+	      l.Elem(j, i) = x / d.Get(k);
+	    }
+	}
+    }
+
+  for (i = 1; i <= n; i++)
+    {
+      l.Elem(i, i) = 1;
+      for (j = i+1; j <= n; j++)
+	l.Elem(i, j) = 0;
+    }
+
+  /*
+  // Multiply:
+  (*testout) << "multiplied factors: " << endl;
+  for (i = 1; i <= n; i++)
+    for (j = 1; j <= n; j++)
+      {
+	x = 0;
+	for (k = 1; k <= n; k++)
+	  x += l.Get(i, k) * l.Get(j, k) * d.Get(k);
+	(*testout) << x << " ";
+      }
+  (*testout) << endl;
+  */
+}
+
+
+void MultLDLt (const DenseMatrix & l, const Vector & d, const Vector & g, Vector & p)
+{
+  /*
+  int i, j, n;
+  double val;
+
+  n = l.Height();
+  p = g;
+  for (i = 1; i <= n; i++)
+    {
+      val = 0;
+      for (j = i; j <= n; j++)
+	val += p.Get(j) * l.Get(j, i);
+      p.Set(i, val);
+    }
+  for (i = 1; i <= n; i++)
+    p.Elem(i) *= d.Get(i);
+
+  for (i = n; i >= 1; i--)
+    {
+      val = 0;
+      for (j = 1; j <= i; j++)
+	val += p.Get(j) * l.Get(i, j);
+      p.Set(i, val);
+    }
+  */
+
+
+
+  double val;
+
+  int n = l.Height();
+  p = g;
+  
+  for (int i = 0; i < n; i++)
+    {
+      val = 0;
+      for (int j = i; j < n; j++)
+	val += p(j) * l(j, i);
+      p(i) = val;
+    }
+
+  for (int i = 0; i < n; i++)
+    p(i) *= d(i);
+
+  for (int i = n-1; i >= 0; i--)
+    {
+      val = 0;
+      for (int j = 0; j <= i; j++)
+	val += p(j) * l(i, j);
+      p(i) = val;
+    }
+}
+
+void SolveLDLt (const DenseMatrix & l, const Vector & d, const Vector & g, Vector & p)
+{
+  double val;
+
+  int n = l.Height();
+  p = g;
+
+  for (int i = 0; i < n; i++)
+    {
+      val = 0;
+      for (int j = 0; j < i; j++)
+	val += p(j) * l(i,j);
+      p(i) -= val;
+    }
+
+  for (int i = 0; i < n; i++)
+    p(i) /= d(i);
+  
+  for (int i = n-1; i >= 0; i--)
+    {
+      val = 0;
+      for (int j = i+1; j < n; j++)
+	val += p(j) * l(j, i);
+      p(i) -= val;
+    }
+}
+
+int LDLtUpdate (DenseMatrix & l, Vector & d, double a, const Vector & u)
+{
+  // Bemerkung: Es wird a aus R erlaubt
+  // Rueckgabewert: 0 .. D bleibt positiv definit
+  //                1 .. sonst
+
+  int i, j, n;
+
+  n = l.Height();
+
+  Vector v(n);
+  double t, told, xi;
+
+  told = 1;
+  v = u;
+
+  for (j = 1; j <= n; j++)
+    {
+      t = told + a * sqr (v.Elem(j)) / d.Get(j);
+
+      if (t <= 0) 
+	{
+	  (*testout) << "update err, t = " << t << endl;
+	  return 1;
+	}
+
+      xi = a * v.Elem(j) / (d.Get(j) * t);
+
+      d.Elem(j) *= t / told;
+
+      for (i = j + 1; i <= n; i++)
+	{
+	  v.Elem(i) -= v.Elem(j) * l.Elem(i, j);
+	  l.Elem(i, j) += xi * v.Elem(i);
+	}
+
+      told = t;
+    }
+
+  return 0;
+}
+
+
+double BFGS (
+	     Vector & x,         // i: Startwert
+	     // o: Loesung, falls IFAIL = 0
+	     const MinFunction & fun,
+	     const OptiParameters & par,
+	     double eps
+	     )
+
+
+{
+  int i, j, n = x.Size();
+  long it;
+  char a1crit, a3acrit;
+
+
+  Vector d(n), g(n), p(n), temp(n), bs(n), xneu(n), y(n), s(n), x0(n);
+  DenseMatrix l(n);
+  DenseMatrix hesse(n);
+
+  double /* normg, */ alphahat, hd, fold;
+  double a1, a2;
+  const double mu1 = 0.1, sigma = 0.1, xi1 = 1, xi2 = 10;
+  const double tau = 0.1, tau1 = 0.1, tau2 = 0.6;
+
+  Vector typx(x.Size());      // i: typische Groessenordnung der Komponenten
+  double f, f0;
+  double typf;               // i: typische Groessenordnung der Loesung
+  double fmin = -1e5;           // i: untere Schranke fuer Funktionswert
+  //  double eps = 1e-8;            // i: Abbruchschranke fuer relativen Gradienten
+  double tauf = 0.1;            // i: Abbruchschranke fuer die relative Aenderung der
+                                //    Funktionswerte
+  int ifail;                    // o:  0 .. Erfolg
+                                //    -1 .. Unterschreitung von fmin
+                                //     1 .. kein Erfolg bei Liniensuche
+                                //     2 .. �berschreitung von itmax
+
+  typx = par.typx;
+  typf = par.typf;
+
+
+  l = 0;
+  for (i = 1; i <= n; i++)
+    l.Elem(i, i) = 1;
+
+  f = fun.FuncGrad (x, g);
+  f0 = f;
+  x0 = x;
+
+  it = 0;
+  do
+    {
+      // Restart
+
+      if (it % (5 * n) == 0)
+	{
+
+	  for (i = 1; i <= n; i++)
+	    d.Elem(i) = typf/ sqr (typx.Get(i));   // 1;
+	  for (i = 2; i <= n; i++)
+	    for (j = 1; j < i; j++)
+	      l.Elem(i, j) = 0;
+
+	  /*
+	  hesse = 0;
+	  for (i = 1; i <= n; i++)
+	    hesse.Elem(i, i) = typf / sqr (typx.Get(i));  
+
+	  fun.ApproximateHesse (x, hesse);
+
+	  Cholesky (hesse, l, d);
+	  */
+	}
+
+      it++;
+      if (it > par.maxit_bfgs)
+	{
+	  ifail = 2;
+	  break;
+	}
+
+
+      // Solve with factorized B
+
+      SolveLDLt (l, d, g, p);
+
+ //      (*testout) << "l " << l << endl
+// 		 << "d " << d << endl
+// 		 << "g " << g << endl
+// 		 << "p " << p << endl;
+
+
+      p *= -1;
+      y = g;
+
+      fold = f;
+
+      // line search
+
+      alphahat = 1;
+      lines (x, xneu, p, f, g, fun, par, alphahat, fmin,
+	     mu1, sigma, xi1, xi2, tau, tau1, tau2, ifail);
+
+      if(ifail == 1)
+	(*testout) << "no success with linesearch" << endl;
+
+       /*
+      // if (it > par.maxit_bfgs/2)
+	{
+	  (*testout) << "x = " << x << endl;
+	  (*testout) << "xneu = " << xneu << endl;
+	  (*testout) << "f = " << f << endl;
+	  (*testout) << "g = " << g << endl;
+	}
+      */
+
+      //      (*testout) << "it = " << it << " f = " << f << endl;
+      //      if (ifail != 0) break;
+
+      s.Set2 (1, xneu, -1, x);
+      y *= -1;
+      y.Add (1,g); // y += g;
+
+      x = xneu;
+
+      // BFGS Update
+
+      MultLDLt (l, d, s, bs);
+
+      a1 = y * s;
+      a2 = s * bs;
+
+      if (a1 > 0 && a2 > 0)
+	{
+	  if (LDLtUpdate (l, d, 1 / a1, y) != 0)
+	    {
+              cerr << "BFGS update error1" << endl;
+	      (*testout) << "BFGS update error1" << endl;
+	      (*testout) << "l " << endl << l << endl
+			 << "d " << d << endl;
+	      ifail = 1;
+	      break;
+	    }
+
+	  if (LDLtUpdate (l, d, -1 / a2, bs) != 0)
+	    {
+              cerr << "BFGS update error2" << endl;
+	      (*testout) << "BFGS update error2" << endl;
+	      (*testout) << "l " << endl << l << endl
+			 << "d " << d << endl;
+	      ifail = 1;
+	      break;
+	    }
+	}
+
+      // Calculate stop conditions
+
+      hd = eps * max2 (typf, fabs (f));
+      a1crit = 1;
+      for (i = 1; i <= n; i++)
+	if ( fabs (g.Elem(i)) * max2 (typx.Elem(i), fabs (x.Elem(i))) > hd)
+	  a1crit = 0;
+
+
+      a3acrit = (fold - f <= tauf * max2 (typf, fabs (f)));
+
+      //    testout << "g = " << g << endl;
+      //    testout << "a1crit, a3crit = " << int(a1crit) << ", " << int(a3acrit) << endl;
+
+      /*
+	// Output for tests
+
+	normg = sqrt (g * g);
+
+	testout << "it =" << setw (5) << it
+	<< " f =" << setw (12) << setprecision (5) << f
+	<< " |g| =" << setw (12) << setprecision (5) << normg;
+
+	testout << " x = (" << setw (12) << setprecision (5) << x.Elem(1);
+	for (i = 2; i <= n; i++)
+	testout << "," << setw (12) << setprecision (5) << x.Elem(i);
+	testout << ")" << endl;
+	*/
+
+      //(*testout) << "it = " << it << " f = " << f << " x = " << x << endl
+      //	 << " g = " << g << " p = " << p << endl << endl;
+
+      //      (*testout) << "|g| = " << g.L2Norm() << endl;
+
+      if (g.L2Norm() < fun.GradStopping (x)) break;
+
+    }
+  while (!a1crit || !a3acrit);
+
+  /*
+  (*testout) << "it = " << it << " g = " << g << " f = " << f 
+	     << " fail = " << ifail << endl;
+  */
+  if (f0 < f || (ifail == 1))
+    {
+      (*testout) << "fail, f = " << f << " f0 = " << f0 << endl;
+      f = f0;
+      x = x0;
+    }
+
+  //  (*testout) << "x = " << x << ", x0 = " << x0 << endl;
+  return f;
+}
+
+}
diff --git a/contrib/Netgen/libsrc/opti/linopt.cpp b/contrib/Netgen/libsrc/opti/linopt.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..a5d381e6b7b56b610e6255914a1f749188cc38b1
--- /dev/null
+++ b/contrib/Netgen/libsrc/opti/linopt.cpp
@@ -0,0 +1,73 @@
+#include <mystdlib.h>
+#include <myadt.hpp>
+
+#include <linalg.hpp>
+#include "opti.hpp"
+
+namespace netgen
+{
+
+void LinearOptimize (const DenseMatrix & a, const Vector & b, 
+    const Vector & c, Vector & x)
+    
+  {
+  int i1, i2, i3, j;
+  DenseMatrix m(3), inv(3);
+  Vector rs(3), hx(3), res(a.Height()), res2(3);
+  double f, fmin;
+  int nrest;
+    
+  if (a.Width() != 3)
+    {
+    cerr << "LinearOptimize only implemented for 3 unknowns" << endl;
+    return;
+    }
+    
+  fmin = 1e10;
+  x = 0;
+  nrest = a.Height();
+  for (i1 = 1; i1 <= nrest; i1++)
+    for (i2 = i1 + 1; i2 <= nrest; i2++)
+      for (i3 = i2 + 1; i3 <= nrest; i3++)
+        {
+        for (j = 1; j <= 3; j++)
+          {
+          m.Elem(1, j) = a.Get(i1, j);
+          m.Elem(2, j) = a.Get(i2, j);
+          m.Elem(3, j) = a.Get(i3, j);
+          }
+          
+        rs.Elem(1) = b.Get(i1);
+        rs.Elem(2) = b.Get(i2);
+        rs.Elem(3) = b.Get(i3);
+        
+        if (fabs (m.Det()) < 1e-12) continue;
+        
+        CalcInverse (m, inv);
+        inv.Mult (rs, hx);
+        
+        a.Residuum (hx, b, res);
+//        m.Residuum (hx, rs, res2);
+        f = c * hx;
+
+/*        
+        testout -> precision(12);
+        (*testout) << "i = (" << i1 << "," << i2 << "," << i3 
+           << "), f = " << f << " x = " << x << " res = " << res 
+           <<  " resmin = " << res.Min() 
+           << " res2 = " << res2 << " prod = " << prod << endl;
+*/
+
+	
+	double rmin = res.Elem(1);
+	for (int hi = 2; hi <= res.Size(); hi++)
+	  if (res.Elem(hi) < rmin) rmin = res.Elem(hi);
+        
+        if ( (f < fmin) && rmin >= -1e-8)
+          {
+          fmin = f;
+          x = hx;
+          }
+        }
+  }
+}
diff --git a/contrib/Netgen/libsrc/opti/linsearch.cpp b/contrib/Netgen/libsrc/opti/linsearch.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..4c297fd92c8dc0b6b8007297c213a3a2dae5cf55
--- /dev/null
+++ b/contrib/Netgen/libsrc/opti/linsearch.cpp
@@ -0,0 +1,351 @@
+/***************************************************************************/
+/*                                                                         */
+/* Problem:        Liniensuche                                             */
+/*                                                                         */
+/* Programmautor:  Joachim Sch�berl                                        */
+/* Matrikelnummer: 9155284                                                 */
+/*                                                                         */
+/* Algorithmus nach:                                                       */
+/*                                                                         */
+/*   Optimierung I, Gfrerer, WS94/95                                       */
+/*   Algorithmus 2.1: Liniensuche Problem (ii)                             */
+/*                                                                         */
+/***************************************************************************/
+
+
+
+#include <mystdlib.h>
+
+#include <myadt.hpp>  // min, max, sqr
+
+#include <linalg.hpp>
+#include "opti.hpp"
+
+
+namespace netgen
+{
+const double eps0 = 1E-15;
+
+// Liniensuche
+
+
+double MinFunction :: Func (const Vector & /* x */) const
+{
+  cerr << "Func of MinFunction called" << endl;
+  return 0;
+}
+
+void MinFunction :: Grad (const Vector & /* x */, Vector & /* g */) const
+{
+  cerr << "Grad of MinFunction called" << endl;
+}
+  
+double MinFunction :: FuncGrad (const Vector & x, Vector & g) const
+{
+  cerr << "Grad of MinFunction called" << endl;
+  return 0;
+  /*
+  int n = x.Size();
+
+  static Vector xr;
+  static Vector xl;
+  xr.SetSize(n);
+  xl.SetSize(n);
+
+  double eps = 1e-6;
+  double fl, fr;
+  
+  for (int i = 1; i <= n; i++)
+    {
+      xr.Set (1, x);
+      xl.Set (1, x);
+
+      xr.Elem(i) += eps;
+      fr = Func (xr);
+
+      xl.Elem(i) -= eps;
+      fl = Func (xl);
+
+      g.Elem(i) = (fr - fl) / (2 * eps);
+    }
+
+  double f = Func(x);
+  //  (*testout) << "f = " << f << " grad = " << g << endl;
+  return f;
+  */
+}
+
+
+double MinFunction :: FuncDeriv (const Vector & x, const Vector & dir, double & deriv) const
+{
+  Vector g(x.Size());
+  double f = FuncGrad (x, g);
+  deriv = (g * dir);
+
+  //  (*testout) << "g = " << g << ", dir = " << dir << ", deriv = " << deriv << endl;
+  return f;
+}
+
+void MinFunction :: ApproximateHesse (const Vector & x,
+				      DenseMatrix & hesse) const
+{
+  int n = x.Size();
+  int i, j;
+
+  static Vector hx;
+  hx.SetSize(n);
+
+  double eps = 1e-6;
+  double f, f11, f12, f21, f22;
+  
+  for (i = 1; i <= n; i++)
+    {
+      for (j = 1; j < i; j++)
+	{
+	  hx = x;
+	  hx.Elem(i) = x.Get(i) + eps;
+	  hx.Elem(j) = x.Get(j) + eps;
+	  f11 = Func(hx);
+	  hx.Elem(i) = x.Get(i) + eps;
+	  hx.Elem(j) = x.Get(j) - eps;
+	  f12 = Func(hx);
+	  hx.Elem(i) = x.Get(i) - eps;
+	  hx.Elem(j) = x.Get(j) + eps;
+	  f21 = Func(hx);
+	  hx.Elem(i) = x.Get(i) - eps;
+	  hx.Elem(j) = x.Get(j) - eps;
+	  f22 = Func(hx);
+
+	  hesse.Elem(i, j) = hesse.Elem(j, i) =
+	    (f11 + f22 - f12 - f21) / (2 * eps * eps);
+	}
+
+      hx = x;
+      f = Func(x);
+      hx.Elem(i) = x.Get(i) + eps;
+      f11 = Func(hx);
+      hx.Elem(i) = x.Get(i) - eps;
+      f22 = Func(hx);
+
+      hesse.Elem(i, i) = (f11 + f22 - 2 * f) / (eps * eps);
+    }
+  //  (*testout) << "hesse = " << hesse << endl;
+}
+
+
+
+
+
+
+
+/// Line search, modified Mangasarien conditions
+void lines (Vector & x,         // i: initial point of line-search
+	    Vector & xneu,      // o: solution, if successful
+	    Vector & p,         // i: search direction
+	    double & f,         // i: function-value at x
+	    // o: function-value at xneu, iff ifail = 0
+	    Vector & g,         // i: gradient at x
+	    // o: gradient at xneu, iff ifail = 0
+	    const MinFunction & fun,  // function to minimize
+	    const OptiParameters & par,
+	    double & alphahat,  // i: initial value for alpha_hat
+	    // o: solution alpha iff ifail = 0
+	    double fmin,        // i: lower bound for f
+	    double mu1,         // i: Parameter mu_1 of Alg.2.1
+	    double sigma,       // i: Parameter sigma of Alg.2.1
+	    double xi1,         // i: Parameter xi_1 of Alg.2.1
+	    double xi2,         // i: Parameter xi_1 of Alg.2.1
+	    double tau,         // i: Parameter tau of Alg.2.1
+	    double tau1,        // i: Parameter tau_1 of Alg.2.1
+	    double tau2,        // i: Parameter tau_2 of Alg.2.1
+	    int & ifail)        // o: 0 on success
+  //    -1 bei termination because lower limit fmin
+  //     1 bei illegal termination due to different reasons
+
+{
+  double phi0, phi0prime, phi1, phi1prime, phihatprime;
+  double alpha1, alpha2, alphaincr, c;
+  char flag = 1;
+  long it;
+
+  alpha1 = 0;
+  alpha2 = 1e50;
+  phi0 = phi1 = f;
+
+  phi0prime = g * p;
+
+  if (phi0prime > 0)
+    {
+      ifail = 1;
+      return;
+    }
+
+  ifail = 1;  // Markus
+
+  phi1prime = phi0prime;
+
+  //  (*testout) << "phi0prime = " << phi0prime << endl;
+
+  //  it = 100000l;
+  it = 0;
+
+  while (it++ <= par.maxit_linsearch)
+    {
+
+      xneu.Set2 (1, x, alphahat, p);
+
+
+      //    f = fun.FuncGrad (xneu, g);
+      //      f = fun.Func (xneu);
+      f = fun.FuncDeriv (xneu, p, phihatprime);
+
+      // (*testout) << "lines, f = " << f << " phip = " << phihatprime << endl;
+
+      if (f < fmin)
+	{
+	  ifail = -1;
+	  break;
+	}
+
+
+      if (alpha2 - alpha1 < eps0 * alpha2)
+	{
+	  ifail = 0;
+	  break;
+	}
+
+      // (*testout) << "i = " << it << " al = " << alphahat << " f = " << f << " fprime " << phihatprime << endl;;
+
+      if (f - phi0 > mu1 * alphahat * phi1prime + eps0 * fabs (phi0))
+
+	{
+
+	  flag = 0;
+	  alpha2 = alphahat;
+
+	  c = 
+	    (f - phi1 - phi1prime * (alphahat-alpha1)) / 
+	    sqr (alphahat-alpha1);
+
+	  alphahat = alpha1 - 0.5 * phi1prime / c;
+
+	  if (alphahat > alpha2)
+	    alphahat = alpha1 + 1/(4*c) *
+	      ( (sigma+mu1) * phi0prime - 2*phi1prime
+		+ sqrt (sqr(phi1prime - mu1 * phi0prime) -
+			4 * (phi1 - phi0 - mu1 * alpha1 * phi0prime) * c));
+
+	  alphahat = max2 (alphahat, alpha1 + tau * (alpha2 - alpha1));
+	  alphahat = min2 (alphahat, alpha2 - tau * (alpha2 - alpha1));
+	  
+	  //	  (*testout) << " if-branch" << endl;
+
+	}
+
+      else
+
+	{
+	  /*
+	  f = fun.FuncGrad (xneu, g);
+	  phihatprime = g * p;
+	  */
+	  f = fun.FuncDeriv (xneu, p, phihatprime);
+
+	  if (phihatprime < sigma * phi0prime * (1 + eps0))
+
+	    {
+	      if (phi1prime < phihatprime)   
+		// Approximationsfunktion ist konvex
+
+		alphaincr = (alphahat - alpha1) * phihatprime /
+		  (phi1prime - phihatprime);
+
+	      else
+		alphaincr = 1e99; // MAXDOUBLE;
+
+	      if (flag)
+		{
+		  alphaincr = max2 (alphaincr, xi1 * (alphahat-alpha1));
+		  alphaincr = min2 (alphaincr, xi2 * (alphahat-alpha1));
+		}
+	      else
+		{
+		  alphaincr = max2 (alphaincr, tau1 * (alpha2 - alphahat));
+		  alphaincr = min2 (alphaincr, tau2 * (alpha2 - alphahat));
+		}
+
+	      alpha1 = alphahat;
+	      alphahat += alphaincr;
+	      phi1 = f;
+	      phi1prime = phihatprime;
+	    }
+
+	  else
+
+	    {
+	      ifail = 0;     // Erfolg !!
+	      break;
+	    }
+	  
+	  //	  (*testout) << " else, " << endl;
+
+	}
+
+    }
+
+  //  (*testout) << "linsearch: it = " << it << " ifail = " << ifail << endl;
+
+  fun.FuncGrad (xneu, g);
+
+
+  if (it < 0)
+    ifail = 1;
+
+  //  (*testout) << "fail = " << ifail << endl;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+void SteepestDescent (Vector & x, const MinFunction & fun,
+		      const OptiParameters & par)
+{
+  int it, n = x.Size();
+  Vector xnew(n), p(n), g(n), g2(n);
+  double val, alphahat;
+  int fail;
+
+  val = fun.FuncGrad(x, g);
+
+  alphahat = 1;
+  //  testout << "f = ";
+  for (it = 0; it < 10; it++)
+    {
+      //    testout << val << " ";
+
+      // p = -g;
+      p.Set (-1, g);
+
+      lines (x, xnew, p, val, g, fun, par, alphahat, -1e5,
+	     0.1, 0.1, 1, 10, 0.1, 0.1, 0.6, fail);
+
+      x = xnew;
+    }
+  //  testout << endl;
+}
+}
diff --git a/contrib/Netgen/libsrc/opti/opti.hpp b/contrib/Netgen/libsrc/opti/opti.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..9875786900ea8cba360c04149ff4c57c5e0aa66e
--- /dev/null
+++ b/contrib/Netgen/libsrc/opti/opti.hpp
@@ -0,0 +1,142 @@
+#ifndef FILE_OPTI
+#define FILE_OPTI
+
+/**************************************************************************/
+/* File:   opti.hpp                                                       */
+/* Author: Joachim Schoeberl                                              */
+/* Date:   01. Jun. 95                                                    */
+/**************************************************************************/
+
+
+
+namespace netgen
+{
+
+  /** 
+      Function to be minimized.
+  */
+  class MinFunction 
+  {
+  public:
+    ///
+    virtual double Func (const Vector & x) const;
+    ///
+    virtual void Grad (const Vector & x, Vector & g) const;
+    /// function and gradient
+    virtual double FuncGrad (const Vector & x, Vector & g) const;
+    /// directional derivative
+    virtual double FuncDeriv (const Vector & x, const Vector & dir, double & deriv) const;
+    /// if |g| < gradaccuray, then stop bfgs
+    virtual double GradStopping (const Vector & /* x */) const { return 0; } 
+
+    ///
+    virtual void ApproximateHesse (const Vector & /* x */,
+				   DenseMatrix & /* hesse */) const;
+  };
+
+
+  class OptiParameters
+  {
+  public:
+    int maxit_linsearch;
+    int maxit_bfgs;
+    double typf;
+    double typx;
+
+    OptiParameters ()
+    {
+      maxit_linsearch = 100;
+      maxit_bfgs = 100;
+      typf = 1;
+      typx = 1;
+    }
+  };
+  
+  
+  /** Implementation of BFGS method.
+      Efficient method for non-linear minimiztion problems.
+      @param x initial value and solution 
+      @param fun function to be minimized
+  */
+  extern double BFGS (Vector & x, const MinFunction & fun, 
+		      const OptiParameters & par,
+		      double eps = 1e-8);
+
+  /** Steepest descent method.
+      Simple method for non-linear minimization problems.
+      @param x initial value and solution 
+      @param fun function to be minimized
+  */
+  void SteepestDescent (Vector & x, const MinFunction & fun,
+			const OptiParameters &  par);
+
+
+  extern void lines (
+		     Vector & x,         // i: Ausgangspunkt der Liniensuche
+		     Vector & xneu,      // o: Loesung der Liniensuche bei Erfolg
+		     Vector & p,         // i: Suchrichtung
+		     double & f,         // i: Funktionswert an der Stelle x
+		     // o: Funktionswert an der Stelle xneu, falls ifail = 0
+		     Vector & g,         // i: Gradient an der Stelle x
+		     // o: Gradient an der Stelle xneu, falls ifail = 0
+
+		     const MinFunction & fun,  // function to minmize
+		     const OptiParameters & par, // parameters
+		     double & alphahat,  // i: Startwert f�r alpha_hat
+		     // o: Loesung falls ifail = 0
+		     double fmin,        // i: untere Schranke f�r f
+		     double mu1,         // i: Parameter mu_1 aus Alg.2.1
+		     double sigma,       // i: Parameter sigma aus Alg.2.1
+		     double xi1,         // i: Parameter xi_1 aus Alg.2.1
+		     double xi2,         // i: Parameter xi_1 aus Alg.2.1
+		     double tau,         // i: Parameter tau aus Alg.2.1
+		     double tau1,        // i: Parameter tau_1 aus Alg.2.1
+		     double tau2,        // i: Parameter tau_2 aus Alg.2.1
+		     int & ifail);        // o:  0 bei erfolgreicher Liniensuche
+  //    -1 bei Abbruch wegen Unterschreiten von fmin
+  //    1 bei Abbruch, aus sonstigen Gr�nden
+
+
+
+
+  /**  
+       Solver for linear programming problem.
+
+       \begin{verbatim}
+       min      c^t x
+       A x <= b    
+       \end{verbatim}
+  */
+  extern void LinearOptimize (const DenseMatrix & a, const Vector & b, 
+			      const Vector & c, Vector & x);
+
+
+#ifdef NONE
+
+  /**
+     Simple projection iteration.
+  
+     find $u = argmin_{v >= 0}  0.5 u A u - f u$
+  */
+  extern void ApproxProject (const BaseMatrix & a, Vector & u, 
+			     const Vector & f,
+			     double tau, int its);
+ 
+
+  /**
+     CG Algorithm for quadratic programming problem.
+     See: Dostal ...
+
+     d ... diag(A) ^{-1}
+  */
+  extern void ApproxProjectCG (const BaseMatrix & a, Vector & x, 
+			       const Vector & b, const class DiagMatrix & d,
+			       double gamma, int & steps, int & changes);
+
+#endif
+
+
+}
+
+#endif
+