Exemplo n.º 1
0
        // Stiffness ratio = 1E-6
        //[InlineData(1E-6, InterfaceSolver.Method1, Precond.Dirichlet, MatrixQ.Identity, Residual.Exact, 40)] // converges, stagnates almost before the tolerance and then diverges
        //[InlineData(1E-6, InterfaceSolver.Method2, Precond.Dirichlet, MatrixQ.Precond, Residual.Exact, 9)] // converges, stagnates almost before the tolerance and then diverges
        //[InlineData(1E-6, InterfaceSolver.Method3, Precond.Dirichlet, MatrixQ.Precond, Residual.Exact, 23)] //3
        //[InlineData(1E-6, InterfaceSolver.Method4, Precond.Dirichlet, MatrixQ.Precond, Residual.Exact, 9)] // converges, stagnates almost before the tolerance and then diverges
        //[InlineData(1E-6, InterfaceSolver.Default, Precond.Dirichlet, MatrixQ.Precond, Residual.Approximate, 9)]
        public static void Run(double stiffnessRatio, InterfaceSolver interfaceSolver, Precond precond, MatrixQ q,
                               Residual convergence, int iterExpected)
        {
            //InterfaceSolver interfaceSolver = 0;
            double      factorizationTol = 1E-3, pcpgConvergenceTol = 1E-5;
            IVectorView directDisplacements = SolveModelWithoutSubdomains(stiffnessRatio);

            (IVectorView ddDisplacements, SolverLogger logger, int numUniqueGlobalDofs, int numExtenedDomainDofs) =
                SolveModelWithSubdomains(stiffnessRatio, interfaceSolver, precond, q, convergence,
                                         factorizationTol, pcpgConvergenceTol);
            double normalizedError = directDisplacements.Subtract(ddDisplacements).Norm2() / directDisplacements.Norm2();

            int analysisStep = 0;

            Assert.Equal(882, numUniqueGlobalDofs);               // 882 includes constrained and free dofs
            Assert.Equal(1056, numExtenedDomainDofs);             // 1056 includes constrained and free dofs
            Assert.Equal(190, logger.GetNumDofs(analysisStep, "Lagrange multipliers"));

            // The error is provided in the reference solution the, but it is almost impossible for two different codes run on
            // different machines to achieve the exact same accuracy.
            Assert.Equal(0.0, normalizedError, 5);

            // Allow a tolerance: It is ok if my solver is better or off by 1 iteration
            int pcgIterations = logger.GetNumIterationsOfIterativeAlgorithm(analysisStep);

            Assert.InRange(pcgIterations, 1, iterExpected + 1);             // the upper bound is inclusive!
        }
Exemplo n.º 2
0
 public void Read(BitReader bitReader)
 {
     if (_bEntropyCodingModeFlag)
     ResidualBlock = ResidualBlockCABAC;
       else
     ResidualBlock = ResidualBlockCAVLC;
 }
Exemplo n.º 3
0
        public static ItemRoot SageStockItemToMTItem(SageStockItem sagestockitem)
        {
            ItemRoot itemroot = new ItemRoot();
            Item     item     = new Item();

            item.id     = "";
            item.active = sagestockitem.StockItemStatus == Sage.Accounting.Stock.StockItemStatusEnum.EnumStockItemStatusTypeActive ? true : false;

            item.externalId = sagestockitem.PrimaryKey.DbValue.ToString();
            item.name       = sagestockitem.Name;
            item.type       = "INVENTORY";       // ???

            Cost cost = new Cost()
            {
                amount    = PriceConverter.FromDecimal(sagestockitem.PriceBands[0].StockItemPrices[0].Price, 2),
                precision = 2
            };

            item.cost = cost;

            Residual residual = new Residual()
            {
                amount = 0                 // ???
            };

            item.residual = residual;

            itemroot.item = item;
            return(itemroot);
        }
Exemplo n.º 4
0
        override public void SolverDriver <S>(CoordinateVector SolutionVec, S RHS)
        {
            // initial guess and its residual
            // ==============================
            double[] Solution, Residual;
            base.Init(SolutionVec, RHS, out Solution, out Residual);
            double[] Correction     = new double[Solution.Length];
            double   ResidualNorm   = Residual.L2NormPow2().MPISum().Sqrt();
            int      NoOfIterations = 0;

            if (m_LinearSolver.GetType() == typeof(SoftGMRES))
            {
                ((SoftGMRES)m_LinearSolver).m_SessionPath = m_SessionPath;
            }

            OnIterationCallback(NoOfIterations, Solution.CloneAs(), Residual.CloneAs(), this.CurrentLin);

            if (LastIteration_Converged == null)
            {
                LastIteration_Converged = delegate(double ResNorm) {
                    return(ResNorm < ConvCrit);
                }
            }
            ;

            // iterate...
            // ==========
            while ((!LastIteration_Converged(ResidualNorm) && NoOfIterations < MaxIter) || (NoOfIterations < MinIter))
            {
                NoOfIterations++;

                //DirectSolver ds = new DirectSolver();
                //ds.Init(this.CurrentLin);
                //double L2_Res = Residual.L2Norm();
                this.m_LinearSolver.Init(this.CurrentLin);
                Correction.ClearEntries();
                if (Correction.Length != Residual.Length)
                {
                    Correction = new double[Residual.Length];
                }
                this.m_LinearSolver.Solve(Correction, Residual);

                // Residual may be invalid from now on...
                Solution.AccV(UnderRelax, Correction);

                // transform solution back to 'original domain'
                // to perform the linearization at the new point...
                // (and for Level-Set-Updates ...)
                this.CurrentLin.TransformSolFrom(SolutionVec, Solution);

                // update linearization
                base.Update(SolutionVec.Mapping.Fields, ref Solution);

                // residual evaluation & callback
                base.EvalResidual(Solution, ref Residual);
                ResidualNorm = Residual.L2NormPow2().MPISum().Sqrt();
                OnIterationCallback(NoOfIterations, Solution.CloneAs(), Residual.CloneAs(), this.CurrentLin);
            }
        }
    }
Exemplo n.º 5
0
 public void Read(BitReader bitReader)
 {
     if (_bEntropyCodingModeFlag)
     {
         ResidualBlock = ResidualBlockCABAC;
     }
     else
     {
         ResidualBlock = ResidualBlockCAVLC;
     }
 }
Exemplo n.º 6
0
        public void test_SumOfSquaredResiduals()
        {
            /*Calculated with R, result is 0.19753.*/
            List <double> y = new List <double>()
            {
                1, 2.2, 3.1, 2.5
            };
            List <double> x1 = new List <double>()
            {
                177, 175, 183, 167
            };
            List <double> x2 = new List <double>()
            {
                3, 5, 6, 9
            };
            List <List <double> > x = new List <List <double> >()
            {
                x1, x2
            };

            Assert.AreEqual(0.19753, Math.Round(Residual.SumOfSquaredResiduals(y, x), 5));
        }
Exemplo n.º 7
0
            public static Func <double, double, double> ChooseLossFunction(Residual lf)
            {
                switch (lf)
                {
                case (Residual.MAE):
                    return(LossFunctions.MeanAbsoluteError);

                case (Residual.MSE):
                    return(LossFunctions.MeanSquareError);

                case (Residual.RMSE):
                    return(LossFunctions.RootMeanSquareError);

                case (Residual.Hinge):
                    return(LossFunctions.HingeError);

                case (Residual.CrossEntropy):
                    return(LossFunctions.CrossEntropyError);

                default:
                    return(LossFunctions.MeanSquareError);
                }
            }
        public static void Run(double stiffnessRatio, Precond precond, Residual convergence, int iterExpected)
        {
            double      pcgConvergenceTol   = 1E-5;
            IVectorView directDisplacements = SolveModelWithoutSubdomains(stiffnessRatio);

            (IVectorView ddDisplacements, SolverLogger logger) =
                SolveModelWithSubdomains(stiffnessRatio, precond, convergence, pcgConvergenceTol);
            double normalizedError = directDisplacements.Subtract(ddDisplacements).Norm2() / directDisplacements.Norm2();

            int analysisStep = 0;

            Assert.Equal(140, logger.GetNumDofs(analysisStep, "Lagrange multipliers"));
            Assert.Equal(20, logger.GetNumDofs(analysisStep, "Corner dofs"));

            // The error is provided in the reference solution the, but it is almost impossible for two different codes run on
            // different machines to achieve the exact same accuracy.
            Assert.Equal(0.0, normalizedError, 6);

            // Allow some tolerance for the iterations:
            int maxIterationsForApproximateResidual = (int)Math.Ceiling(1.0 * iterExpected);
            int pcgIterations = logger.GetNumIterationsOfIterativeAlgorithm(analysisStep);

            Assert.InRange(pcgIterations, 1, maxIterationsForApproximateResidual); // the upper bound is inclusive!
        }
Exemplo n.º 9
0
        //bool solveVelocity = true;

        //double VelocitySolver_ConvergenceCriterion = 1e-5;

        //double StressSolver_ConvergenceCriterion = 1e-5;


        override public void SolverDriver <S>(CoordinateVector SolutionVec, S RHS)
        {
            using (var tr = new FuncTrace()) {
                // initial guess and its residual
                // ==============================
                double[] Solution, Residual;

                using (new BlockTrace("Slv Init", tr)) {
                    base.Init(SolutionVec, RHS, out Solution, out Residual);
                }
                double[] Correction     = new double[Solution.Length];
                double   ResidualNorm   = Residual.L2NormPow2().MPISum().Sqrt();
                int      NoOfIterations = 0;
                if (m_LinearSolver.GetType() == typeof(SoftGMRES))
                {
                    ((SoftGMRES)m_LinearSolver).m_SessionPath = m_SessionPath;
                }

                OnIterationCallback(NoOfIterations, Solution.CloneAs(), Residual.CloneAs(), this.CurrentLin);

                if (CoupledIteration_Converged == null)
                {
                    CoupledIteration_Converged = delegate() {
                        return(true);
                    }
                }
                ;

                int NoOfCoupledIteration = 0;
                if (Iteration_Count == null)
                {
                    Iteration_Count = delegate(int NoIter, ref int coupledIter) {
                        return(NoIter + 1);
                    }
                }
                ;

                //int[] Velocity_idx = SolutionVec.Mapping.GetSubvectorIndices(false, 0, 1, 2);
                //int[] Stresses_idx = SolutionVec.Mapping.GetSubvectorIndices(false, 3, 4, 5);

                //int[] Velocity_fields = new int[] { 0, 1, 2 };
                //int[] Stress_fields = new int[] { 3, 4, 5 };

                //int NoCoupledIterations = 10;

                // iterate...
                // ==========
                //int NoOfMainIterations = 0;
                using (new BlockTrace("Slv Iter", tr)) {
                    while ((!(ResidualNorm < ConvCrit && CoupledIteration_Converged()) && NoOfIterations < MaxIter && NoOfCoupledIteration < MaxCoupledIter) || (NoOfIterations < MinIter))
                    {
                        NoOfIterations = Iteration_Count(NoOfIterations, ref NoOfCoupledIteration);
                        //Console.WriteLine("NoOfIterations = {0}", NoOfIterations);

                        //DirectSolver ds = new DirectSolver();
                        //ds.Init(this.CurrentLin);
                        //double L2_Res = Residual.L2Norm();
                        this.m_LinearSolver.Init(this.CurrentLin);
                        Correction.ClearEntries();
                        if (Correction.Length != Residual.Length)
                        {
                            Correction = new double[Residual.Length];
                        }
                        this.m_LinearSolver.Solve(Correction, Residual);

                        //if (NoOfIterations > NoCoupledIterations)
                        //{
                        //    if (solveVelocity)
                        //    {
                        //        Console.WriteLine("stress correction = 0");
                        //        foreach (int idx in Stresses_idx)
                        //        {
                        //            Correction[idx] = 0.0;
                        //        }
                        //    }
                        //    else
                        //    {
                        //        Console.WriteLine("velocity correction = 0");
                        //        foreach (int idx in Velocity_idx)
                        //        {
                        //            Correction[idx] = 0.0;
                        //        }
                        //    }
                        //}

                        // Residual may be invalid from now on...
                        Solution.AccV(UnderRelax, Correction);

                        // transform solution back to 'original domain'
                        // to perform the linearization at the new point...
                        // (and for Level-Set-Updates ...)
                        this.CurrentLin.TransformSolFrom(SolutionVec, Solution);

                        // update linearization
                        base.Update(SolutionVec.Mapping.Fields, ref Solution);

                        // residual evaluation & callback
                        base.EvalResidual(Solution, ref Residual);
                        ResidualNorm = Residual.L2NormPow2().MPISum().Sqrt();

                        //if (NoOfIterations > NoCoupledIterations)
                        //{

                        //    double coupledL2Res = 0.0;
                        //    if (solveVelocity)
                        //    {
                        //        foreach (int idx in Velocity_idx)
                        //        {
                        //            coupledL2Res += Residual[idx].Pow2();
                        //        }
                        //    }
                        //    else
                        //    {
                        //        foreach (int idx in Stresses_idx)
                        //        {
                        //            coupledL2Res += Residual[idx].Pow2();
                        //        }
                        //    }
                        //    coupledL2Res = coupledL2Res.Sqrt();

                        //    Console.WriteLine("coupled residual = {0}", coupledL2Res);

                        //    if (solveVelocity && coupledL2Res < this.VelocitySolver_ConvergenceCriterion)
                        //    {
                        //        Console.WriteLine("SolveVelocity = false");
                        //        this.solveVelocity = false;
                        //    }
                        //    else if (!solveVelocity && coupledL2Res < this.StressSolver_ConvergenceCriterion)
                        //    {
                        //        Console.WriteLine("SolveVelocity = true");
                        //        this.solveVelocity = true;
                        //    }
                        //}

                        OnIterationCallback(NoOfIterations, Solution.CloneAs(), Residual.CloneAs(), this.CurrentLin);
                    }
                }
            }
        }
    }
}
Exemplo n.º 10
0
        SolveModelWithSubdomains(double stiffnessRatio, InterfaceSolver interfaceSolver, Precond precond, MatrixQ q,
                                 Residual residualConvergence, double factorizationTolerance, double pcgConvergenceTolerance)
        {
            // Model
            Model multiSubdomainModel = CreateModel(stiffnessRatio);

            // Solver
            var factorizationTolerances = new Dictionary <int, double>();

            foreach (Subdomain s in multiSubdomainModel.Subdomains)
            {
                factorizationTolerances[s.ID] = factorizationTolerance;
            }
            //var fetiMatrices = new DenseFeti1SubdomainMatrixManager.Factory();
            //var fetiMatrices = new SkylineFeti1SubdomainMatrixManager.Factory();
            var fetiMatrices  = new SkylineFeti1SubdomainMatrixManager.Factory(new OrderingAmdCSparseNet());
            var solverBuilder = new Feti1Solver.Builder(fetiMatrices, factorizationTolerances);

            // Homogeneous/heterogeneous problem, matrix Q.
            solverBuilder.ProblemIsHomogeneous = stiffnessRatio == 1.0;
            if (q == MatrixQ.Identity)
            {
                solverBuilder.ProjectionMatrixQIsIdentity = true;
            }
            else
            {
                solverBuilder.ProjectionMatrixQIsIdentity = false;
            }

            // Preconditioner
            if (precond == Precond.Lumped)
            {
                solverBuilder.PreconditionerFactory = new LumpedPreconditioner.Factory();
            }
            else if (precond == Precond.DirichletDiagonal)
            {
                solverBuilder.PreconditionerFactory = new DiagonalDirichletPreconditioner.Factory();
            }
            else
            {
                solverBuilder.PreconditionerFactory = new DirichletPreconditioner.Factory();
            }

            // PCG may need to use the exact residual for the comparison with the expected values
            bool residualIsExact = residualConvergence == Residual.Exact;

            ExactFeti1PcgConvergence.Factory exactResidualConvergence = null;
            if (residualIsExact)
            {
                exactResidualConvergence = new ExactFeti1PcgConvergence.Factory(
                    CreateSingleSubdomainModel(stiffnessRatio), solverBuilder.DofOrderer,
                    (model, solver) => new ProblemStructural(model, solver));
            }

            // Lagrange separation method
            if (interfaceSolver == InterfaceSolver.Method1)
            {
                var interfaceProblemSolverBuilder = new Feti1UnprojectedInterfaceProblemSolver.Builder();
                interfaceProblemSolverBuilder.MaxIterationsProvider   = new FixedMaxIterationsProvider(maxIterations);
                interfaceProblemSolverBuilder.PcgConvergenceTolerance = pcgConvergenceTolerance;
                if (residualIsExact)
                {
                    interfaceProblemSolverBuilder.PcgConvergenceStrategyFactory = exactResidualConvergence;
                }
                Feti1UnprojectedInterfaceProblemSolver interfaceProblemSolver = interfaceProblemSolverBuilder.Build();
                solverBuilder.InterfaceProblemSolver = interfaceProblemSolver;
            }
            else
            {
                var interfaceProblemSolverBuilder = new Feti1ProjectedInterfaceProblemSolver.Builder();
                interfaceProblemSolverBuilder.MaxIterationsProvider   = new FixedMaxIterationsProvider(maxIterations);
                interfaceProblemSolverBuilder.PcgConvergenceTolerance = pcgConvergenceTolerance;
                if (residualIsExact)
                {
                    interfaceProblemSolverBuilder.PcgConvergenceStrategyFactory = exactResidualConvergence;
                }

                if (interfaceSolver == InterfaceSolver.Method2)
                {
                    interfaceProblemSolverBuilder.LagrangeSeparation           = Feti1ProjectedInterfaceProblemSolver.LagrangeMultiplierSeparation.Simple;
                    interfaceProblemSolverBuilder.ProjectionSideMatrix         = Feti1ProjectedInterfaceProblemSolver.ProjectionSide.Left;
                    interfaceProblemSolverBuilder.ProjectionSidePreconditioner = Feti1ProjectedInterfaceProblemSolver.ProjectionSide.Left;
                }
                else if (interfaceSolver == InterfaceSolver.Method3)
                {
                    interfaceProblemSolverBuilder.LagrangeSeparation           = Feti1ProjectedInterfaceProblemSolver.LagrangeMultiplierSeparation.WithProjection;
                    interfaceProblemSolverBuilder.ProjectionSideMatrix         = Feti1ProjectedInterfaceProblemSolver.ProjectionSide.Both;
                    interfaceProblemSolverBuilder.ProjectionSidePreconditioner = Feti1ProjectedInterfaceProblemSolver.ProjectionSide.None;
                }
                else if (interfaceSolver == InterfaceSolver.Method4)
                {
                    interfaceProblemSolverBuilder.LagrangeSeparation           = Feti1ProjectedInterfaceProblemSolver.LagrangeMultiplierSeparation.WithProjection;
                    interfaceProblemSolverBuilder.ProjectionSideMatrix         = Feti1ProjectedInterfaceProblemSolver.ProjectionSide.Both;
                    interfaceProblemSolverBuilder.ProjectionSidePreconditioner = Feti1ProjectedInterfaceProblemSolver.ProjectionSide.Left;
                }
                else                 // default
                {
                    interfaceProblemSolverBuilder.LagrangeSeparation           = Feti1ProjectedInterfaceProblemSolver.LagrangeMultiplierSeparation.WithProjection;
                    interfaceProblemSolverBuilder.ProjectionSideMatrix         = Feti1ProjectedInterfaceProblemSolver.ProjectionSide.Both;
                    interfaceProblemSolverBuilder.ProjectionSidePreconditioner = Feti1ProjectedInterfaceProblemSolver.ProjectionSide.Both;
                }

                Feti1ProjectedInterfaceProblemSolver interfaceProblemSolver = interfaceProblemSolverBuilder.Build();
                solverBuilder.InterfaceProblemSolver = interfaceProblemSolver;

                // Only needed in methods 2,3,4, default (where there is lagrange separation)
                if (residualIsExact)
                {
                    exactResidualConvergence.InterfaceProblemSolver = interfaceProblemSolver;
                }
            }

            Feti1Solver fetiSolver = solverBuilder.BuildSolver(multiSubdomainModel);

            if (residualIsExact)
            {
                exactResidualConvergence.FetiSolver = fetiSolver;
            }

            // Structural problem provider
            var provider = new ProblemStructural(multiSubdomainModel, fetiSolver);

            // Linear static analysis
            var childAnalyzer  = new LinearAnalyzer(multiSubdomainModel, fetiSolver, provider);
            var parentAnalyzer = new StaticAnalyzer(multiSubdomainModel, fetiSolver, provider, childAnalyzer);

            // Run the analysis
            parentAnalyzer.Initialize();
            parentAnalyzer.Solve();

            // Gather the global displacements
            var sudomainDisplacements = new Dictionary <int, IVectorView>();

            foreach (var ls in fetiSolver.LinearSystems)
            {
                sudomainDisplacements[ls.Key] = ls.Value.Solution;
            }
            Vector globalDisplacements = fetiSolver.GatherGlobalDisplacements(sudomainDisplacements);

            // Other stats
            int numUniqueGlobalDofs  = multiSubdomainModel.Nodes.Count * 2;
            int numExtenedDomainDofs = 0;

            foreach (var subdomain in multiSubdomainModel.Subdomains)
            {
                numExtenedDomainDofs += subdomain.Nodes.Count * 2;
            }

            return(globalDisplacements, fetiSolver.Logger, numUniqueGlobalDofs, numExtenedDomainDofs);
        }
Exemplo n.º 11
0
        public static IEnumerable <double> GetError <T, R>(IEnumerable <T> est, IEnumerable <R> meas, Func <T, double> estf, Func <R, double> measf, Residual lf)
        {
            var lossFunction = Helper.ChooseLossFunction(lf);

            return(est.Zip(meas, (a, b) => new { a, b }).Scan(0d, (e, f) => e + lossFunction(estf(f.a), measf(f.b))));
        }
Exemplo n.º 12
0
        public static IEnumerable <double> GetError(IEnumerable <double> est, IEnumerable <double> meas, Residual lf)
        {
            var lossFunction = Helper.ChooseLossFunction(lf);

            return(est.Zip(meas, (a, b) => new { a, b }).Scan(0d, (e, f) => e + lossFunction(f.a, f.b)));
        }
        private static (IVectorView globalDisplacements, SolverLogger logger) SolveModelWithSubdomains(double stiffnessRatio,
                                                                                                       Precond precond, Residual residualConvergence, double pcgConvergenceTolerance)
        {
            // Model
            Model multiSubdomainModel = CreateModel(stiffnessRatio);

            // Corner nodes
            double meshTol = 1E-6;
            var    cornerNodesOfEachSubdomain = new Dictionary <int, HashSet <INode> >();

            foreach (Subdomain subdomain in multiSubdomainModel.Subdomains)
            {
                subdomain.DefineNodesFromElements(); //TODO: This will also be called by the analyzer.
                INode[] corners     = CornerNodeUtilities.FindCornersOfRectangle2D(subdomain);
                var     cornerNodes = new HashSet <INode>();
                foreach (INode node in corners)
                {
                    if (node.Constraints.Count > 0)
                    {
                        continue;
                    }
                    if ((Math.Abs(node.X - domainLengthX) <= meshTol) && (Math.Abs(node.Y) <= meshTol))
                    {
                        continue;
                    }
                    if ((Math.Abs(node.X - domainLengthX) <= meshTol) && (Math.Abs(node.Y - domainLengthY) <= meshTol))
                    {
                        continue;
                    }
                    cornerNodes.Add(node);
                }
                cornerNodesOfEachSubdomain[subdomain.ID] = cornerNodes;
            }

            // Solver
            var fetiMatrices = new SkylineFetiDPSubdomainMatrixManager.Factory(new OrderingAmdSuiteSparse());
            //var fetiMatrices = new SkylineFetiDPSubdomainMatrixManager.Factory();
            //var fetiMatrices = new DenseFetiDPSubdomainMatrixManager.Factory();
            var cornerNodeSelection = new UsedDefinedCornerNodes(cornerNodesOfEachSubdomain);
            var solverBuilder       = new FetiDPSolver.Builder(cornerNodeSelection, fetiMatrices);

            solverBuilder.ProblemIsHomogeneous = stiffnessRatio == 1.0;
            //solverBuilder.ProblemIsHomogeneous = false;

            // Preconditioner
            if (precond == Precond.Lumped)
            {
                solverBuilder.PreconditionerFactory = new LumpedPreconditioner.Factory();
            }
            else if (precond == Precond.DirichletDiagonal)
            {
                solverBuilder.PreconditionerFactory = new DiagonalDirichletPreconditioner.Factory();
            }
            else
            {
                solverBuilder.PreconditionerFactory = new DirichletPreconditioner.Factory();
            }

            //TODO: This needs to be implemented for FETI-DP
            //// PCG may need to use the exact residual for the comparison with the expected values
            //bool residualIsExact = residualConvergence == Residual.Exact;
            //ExactPcpgConvergence.Factory exactResidualConvergence = null;
            //if (residualIsExact)
            //{
            //    exactResidualConvergence = new ExactPcpgConvergence.Factory(
            //        CreateSingleSubdomainModel(stiffnessRatio), solverBuilder.DofOrderer,
            //            (model, solver) => new ProblemStructural(model, solver));
            //}
            //if (residualIsExact) exactResidualConvergence.InterfaceProblemSolver = interfaceProblemSolver;

            // Specify solver for the interface problem
            var interfaceSolverBuilder = new FetiDPInterfaceProblemSolver.Builder();

            interfaceSolverBuilder.PcgConvergenceStrategyFactory = new ApproximateResidualConvergence.Factory();
            interfaceSolverBuilder.PcgConvergenceTolerance       = pcgConvergenceTolerance;
            solverBuilder.InterfaceProblemSolver = interfaceSolverBuilder.Build();

            FetiDPSolver fetiSolver = solverBuilder.BuildSolver(multiSubdomainModel);
            //if (residualIsExact) exactResidualConvergence.FetiSolver = fetiSolver;

            // Structural problem provider
            var provider = new ProblemStructural(multiSubdomainModel, fetiSolver);

            // Linear static analysis
            var childAnalyzer  = new LinearAnalyzer(multiSubdomainModel, fetiSolver, provider);
            var parentAnalyzer = new StaticAnalyzer(multiSubdomainModel, fetiSolver, provider, childAnalyzer);

            // Run the analysis
            parentAnalyzer.Initialize();
            parentAnalyzer.Solve();

            // Gather the global displacements
            var sudomainDisplacements = new Dictionary <int, IVectorView>();

            foreach (var ls in fetiSolver.LinearSystems)
            {
                sudomainDisplacements[ls.Key] = ls.Value.Solution;
            }
            Vector globalDisplacements = fetiSolver.GatherGlobalDisplacements(sudomainDisplacements);

            return(globalDisplacements, fetiSolver.Logger);
        }