using FeMM.Common.Models;
using FeMM.Grasshopper.Components.Models.MeCheck2;
using FeMM.Grasshopper.DataTypes;
using GH_IO.Serialization;
using Grasshopper;
using Grasshopper.Kernel;
using Grasshopper.Kernel.Data;
using Maffeis.Checkers.Concrete.Checkers;
using Maffeis.Model.Sections;
using Maffeis.Model.Sections.Steel;
using Maffeis.Model.Standards;
using Maffeis.Utilities.Maths;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Runtime.Versioning;

namespace FeMM.Grasshopper.Components.MeCheck2
{
#if NETCOREAPP
    [SupportedOSPlatform("windows")]
#endif
    public class SuperElementCheckComponentV2 : SuperElementCheckComponentBase
    {
        protected double[][] _rds;

        private List<CompositeSectionStiffeners> CompositeSectionStiffeners { get; set; }

        public SuperElementCheckComponentV2()
          : base()
        {
            _rds = null;
        }

        public override GH_Exposure Exposure => GH_Exposure.tertiary;

        /// <summary>
        /// Gets the unique ID for this component. Do not change this ID after release.
        /// </summary>
        public override Guid ComponentGuid => new("2c6c7e87-cd4d-42a1-b5d3-a06b0f8b5949");

        protected override void RegisterInputs(GH_InputParamManager pManager)
        {
            pManager.AddGenericParameter("Section Stiffeners", "SS", "Stiffeners data", GH_ParamAccess.list);
            pManager[6].Optional = true;
            pManager.AddIntegerParameter("Class 4 max iterations", "C4", "Maximum number of iterations to be made for section reduction in class 4. The value 1 means it stops after the first reduction. Value between 1 and 20.", GH_ParamAccess.item, 7);
            pManager[7].Optional = true;
        }

        protected override void RegisterOutputs(GH_OutputParamManager pManager)
        {
            pManager.AddNumberParameter("Shear Resistance", "SR", "The shear Rd values", GH_ParamAccess.list);
        }

        protected override void LoadReadedData(IGH_DataAccess DA)
        {
            if (_rds != null)
            {
                DataTree<double> rdsSaved = new();

                for (int i = 0; i < _rds.Length; i++)
                    rdsSaved.AddRange(_rds[i], new GH_Path(i));

                DA.SetDataTree(3, rdsSaved);
            }
        }

        protected override void ReadAdditionalParams(IGH_DataAccess DA)
        {
            CompositeSectionStiffeners = [];
            DA.GetDataList(6, CompositeSectionStiffeners);
            DA.GetData(7, ref _class4MaxIterations);
            if (_class4MaxIterations < 1 || _class4MaxIterations > 20)
                AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "Class 4 max iterations value must be between 1 and 20.");

            _forcesDataTree = null;
        }

        protected override bool ComputeStiffeners(IGH_DataAccess DA, List<GH_CompositeBeam> beams, SectionCheckerModelCode2010[][] checkers, double tolerance = 10)
        {
            StandardEN1993p11 EN1993p11 = new();

            double cumulativeBeamLength = 0;
            double cumulativeStiffenersLength = 0;
            int c = 0;
            List<int> multipleStiffenerBeams = [];

            _rds = new double[beams.Count][];
            DataTree<double> rds = new();

            for (int i = 0; i < beams.Count; i++)
            {
                CompositeBeamModel currentBeam = beams[i].Value;
                List<CompositeSectionStiffeners> beamStiffeners;
                SteelSection steelSectionStart = checkers[i][0].CheckerAttribute.Section.SteelSections[0].Section;
                SteelSection steelSectionEnd = checkers[i][checkers[i].Length - 1].CheckerAttribute.Section.SteelSections[0].Section;

                if (Math.Abs(cumulativeBeamLength - cumulativeStiffenersLength) <= tolerance)
                {
                    c++;
                    if (CompositeSectionStiffeners.Count > c)
                        cumulativeStiffenersLength += CompositeSectionStiffeners[c].BeamLength;
                }
                if (CompositeSectionStiffeners.Count > c)
                {
                    beamStiffeners = [CompositeSectionStiffeners[c]];
                    cumulativeBeamLength += currentBeam.Length;

                    if (cumulativeBeamLength > cumulativeStiffenersLength)
                    {
                        c++;

                        if (Math.Abs(cumulativeBeamLength - cumulativeStiffenersLength) > tolerance)
                        {
                            if (CompositeSectionStiffeners.Count > c)
                                beamStiffeners.Add(CompositeSectionStiffeners[c]);
                            else
                                beamStiffeners.Add(new CompositeSectionStiffeners(double.MaxValue, double.MaxValue, 1, 1, true, false));
                        }

                        if (CompositeSectionStiffeners.Count > c)
                            cumulativeStiffenersLength += CompositeSectionStiffeners[c].BeamLength;
                    }
                }
                else
                    beamStiffeners = [new CompositeSectionStiffeners(double.MaxValue, double.MaxValue, 1, 1, true, false)];

                double[] branchResults = new double[beamStiffeners.Count];
                for (int j = 0; j < beamStiffeners.Count; j++)
                {
                    branchResults[j] = GetRd(steelSectionStart, steelSectionEnd, currentBeam.Length, beamStiffeners[j], EN1993p11) / 1000;

                    if (double.IsNaN(branchResults[j]))
                    {
                        AddRuntimeMessage(GH_RuntimeMessageLevel.Error, $"The Length value of the composite stiffeners {c} is not valid.");
                        Message = "Error";
                        return false;
                    }
                }

                if (branchResults.Length > 1)
                    multipleStiffenerBeams.Add(i);

                _rds[i] = [.. branchResults];
                rds.AddRange(branchResults, new GH_Path(i));
            }

            if (multipleStiffenerBeams.Count > 0)
            {
                AddRuntimeMessage(GH_RuntimeMessageLevel.Warning, $"The stiffeners zones don't respect beams boundaries. Some beams have multiple zones defined inside them: {string.Join(", ", multipleStiffenerBeams)}.");
            }

            DA.SetDataTree(3, rds);
            return true;
        }

        /// <summary>
        /// Simplified version of the <see cref="EN1993p11Checker.ShearStiffnerCheck(SteelSection, StationResultBeamForces, double, double, double, bool, bool)"/> method. Returns the list of Shear Rd values for each beam.
        /// </summary>
        /// <param name="steelSectionStart"></param>
        /// <param name="steelSectionEnd"></param>
        /// <param name="beamLength"></param>
        /// <param name="beamStiffeners"></param>
        /// <param name="EN1993p11"></param>
        /// <returns></returns>
        private static double GetRd(SteelSection steelSectionStart, SteelSection steelSectionEnd, double beamLength, CompositeSectionStiffeners beamStiffeners, StandardEN1993p11 EN1993p11)
        {
            if (steelSectionStart.SectionShape is SectionH sectionHStart && steelSectionEnd.SectionShape is SectionH sectionHEnd)
            {
                double spacing = beamStiffeners.GeometryStiffenerSpacing;
                double width = beamStiffeners.GeometryStiffenerWidth;
                double thickness = beamStiffeners.GeometryStiffenerThickness;
                bool symm = beamStiffeners.GeometryStiffenerSymmetric;
                bool rigid = beamStiffeners.GeometryStiffenerRigid;

                double tw;
                double hw;
                double fyk;
                double E;

                // il calcolo viene fatto sulla sezione media del beam
                try
                {
                    tw = Interpolation.GetLinearInterpolation(0, beamLength, sectionHStart.ThicknessWeb, sectionHEnd.ThicknessWeb, beamLength / 2);
                    hw = Interpolation.GetLinearInterpolation(0, beamLength, sectionHStart.HeightWeb, sectionHEnd.HeightWeb, beamLength / 2);
                    fyk = Interpolation.GetLinearInterpolation(0, beamLength, steelSectionStart.SteelMaterial.Fyk, steelSectionEnd.SteelMaterial.Fyk, beamLength / 2);
                    E = Interpolation.GetLinearInterpolation(0, beamLength, steelSectionStart.SteelMaterial.E, steelSectionEnd.SteelMaterial.E, beamLength / 2);
                }
                catch (ArgumentException)
                {
                    return double.NaN;
                }

                double gm1 = EN1993p11.GammaM1;
                double gm0 = EN1993p11.GammaM0;

                double eta = 1.2;
                double sigmaE = 190000.0 * Math.Pow(tw / hw, 2.0);
                double kt = spacing / hw < 1.0 ? 4.0 + 5.34 * Math.Pow(hw / spacing, 2.0) : 5.34 + 4.0 * Math.Pow(hw / spacing, 2.0);
                double v1 = kt * sigmaE;
                double lambdaW = 0.76 * Math.Sqrt(fyk / v1);

                double stiffnersConsideredArea = symm ? (width + width) * thickness : width * thickness;

                double j = symm ? 1.0 / 12.0 * thickness * Math.Pow(width + tw + width, 3) : 1.0 / 12.0 * thickness * Math.Pow(width, 3);
                double nCr = Math.PI * Math.PI * E * j / Math.Pow(hw, 2);
                double lambdaSigned = Math.Sqrt(fyk * stiffnersConsideredArea / nCr);

                double chiW;
                if (lambdaW < 0.83 / eta)
                {
                    chiW = eta;
                }
                else if (lambdaW >= 0.83 / eta && lambdaW < 1.08)
                {
                    chiW = 0.83 / eta;
                }
                else
                {
                    if (rigid)
                        chiW = 1.37 / (0.7 / lambdaSigned);
                    else
                        chiW = 0.83 / lambdaW;
                }
                chiW = chiW > gm1 / gm0 ? gm1 / gm0 : chiW;

                return chiW * fyk * hw * tw / (Math.Pow(3, 0.5) * gm1);
            }

            return -1;
        }

        protected override void ResetData()
        {
            _rds = null;
        }

        //public override bool Write(GH_IWriter writer)
        //{
        //    bool success = base.Write(writer);
        //    if (!success)
        //        return false;

        //    if (_rds != null)
        //        writer.SetString("RdsDataTree", JsonConvert.SerializeObject(_rds));

        //    return true;
        //}

        //public override bool Read(GH_IReader reader)
        //{
        //    bool success = base.Read(reader);
        //    if (!success)
        //        return false;

        //    try
        //    {
        //        string rds = string.Empty;
        //        if (reader.TryGetString("RdsDataTree", ref rds) && !string.IsNullOrWhiteSpace(rds))
        //            _rds = JsonConvert.DeserializeObject<double[][]>(rds);
        //    }
        //    catch
        //    {
        //        _rds = null;
        //    }

        //    _just_loaded = true;

        //    return true;
        //}
    }
}
303 files24 directories