Read of soil, iterate on phi_k and export displacement [SOLVED]

Hi I am trying to replicate example in Geotechnocal Modul Handbook chap 5.7.

I am a beginner programmer in C# have not come that far as I am trouble finding names for method/classes and commands that is posible from FEMDesign.Core.
Is there handbook for this? (Is it too few users for this?)

As a starting point I think the example “Parametric study - reactions” is similar to what I am trying to do.
But insted of changing E-mdulus of concrete I want to iterate on phi_k (c_k for a clay or till) for a soil material.

I have sectioned my problem in 3 parts

  1. READ SOIL MATERIAL TO ANALYSE
  2. CHANGE phi_k
  3. GET DISPLACEMENT RESULTS

I have attached the current code + .struxml
Any help would be much appreciated

sample_slab_KPN.struxml (49.6 KB)
Program.cs (3.6 KB)

Hi @KPN :wave:

What you are trying to do is not super simple for a beginner but it is definitely possible.

I want you to have a look at the attached file, and come back with question (if any).

I slightly modified the .struxml as there were 2 stratum object with the same name.

The program will:

  • read a model
  • modify some of the properties of the stratum

You will need to implement the analysis ( simple ) and get some results ( medium ).

Let me know how it goes. If any issue, we can arrange a call tomorrow in the afternoon.

Modify and iterate.zip (9.6 KB)

1 Like

Thank you :slight_smile: With this info part 1 and 2 of the problem could be solved.

Still confused about exporting nodal displacement for a selected node in text format. I am aiming for a graph similar to fig 5.86 in Geotechnical Module Handbook.

hmm will have to try some more before I can have more questions.

Saving a .struxml file for a selected iteration so that the failure can visually be controlled would also be desirable, maybe I am asking for to much XD

The API is currently giving you access to several methods to return results.

var disp = femDesign.GetResults<NodalDisplacement>(units: unit).ToList();

disp is a list and with some filtering, you can get the results in any node.
I am pretty sure that ChatGPT can give you an answer on how to do filtering in a list of object.

var disp = femDesign.GetResults<NodalDisplacement>(units: unit).ToList();

Filtering can be done in several way but below an idea.

var dispNodeId = disp.Where(x => x.CaseIdentifier == "CASE").Where(x => x.NodeId == 1).ToList();

To save the model, you can use the following method

var filePath = "filePath"
var disp = femDesign.Save(filePath);

It is now a matter of implementing a logic but you have all the piece of informations :slight_smile:

1 Like

Now the filtering and saving works.

Probably an easy thing but I can’t get FEMDesign to calculate soil as solid elements. (Combination setup is copied from Practical example - Run analysis)

I also have problem with changing nodal position as I want to track displacement in a specific point :confused:

To my understanding node number can change.
Node number changes for the desired point when I manually regenerate the mesh.

As I want result in a specific point (bottom of slope with coordinates x,y,z = 4.00 , 1.50 , 0.00, se picutre below) maybe resultpoint is better to use?

As this could not be used for soil maybe a dummy fictitious bar with negligible stiffness could be created in order to have a result point here?

I have marked my two problems in the code with:

  1. Run calculation with soil as solid elements
  2. Export displacement from result point.

Thankful for any help :slight_smile:

As a side note for saving.

It is possible to save the resultfile? So that I can visually control deformation in selected failure iteration without new calculation?

What I can se only .str or .struxml is allowed.

Manual calculation normally create .strFEM file so that you can access the result of a analysis even after reopening the program.

See current code in attached zip folder:
Testrun.zip (7.1 MB)

1 Like

Hi @KPN :wave:

I have just asked to the developer if they can give access to the function to calculate the soil as solid elements. As a work-around, you can put a breaking point just after connection.Open() and manually set calculation option.

Results can be probably taken with ResultPoints created on a FictiousBar and read the value of it.

Otherwise, if you want to do it nicely, you can create a method that look for the closest point.

feaNode = femDesign.GetFeaNodes();

var myPoint = new Geometry.Point3d(10, 10, 10);
var myNodeId = feaNode.Where(n => (new Geometry.Point3d(n.X, n.Y, n.Z) - myPoint).Length() < 0.001).FirstOrDefault().NodeId;

var myRes = displacements.Where(r => r.CaseIdentifier == "CASE").Where(x => x.NodeId == myNodeId).FirstOrDefault();

I haven’t tested this code but it should give you an idea :slight_smile:

Feel free to raise other question if you get stuck!

1 Like

@KPN

I have realised that you do not need to set a breaking point.
What you can do, it is to manually open FEM-Design, set the “Soil as Solid” and click on “Save as default”.

Next time that you open FEM-Design, you will have the settings ready

I feel like you have helped me every step of the way so I just want to say thank you :slight_smile:

Setting “Soil as Solid” as default was my initial ide, does not work for me (changed in both net6.0 folder / FEM-Design API and when iterating). Have you tested it?

When I test the same node number is chosen every iteration.
What I find interesting is that any of the calculation tabs Analysis → Composite generate a mesh before calculation with node number 558 at my result point.
But when using Finite elements “Generate” button the result points gets a different node number (1808).

My code so far:

using FemDesign;
using FemDesign.Calculate;
using FemDesign.Materials;
using FemDesign.Results;
using FemDesign.Shells;
using FemDesign.Soil;
using StruSoft.Interop.StruXml.Data;

namespace FemDesign.SoilIter //ITERATE SOIL STRENGTH
{
    internal class Program
    {
        static void Main()
        {

            // READ AND SAVE MODEL NAME
            string struxmlPath = "GEO.struxml";
            Model model = Model.DeserializeFromFilePath(struxmlPath);
            string struxmlPath_saved = "GEO_saved.str";

            // 1. READ SOIL MATERIAL TO ANALYSE
            var soil = model.Materials.Material.Where(m => m.Name == "Soil_ver").ToList()[0];
            var drained = (Material_typeStratumBehaviourDrained)soil.Stratum.Behaviour.Item;
            var C_k_org = drained.C_k;
            var Phi_k_org = drained.Phi_k;
            var Phi_cvk_org = drained.Phi_cvk;

            int i_failure = 1;              // SAVEING .STRUXML FILE AT FAILURE (ADJUST AFTER FAILIURE ITERATION IS KNOW)
            List<double> MsfList_SDL = new List<double> { 0.0, 0.4, 0.5, 0.55, 0.56, 0.57, 0.58, 0.6, 0.66 };
            //List<double> MsfList_SUR = new List<double> { 0.0, 0.1, 0.2, 0.23, 0.25, 0.27, 0.30, 0.35 };

            // ANALYSIS SETTINGS
            var combItem = new Calculate.CombItem
            {
                ImpfRqd = 0,
                StabRqd = 0,
                NLE = false,
                PL = false,
                NLS = true,
                Cr = false,
                f2nd = false,
                Im = 0,
                Waterlevel = 0,
            };
            var combItems = new List<Calculate.CombItem>
                    {
                        combItem,
                    };
            var comb = new Calculate.Comb
            {
                NLEmaxiter = 30,
                PLdefloadstep = 20,
                PLminloadstep = 2,
                PlKeepLoadStep = true,
                PlTolerance = 1,
                PLmaxeqiter = 50,
                PlShellLayers = 10,
                NLSMohr = true,
                NLSinitloadstep = 10,
                NLSminloadstep = 10,
                NLSactiveelemratio = 5,
                NLSplasticelemratio = 5,
                CRloadstep = 20,
                CRmaxiter = 30,
                CRstifferror = 2,
                CombItem = combItems,
            };

            Analysis analysis = new Analysis(comb: comb, calcCase: true, calcComb: true);
            double myPointX = 4;
            double myPointY = 1.5;
            double myPointZ = 0;
            
            string LCName = "LC1";

            // ITERATION & ANALYSIS PROCESS

            using (var femDesign = new FemDesignConnection(keepOpen: true))
            {
                for (int i = 0; i < MsfList_SDL.Count; i++)
                //for (int i = 0; i < MsfList_SUR.Count; i++)
                {
                    Console.WriteLine($"Iteration {i}");
                    // Setting material safty factor and reduce soil strength 
                    double Msf = 1 + MsfList_SDL[i];
                    // double Msf = 1 + MsfList_SUR[i];
                    drained.C_k = C_k_org / Msf;
                    drained.Phi_k = Math.Atan(Math.Tan(Phi_k_org) / Msf);
                    drained.Phi_cvk = Math.Atan(Math.Tan(Phi_cvk_org) / Msf);

                    // Print of friction angle and material safty factor
                    Console.WriteLine($"Msf: {Math.Round(Msf, 2)}");
                    Console.WriteLine($"C_k: {Math.Round(drained.C_k, 2)}");
                    Console.WriteLine($"Phi_k: {Math.Round(180 / Math.PI * drained.Phi_k, 2)}");
                    Console.WriteLine($"Phi_cvk: {Math.Round(180 / Math.PI * drained.Phi_cvk, 2)}");

                    // Run analysis 
                    femDesign.Open(model);
                    // --- Run calculation with soil as solid elements (NOT IMPLEMENTED YET) ---

                    femDesign.RunAnalysis(analysis); // ADD BREAKPOINT AND MANUALLY SETT "CALCULATE SOIL AS SOILD ELEMENT" (TEMPERORY FIX)
                    // Find node number at myPoint
                    var feaNode = femDesign.GetFeaNodes();
                    var myPoint = new Geometry.Point3d(myPointX, myPointY, myPointZ);
                    var myNodeId = feaNode.Where(n => (new Geometry.Point3d(n.X, n.Y, n.Z) - myPoint).Length() < 0.001).FirstOrDefault().NodeId;
                    Console.WriteLine($"Node Id: {myNodeId}");
                    var disp = femDesign.GetResults<NodalDisplacement>();
                    var myRes = disp.Where(r => r.CaseIdentifier == LCName).Where(x => x.NodeId == myNodeId).ToList();

                    // Print node displacement
                    foreach (var myRe in myRes)
                    {
                        var dispID = myRe.Id;
                        var dispX = Math.Round(myRe.Ex,3);
                        var dispY = Math.Round(myRe.Ey,3);
                        var dispZ = Math.Round(myRe.Ez,3);
                        var dispAbs = Math.Round(Math.Sqrt(Math.Pow(dispX, 2) + Math.Pow(dispY, 2) + Math.Pow(dispZ, 2)), 3);
                        var dispCId = myRe.CaseIdentifier;
                        Console.WriteLine($"{dispID,5} | ex={dispX,5}, ey={dispY,5}, ez={dispZ,5}, eabs={dispAbs,5} | {dispCId,5}");
                    }

                    // Save failure iteration
                    if (i == i_failure)
                    {
                        Console.WriteLine($"Saving model at i = {i}");
                        femDesign.Save(struxmlPath_saved);
                    }

                    Console.WriteLine("\n");
                }

                Console.WriteLine("FEM-Design is closing.");

            }
            Console.WriteLine("Press any key to exit.");
            Console.ReadKey();
        }

    }
}

Comparing manual calculation with the iteration loops is correct for Msf 1 / 1.5 but differ for 1.4 / 1.5 but maybe this is just because of the large displacement :sweat_smile:

Comparing it to the example in Geotechnical module there is a bit of difference that I will need think about further …

Looks great @KPN !

You are right. “Save as default” seems to have some issue as the femdesign.connection failed to keep the value. I have opened a ticket for our developers. I hope they will be able to fix the error before the end of september.

I hope that the NodeId is selected correctly with the provided code.

ehi @KPN!

I have solved the issue of “soil as solid”.
If you download the branch 23.6.0_Dev, you will have access to a property called SoilAsSolid which can be set to true.

myModel.SoilAsSolid = true;

Let me know if you have trouble in downloading the repository :slight_smile:

1 Like

The update was perfect now the analysis runs with “Calculate soil as solid element”.

Also added selection of max abs value through the folloing code:

var MaxAbs = disp.Select(t => Math.Sqrt(Math.Pow(t.Ex, 2) + Math.Pow(t.Ey, 2) + Math.Pow(t.Ez, 2))).Max();
int MaxAbs_I = disp.FindIndex(t => Math.Sqrt(Math.Pow(t.Ex, 2) + Math.Pow(t.Ey, 2) + Math.Pow(t.Ez, 2)) == MaxAbs);

I notice that avrage element size of solids is not contained in a .strxml file (affects the size of displacement)
image
Could you help me with code for this?
Simmilar to:

model.Entities.Slabs[0].SlabPart.MeshSize = size;

( Practical example - Mesh size convergence study)

Ehi @KPN
Sorry for my late reply but I am currently on holiday!

Unfortunately, we do not have access to the solid dimension input through the API.

I’ll create a case and come back to you as soon as it is implemented :slight_smile:

1 Like

Oh it is not that urgent and can wait. Hope you are having a great holiday then :slight_smile:

ehy @KPN

Holiday was great! :slight_smile:

I have opened a case related to the solid sizes
https://strusoft.fogbugz.com/f/cases/134942/Average-size-element-of-Solid

Do you think something else is missing for your project?

Nope can’t think of any more questions to this project :slight_smile:

1 Like