private double[,] CalculateMembraneDeformationMatrix(ShapeTSplines2DFromBezierExtraction tsplines, int j, double[] surfaceBasisVector1,
                                                             double[] surfaceBasisVector2, ControlPoint[] elementControlPoints)
        {
            var dRIa = new double[3, elementControlPoints.Length * 3];

            for (var i = 0; i < elementControlPoints.Length; i++)
            {
                for (var m = 0; m < 3; m++)
                {
                    dRIa[m, i] = tsplines.TSplineDerivativeValuesHeta[i, j] * surfaceBasisVector1[m] +
                                 tsplines.TSplineDerivativeValuesKsi[i, j] * surfaceBasisVector2[m];
                }
            }

            var Bmembrane = new double[3, elementControlPoints.Length * 3];

            for (var column = 0; column < elementControlPoints.Length * 3; column += 3)
            {
                Bmembrane[0, column]     = tsplines.TSplineDerivativeValuesKsi[column / 3, j] * surfaceBasisVector1[0];
                Bmembrane[0, column + 1] = tsplines.TSplineDerivativeValuesKsi[column / 3, j] * surfaceBasisVector1[1];
                Bmembrane[0, column + 2] = tsplines.TSplineDerivativeValuesKsi[column / 3, j] * surfaceBasisVector1[2];

                Bmembrane[1, column]     = tsplines.TSplineDerivativeValuesHeta[column / 3, j] * surfaceBasisVector2[0];
                Bmembrane[1, column + 1] = tsplines.TSplineDerivativeValuesHeta[column / 3, j] * surfaceBasisVector2[1];
                Bmembrane[1, column + 2] = tsplines.TSplineDerivativeValuesHeta[column / 3, j] * surfaceBasisVector2[2];

                Bmembrane[2, column]     = dRIa[0, column / 3];
                Bmembrane[2, column + 1] = dRIa[1, column / 3];
                Bmembrane[2, column + 2] = dRIa[2, column / 3];
            }

            return(Bmembrane);
        }
        /// <summary>
        /// Calculates knots physical coordinates for post-processing with Paraview.
        /// </summary>
        /// <param name="element">An <see cref="Element"/> of type <see cref="TSplineKirchhoffLoveShellElementMaterial"/>.</param>
        /// <returns>A <see cref="double"/> array calculating the coordinates of the element Knots'.
        /// The rows of the matrix denote the knot numbering while the columns the displacements for each degree of freedom.</returns>
        public double[,] CalculatePointsForPostProcessing(TSplineKirchhoffLoveShellElementMaterial element)
        {
            var localCoordinates = new double[4, 2]
            {
                { -1, -1 },
                { -1, 1 },
                { 1, -1 },
                { 1, 1 }
            };

            var knotParametricCoordinatesKsi  = Vector.CreateFromArray(new double[] { -1, 1 });
            var knotParametricCoordinatesHeta = Vector.CreateFromArray(new double[] { -1, 1 });
            var elementControlPoints          = element.ControlPoints.ToArray();
            var tsplines = new ShapeTSplines2DFromBezierExtraction(element, elementControlPoints, knotParametricCoordinatesKsi, knotParametricCoordinatesHeta);

            var knotDisplacements       = new double[4, 3];
            var paraviewKnotRenumbering = new int[] { 0, 3, 1, 2 };

            for (int j = 0; j < localCoordinates.GetLength(0); j++)
            {
                for (int i = 0; i < elementControlPoints.Length; i++)
                {
                    knotDisplacements[paraviewKnotRenumbering[j], 0] += tsplines.TSplineValues[i, j] * elementControlPoints[i].X;
                    knotDisplacements[paraviewKnotRenumbering[j], 1] += tsplines.TSplineValues[i, j] * elementControlPoints[i].Y;
                    knotDisplacements[paraviewKnotRenumbering[j], 2] += tsplines.TSplineValues[i, j] * elementControlPoints[i].Z;
                }
            }

            return(knotDisplacements);
        }
        private Matrix CalculateMembraneDeformationMatrix(ShapeTSplines2DFromBezierExtraction tsplines, int j, Vector surfaceBasisVector1,
                                                          Vector surfaceBasisVector2, ControlPoint[] elementControlPoints)
        {
            Matrix dRIa = Matrix.CreateZero(3, elementControlPoints.Length * 3);

            for (int i = 0; i < elementControlPoints.Length; i++)
            {
                for (int m = 0; m < 3; m++)
                {
                    dRIa[m, i] = tsplines.TSplineDerivativeValuesHeta[i, j] * surfaceBasisVector1[m] +
                                 tsplines.TSplineDerivativeValuesKsi[i, j] * surfaceBasisVector2[m];
                }
            }

            Matrix Bmembrane = Matrix.CreateZero(3, elementControlPoints.Length * 3);

            for (int column = 0; column < elementControlPoints.Length * 3; column += 3)
            {
                Bmembrane[0, column]     = tsplines.TSplineDerivativeValuesKsi[column / 3, j] * surfaceBasisVector1[0];
                Bmembrane[0, column + 1] = tsplines.TSplineDerivativeValuesKsi[column / 3, j] * surfaceBasisVector1[1];
                Bmembrane[0, column + 2] = tsplines.TSplineDerivativeValuesKsi[column / 3, j] * surfaceBasisVector1[2];

                Bmembrane[1, column]     = tsplines.TSplineDerivativeValuesHeta[column / 3, j] * surfaceBasisVector2[0];
                Bmembrane[1, column + 1] = tsplines.TSplineDerivativeValuesHeta[column / 3, j] * surfaceBasisVector2[1];
                Bmembrane[1, column + 2] = tsplines.TSplineDerivativeValuesHeta[column / 3, j] * surfaceBasisVector2[2];

                Bmembrane[2, column]     = dRIa[0, column / 3];
                Bmembrane[2, column + 1] = dRIa[1, column / 3];
                Bmembrane[2, column + 2] = dRIa[2, column / 3];
            }

            return(Bmembrane);
        }
        /// <summary>
        /// This method calculates the internal forces of the element.
        /// </summary>
        /// <param name="element">An element of type <see cref="TSplineKirchhoffLoveShellElementMaterial"/>.</param>
        /// <param name="localDisplacements">A <see cref="double"/> array containing the displacements for the degrees of freedom of the element.</param>
        /// <param name="localdDisplacements">A <see cref="double"/> array containing the displacements change for the degrees of freedom of the element.</param>
        /// <returns>A <see cref="double"/> array containing the forces all degrees of freedom.</returns>
        public double[] CalculateForces(IElement element, double[] localDisplacements, double[] localdDisplacements)
        {
            var shellElement         = (TSplineKirchhoffLoveShellElementMaterial)element;
            var gaussPoints          = CreateElementGaussPoints(shellElement);
            var ElementNodalForces   = new double[shellElement.ControlPointsDictionary.Count * 3];
            var tsplines             = new ShapeTSplines2DFromBezierExtraction(shellElement, shellElement.ControlPoints.ToArray());
            var elementControlPoints = shellElement.ControlPoints.ToArray();

            for (var j = 0; j < gaussPoints.Count; j++)
            {
                var jacobianMatrix = CalculateJacobian(elementControlPoints, tsplines, j);

                var hessianMatrix = CalculateHessian(elementControlPoints, tsplines, j);

                var surfaceBasisVector1 = CalculateSurfaceBasisVector1(jacobianMatrix, 0);

                var surfaceBasisVector2 = CalculateSurfaceBasisVector1(jacobianMatrix, 1);

                var surfaceBasisVector3 = new[]
                {
                    surfaceBasisVector1[1] * surfaceBasisVector2[2] - surfaceBasisVector1[2] * surfaceBasisVector2[1],
                    surfaceBasisVector1[2] * surfaceBasisVector2[0] - surfaceBasisVector1[0] * surfaceBasisVector2[2],
                    surfaceBasisVector1[0] * surfaceBasisVector2[1] - surfaceBasisVector1[1] * surfaceBasisVector2[0]
                };

                var norm = surfaceBasisVector3.Sum(t => t * t);
                var J1   = Math.Sqrt(norm);

                for (int i = 0; i < surfaceBasisVector3.Length; i++)
                {
                    surfaceBasisVector3[i] = surfaceBasisVector3[i] / J1;
                }

                var surfaceBasisVectorDerivative1  = CalculateSurfaceBasisVector1(hessianMatrix, 0);
                var surfaceBasisVectorDerivative2  = CalculateSurfaceBasisVector1(hessianMatrix, 1);
                var surfaceBasisVectorDerivative12 = CalculateSurfaceBasisVector1(hessianMatrix, 2);

                var Bmembrane = CalculateMembraneDeformationMatrix(tsplines, j, surfaceBasisVector1,
                                                                   surfaceBasisVector2, elementControlPoints);
                var Bbending = CalculateBendingDeformationMatrix(surfaceBasisVector3, tsplines, j, surfaceBasisVector2,
                                                                 surfaceBasisVectorDerivative1, surfaceBasisVector1, J1, surfaceBasisVectorDerivative2,
                                                                 surfaceBasisVectorDerivative12, elementControlPoints);

                var(MembraneForces, BendingMoments) =
                    IntegratedStressesOverThickness(gaussPoints, j);

                var wfactor = J1 * gaussPoints[j].WeightFactor;
                for (var i = 0; i < Bmembrane.GetLength(1); i++)
                {
                    for (var k = 0; k < Bmembrane.GetLength(0); k++)
                    {
                        ElementNodalForces[i] += Bmembrane[k, i] * MembraneForces[k] * wfactor +
                                                 Bbending[k, i] * BendingMoments[k] * wfactor;
                    }
                }
            }

            return(ElementNodalForces);
        }
        /// <summary>
        /// Calculates the stiffness matrix of the element.
        /// </summary>
        /// <param name="element">An element of type <see cref="TSplineKirchhoffLoveShellElement"/>.</param>
        /// <returns>An <see cref="IMatrix"/> containing the stiffness matrix of an <see cref="TSplineKirchhoffLoveShellElement"/>.</returns>
        public IMatrix StiffnessMatrix(IElement element)
        {
            var shellElement           = (TSplineKirchhoffLoveShellElement)element;
            var gaussPoints            = CreateElementGaussPoints(shellElement);
            var stiffnessMatrixElement = Matrix.CreateZero(shellElement.ControlPointsDictionary.Count * 3,
                                                           shellElement.ControlPointsDictionary.Count * 3);
            var elementControlPoints = shellElement.ControlPoints.ToArray();
            var tsplines             = new ShapeTSplines2DFromBezierExtraction(shellElement, elementControlPoints);

            for (var j = 0; j < gaussPoints.Count; j++)
            {
                var jacobianMatrix = CalculateJacobian(elementControlPoints, tsplines, j);

                var hessianMatrix = CalculateHessian(elementControlPoints, tsplines, j);

                var surfaceBasisVector1 = CalculateSurfaceBasisVector1(jacobianMatrix, 0);

                var surfaceBasisVector2 = CalculateSurfaceBasisVector1(jacobianMatrix, 1);

                var surfaceBasisVector3 = surfaceBasisVector1.CrossProduct(surfaceBasisVector2);
                var J1 = surfaceBasisVector3.Norm2();
                surfaceBasisVector3.ScaleIntoThis(1 / J1);

                var surfaceBasisVectorDerivative1  = CalculateSurfaceBasisVector1(hessianMatrix, 0);
                var surfaceBasisVectorDerivative2  = CalculateSurfaceBasisVector1(hessianMatrix, 1);
                var surfaceBasisVectorDerivative12 = CalculateSurfaceBasisVector1(hessianMatrix, 2);

                var constitutiveMatrix = CalculateConstitutiveMatrix(shellElement, surfaceBasisVector1, surfaceBasisVector2);

                var Bmembrane = CalculateMembraneDeformationMatrix(tsplines, j, surfaceBasisVector1,
                                                                   surfaceBasisVector2, elementControlPoints);

                var Bbending = CalculateBendingDeformationMatrix(surfaceBasisVector3, tsplines, j, surfaceBasisVector2,
                                                                 surfaceBasisVectorDerivative1, surfaceBasisVector1, J1, surfaceBasisVectorDerivative2,
                                                                 surfaceBasisVectorDerivative12, elementControlPoints);

                var membraneStiffness = ((IIsotropicContinuumMaterial2D)shellElement.Patch.Material).YoungModulus * shellElement.Patch.Thickness /
                                        (1 - Math.Pow(((IIsotropicContinuumMaterial2D)shellElement.Patch.Material).PoissonRatio, 2));

                var Kmembrane = Bmembrane.Transpose() * constitutiveMatrix * Bmembrane * membraneStiffness * J1 *
                                gaussPoints[j].WeightFactor;

                var bendingStiffness = ((IIsotropicContinuumMaterial2D)shellElement.Patch.Material).YoungModulus * Math.Pow(shellElement.Patch.Thickness, 3) /
                                       12 / (1 - Math.Pow(((IIsotropicContinuumMaterial2D)shellElement.Patch.Material).PoissonRatio, 2));

                var Kbending = Bbending.Transpose() * constitutiveMatrix * Bbending * bendingStiffness * J1 *
                               gaussPoints[j].WeightFactor;

                stiffnessMatrixElement.AddIntoThis(Kmembrane);
                stiffnessMatrixElement.AddIntoThis(Kbending);
            }
            return(stiffnessMatrixElement);
        }
        private static Matrix CalculateJacobian(ControlPoint[] elementControlPoints, ShapeTSplines2DFromBezierExtraction tsplines, int j)
        {
            var jacobianMatrix = Matrix.CreateZero(2, 3);

            for (var k = 0; k < elementControlPoints.Length; k++)
            {
                jacobianMatrix[0, 0] += tsplines.TSplineDerivativeValuesKsi[k, j] * elementControlPoints[k].X;
                jacobianMatrix[0, 1] += tsplines.TSplineDerivativeValuesKsi[k, j] * elementControlPoints[k].Y;
                jacobianMatrix[0, 2] += tsplines.TSplineDerivativeValuesKsi[k, j] * elementControlPoints[k].Z;
                jacobianMatrix[1, 0] += tsplines.TSplineDerivativeValuesHeta[k, j] * elementControlPoints[k].X;
                jacobianMatrix[1, 1] += tsplines.TSplineDerivativeValuesHeta[k, j] * elementControlPoints[k].Y;
                jacobianMatrix[1, 2] += tsplines.TSplineDerivativeValuesHeta[k, j] * elementControlPoints[k].Z;
            }

            return(jacobianMatrix);
        }
        private static Matrix CalculateHessian(ControlPoint[] elementControlPoints, ShapeTSplines2DFromBezierExtraction tsplines, int j)
        {
            Matrix hessianMatrix = Matrix.CreateZero(3, 3);

            for (int k = 0; k < elementControlPoints.Length; k++)
            {
                hessianMatrix[0, 0] += tsplines.TSplineSecondDerivativesValueKsi[k, j] * elementControlPoints[k].X;
                hessianMatrix[0, 1] += tsplines.TSplineSecondDerivativesValueKsi[k, j] * elementControlPoints[k].Y;
                hessianMatrix[0, 2] += tsplines.TSplineSecondDerivativesValueKsi[k, j] * elementControlPoints[k].Z;
                hessianMatrix[1, 0] += tsplines.TSplineSecondDerivativesValueHeta[k, j] * elementControlPoints[k].X;
                hessianMatrix[1, 1] += tsplines.TSplineSecondDerivativesValueHeta[k, j] * elementControlPoints[k].Y;
                hessianMatrix[1, 2] += tsplines.TSplineSecondDerivativesValueHeta[k, j] * elementControlPoints[k].Z;
                hessianMatrix[2, 0] += tsplines.TSplineSecondDerivativesValueKsiHeta[k, j] * elementControlPoints[k].X;
                hessianMatrix[2, 1] += tsplines.TSplineSecondDerivativesValueKsiHeta[k, j] * elementControlPoints[k].Y;
                hessianMatrix[2, 2] += tsplines.TSplineSecondDerivativesValueKsiHeta[k, j] * elementControlPoints[k].Z;
            }

            return(hessianMatrix);
        }
        private double[,] CalculateBendingDeformationMatrix(double[] surfaceBasisVector3, ShapeTSplines2DFromBezierExtraction tsplines, int j,
                                                            double[] surfaceBasisVector2, double[] surfaceBasisVectorDerivative1, double[] surfaceBasisVector1, double J1,
                                                            double[] surfaceBasisVectorDerivative2, double[] surfaceBasisVectorDerivative12, ControlPoint[] elementControlPoints)
        {
            var Bbending = new double[3, elementControlPoints.Length * 3];
            var s1       = Vector.CreateFromArray(surfaceBasisVector1);
            var s2       = Vector.CreateFromArray(surfaceBasisVector2);
            var s3       = Vector.CreateFromArray(surfaceBasisVector3);
            var s11      = Vector.CreateFromArray(surfaceBasisVectorDerivative1);
            var s22      = Vector.CreateFromArray(surfaceBasisVectorDerivative2);
            var s12      = Vector.CreateFromArray(surfaceBasisVectorDerivative12);

            for (int column = 0; column < elementControlPoints.Length * 3; column += 3)
            {
                #region BI1

                var BI1 = s3.CrossProduct(s3);
                BI1.ScaleIntoThis(tsplines.TSplineDerivativeValuesHeta[column / 3, j]);
                var auxVector = s2.CrossProduct(s3);
                auxVector.ScaleIntoThis(tsplines.TSplineDerivativeValuesKsi[column / 3, j]);
                BI1.AddIntoThis(auxVector);
                BI1.ScaleIntoThis(s3.DotProduct(s11));
                auxVector = s1.CrossProduct(s11);
                auxVector.ScaleIntoThis(tsplines.TSplineDerivativeValuesHeta[column / 3, j]);
                BI1.AddIntoThis(auxVector);
                BI1.ScaleIntoThis(1 / J1);
                auxVector[0] = surfaceBasisVector3[0];
                auxVector[1] = surfaceBasisVector3[1];
                auxVector[2] = surfaceBasisVector3[2];
                auxVector.ScaleIntoThis(-tsplines.TSplineSecondDerivativesValueKsi[column / 3, j]);
                BI1.AddIntoThis(auxVector);

                #endregion BI1

                #region BI2

                IVector BI2 = s3.CrossProduct(s3);
                BI2.ScaleIntoThis(tsplines.TSplineDerivativeValuesHeta[column / 3, j]);
                auxVector = s2.CrossProduct(s3);
                auxVector.ScaleIntoThis(tsplines.TSplineDerivativeValuesKsi[column / 3, j]);
                BI2.AddIntoThis(auxVector);
                BI2.ScaleIntoThis(s3.DotProduct(s22));
                auxVector = s1.CrossProduct(s22);
                auxVector.ScaleIntoThis(tsplines.TSplineDerivativeValuesHeta[column / 3, j]);
                BI2.AddIntoThis(auxVector);
                auxVector = s22.CrossProduct(s2);
                auxVector.ScaleIntoThis(tsplines.TSplineDerivativeValuesKsi[column / 3, j]);
                BI2.AddIntoThis(auxVector);
                BI2.ScaleIntoThis(1 / J1);
                auxVector[0] = surfaceBasisVector3[0];
                auxVector[1] = surfaceBasisVector3[1];
                auxVector[2] = surfaceBasisVector3[2];
                auxVector.ScaleIntoThis(-tsplines.TSplineSecondDerivativesValueHeta[column / 3, j]);
                BI2.AddIntoThis(auxVector);

                #endregion BI2

                #region BI3

                Vector BI3 = s3.CrossProduct(s3);
                BI3.ScaleIntoThis(tsplines.TSplineDerivativeValuesHeta[column / 3, j]);
                auxVector = s2.CrossProduct(s3);
                auxVector.ScaleIntoThis(tsplines.TSplineDerivativeValuesKsi[column / 3, j]);
                BI3.AddIntoThis(auxVector);
                BI3.ScaleIntoThis(s3.DotProduct(s12));
                auxVector = s1.CrossProduct(s12);
                auxVector.ScaleIntoThis(tsplines.TSplineDerivativeValuesHeta[column / 3, j]);
                BI3.AddIntoThis(auxVector);
                auxVector = s22.CrossProduct(s2);
                auxVector.ScaleIntoThis(tsplines.TSplineDerivativeValuesKsi[column / 3, j]);
                BI3.AddIntoThis(auxVector);
                BI3.ScaleIntoThis(1 / J1);
                auxVector[0] = surfaceBasisVector3[0];
                auxVector[1] = surfaceBasisVector3[1];
                auxVector[2] = surfaceBasisVector3[2];
                auxVector.ScaleIntoThis(-tsplines.TSplineSecondDerivativesValueKsiHeta[column / 3, j]);
                BI3.AddIntoThis(auxVector);

                #endregion BI3

                Bbending[0, column]     = BI1[0];
                Bbending[0, column + 1] = BI1[1];
                Bbending[0, column + 2] = BI1[2];

                Bbending[1, column]     = BI2[0];
                Bbending[1, column + 1] = BI2[1];
                Bbending[1, column + 2] = BI2[2];

                Bbending[2, column]     = 2 * BI3[0];
                Bbending[2, column + 1] = 2 * BI3[1];
                Bbending[2, column + 2] = 2 * BI3[2];
            }

            return(Bbending);
        }
        /// <summary>
        /// Calculates the stiffness matrix of the element.
        /// </summary>
        /// <param name="element">An element of type <see cref="TSplineKirchhoffLoveShellElementMaterial"/>.</param>
        /// <returns>An <see cref="IMatrix"/> containing the stiffness matrix of an <see cref="TSplineKirchhoffLoveShellElementMaterial"/>.</returns>
        public IMatrix StiffnessMatrix(IElement element)
        {
            var shellElement         = (TSplineKirchhoffLoveShellElementMaterial)element;
            var gaussPoints          = _materialsAtThicknessGp.Keys.ToArray();
            var elementControlPoints = shellElement.ControlPoints.ToArray();
            ShapeTSplines2DFromBezierExtraction tsplines =
                new ShapeTSplines2DFromBezierExtraction(shellElement, elementControlPoints);

            var bRows           = 3;
            var bCols           = elementControlPoints.Length * 3;
            var stiffnessMatrix = new double[bCols, bCols];
            var BmTranspose     = new double[bCols, bRows];
            var BbTranspose     = new double[bCols, bRows];

            var BmTransposeMultStiffness  = new double[bCols, bRows];
            var BbTransposeMultStiffness  = new double[bCols, bRows];
            var BmbTransposeMultStiffness = new double[bCols, bRows];
            var BbmTransposeMultStiffness = new double[bCols, bRows];

            for (int j = 0; j < gaussPoints.Length; j++)
            {
                var jacobianMatrix = CalculateJacobian(elementControlPoints, tsplines, j);

                var hessianMatrix       = CalculateHessian(elementControlPoints, tsplines, j);
                var surfaceBasisVector1 = CalculateSurfaceBasisVector1(jacobianMatrix, 0);

                var surfaceBasisVector2 = CalculateSurfaceBasisVector1(jacobianMatrix, 1);

                var surfaceBasisVector3 = new[]
                {
                    surfaceBasisVector1[1] * surfaceBasisVector2[2] - surfaceBasisVector1[2] * surfaceBasisVector2[1],
                    surfaceBasisVector1[2] * surfaceBasisVector2[0] - surfaceBasisVector1[0] * surfaceBasisVector2[2],
                    surfaceBasisVector1[0] * surfaceBasisVector2[1] - surfaceBasisVector1[1] * surfaceBasisVector2[0]
                };

                foreach (var integrationPointMaterial in _materialsAtThicknessGp[gaussPoints[j]].Values)
                {
                    integrationPointMaterial.TangentVectorV1 = surfaceBasisVector1;
                    integrationPointMaterial.TangentVectorV2 = surfaceBasisVector2;
                    integrationPointMaterial.NormalVectorV3  = surfaceBasisVector3;
                }

                double norm = 0;
                for (int i = 0; i < surfaceBasisVector3.Length; i++)
                {
                    norm += surfaceBasisVector3[i] * surfaceBasisVector3[i];
                }
                var J1 = Math.Sqrt(norm);

                for (int i = 0; i < surfaceBasisVector3.Length; i++)
                {
                    surfaceBasisVector3[i] = surfaceBasisVector3[i] / J1;
                }

                var surfaceBasisVectorDerivative1  = CalculateSurfaceBasisVector1(hessianMatrix, 0);
                var surfaceBasisVectorDerivative2  = CalculateSurfaceBasisVector1(hessianMatrix, 1);
                var surfaceBasisVectorDerivative12 = CalculateSurfaceBasisVector1(hessianMatrix, 2);

                var Bmembrane = CalculateMembraneDeformationMatrix(tsplines, j, surfaceBasisVector1,
                                                                   surfaceBasisVector2, elementControlPoints);
                var Bbending = CalculateBendingDeformationMatrix(surfaceBasisVector3, tsplines, j, surfaceBasisVector2,
                                                                 surfaceBasisVectorDerivative1, surfaceBasisVector1, J1, surfaceBasisVectorDerivative2,
                                                                 surfaceBasisVectorDerivative12, elementControlPoints);

                var(MembraneConstitutiveMatrix, BendingConstitutiveMatrix, CouplingConstitutiveMatrix) =
                    IntegratedConstitutiveOverThickness(gaussPoints, j);

                double wFactor = J1 * gaussPoints[j].WeightFactor;
                double tempb   = 0;
                double tempm   = 0;
                Array.Clear(BmTranspose, 0, bRows * bCols);
                Array.Clear(BbTranspose, 0, bRows * bCols);
                for (int i = 0; i < bRows; i++)
                {
                    for (int k = 0; k < bCols; k++)
                    {
                        BmTranspose[k, i] = Bmembrane[i, k] * wFactor;
                        BbTranspose[k, i] = Bbending[i, k] * wFactor;
                    }
                }

                double tempcm = 0;
                double tempcb = 0;
                double tempcc = 0;
                Array.Clear(BmTransposeMultStiffness, 0, bRows * bCols);
                Array.Clear(BbTransposeMultStiffness, 0, bRows * bCols);
                Array.Clear(BmbTransposeMultStiffness, 0, bRows * bCols);
                Array.Clear(BbmTransposeMultStiffness, 0, bRows * bCols);
                for (int i = 0; i < bCols; i++)
                {
                    for (int k = 0; k < bRows; k++)
                    {
                        tempm = BmTranspose[i, k];
                        tempb = BbTranspose[i, k];
                        for (int m = 0; m < bRows; m++)
                        {
                            tempcm = MembraneConstitutiveMatrix[k, m];
                            tempcb = BendingConstitutiveMatrix[k, m];
                            tempcc = CouplingConstitutiveMatrix[k, m];

                            BmTransposeMultStiffness[i, m]  += tempm * tempcm;
                            BbTransposeMultStiffness[i, m]  += tempb * tempcb;
                            BmbTransposeMultStiffness[i, m] += tempm * tempcc;
                            BbmTransposeMultStiffness[i, m] += tempb * tempcc;
                        }
                    }
                }

                double tempmb = 0;
                double tempbm = 0;
                double mem    = 0;
                double ben    = 0;
                for (int i = 0; i < bCols; i++)
                {
                    for (int k = 0; k < bRows; k++)
                    {
                        tempm  = BmTransposeMultStiffness[i, k];
                        tempb  = BbTransposeMultStiffness[i, k];
                        tempmb = BmbTransposeMultStiffness[i, k];
                        tempbm = BbmTransposeMultStiffness[i, k];

                        for (int m = 0; m < bCols; m++)
                        {
                            mem = Bmembrane[k, m];
                            ben = Bbending[k, m];
                            stiffnessMatrix[i, m] += tempm * mem + tempb * ben + tempmb * ben + tempbm * mem;
                        }
                    }
                }
            }
            return(Matrix.CreateFromArray(stiffnessMatrix));
        }
        /// <summary>
        /// This method calculates the stresses of the element.
        /// </summary>
        /// <param name="element">An element of type <see cref="TSplineKirchhoffLoveShellElementMaterial"/></param>
        /// <param name="localDisplacements">A <see cref="double"/> array containing the displacements for the degrees of freedom of the element.</param>
        /// <param name="localdDisplacements">A <see cref="double"/> array containing the displacements change for the degrees of freedom of the element.</param>
        /// <returns>A <see cref="Tuple{T1,T2}"/> of the stresses and strains of the element.</returns>
        public Tuple <double[], double[]> CalculateStresses(IElement element, double[] localDisplacements, double[] localdDisplacements)
        {
            var shellElement         = (TSplineKirchhoffLoveShellElementMaterial)element;
            var elementControlPoints = shellElement.ControlPoints.ToArray();
            var tsplines             = new ShapeTSplines2DFromBezierExtraction(shellElement, shellElement.ControlPoints.ToArray());

            for (var j = 0; j < _materialsAtThicknessGp.Keys.Count; j++)
            {
                var jacobianMatrix = CalculateJacobian(elementControlPoints, tsplines, j);

                var hessianMatrix = CalculateHessian(elementControlPoints, tsplines, j);

                var surfaceBasisVector1 = CalculateSurfaceBasisVector1(jacobianMatrix, 0);

                var surfaceBasisVector2 = CalculateSurfaceBasisVector1(jacobianMatrix, 1);

                var surfaceBasisVector3 = new[]
                {
                    surfaceBasisVector1[1] * surfaceBasisVector2[2] - surfaceBasisVector1[2] * surfaceBasisVector2[1],
                    surfaceBasisVector1[2] * surfaceBasisVector2[0] - surfaceBasisVector1[0] * surfaceBasisVector2[2],
                    surfaceBasisVector1[0] * surfaceBasisVector2[1] - surfaceBasisVector1[1] * surfaceBasisVector2[0]
                };

                var norm = surfaceBasisVector3.Sum(t => t * t);

                var J1 = Math.Sqrt(norm);

                var surfaceBasisVectorDerivative1  = CalculateSurfaceBasisVector1(hessianMatrix, 0);
                var surfaceBasisVectorDerivative2  = CalculateSurfaceBasisVector1(hessianMatrix, 1);
                var surfaceBasisVectorDerivative12 = CalculateSurfaceBasisVector1(hessianMatrix, 2);

                var Bmembrane = CalculateMembraneDeformationMatrix(tsplines, j, surfaceBasisVector1, surfaceBasisVector2, elementControlPoints);
                var Bbending  = CalculateBendingDeformationMatrix(surfaceBasisVector3, tsplines, j, surfaceBasisVector2,
                                                                  surfaceBasisVectorDerivative1, surfaceBasisVector1, J1, surfaceBasisVectorDerivative2,
                                                                  surfaceBasisVectorDerivative12, elementControlPoints);

                var membraneStrain = new double[Bmembrane.GetLength(0)];
                var bendingStrain  = new double[Bmembrane.GetLength(0)];
                for (var i = 0; i < Bmembrane.GetLength(1); i++)
                {
                    for (var k = 0; k < Bmembrane.GetLength(0); k++)
                    {
                        membraneStrain[i] += Bmembrane[k, i] * localDisplacements[k];
                        bendingStrain[i]  += Bbending[k, i] * localDisplacements[k];
                    }
                }

                foreach (var keyValuePair in _materialsAtThicknessGp[_materialsAtThicknessGp.Keys.ToList()[j]])
                {
                    var thicknessPoint = keyValuePair.Key;
                    var material       = keyValuePair.Value;
                    var gpStrain       = new double[bendingStrain.Length];
                    var z = -thicknessPoint.Zeta;
                    for (var i = 0; i < bendingStrain.Length; i++)
                    {
                        gpStrain[i] += membraneStrain[i] + bendingStrain[i] * z;
                    }
                    material.UpdateMaterial(gpStrain);
                }
            }
            return(new Tuple <double[], double[]>(new double[0], new double[0]));
        }