using FeMM.Common.Models;
using FeMM.Grasshopper.DataTypes.FeMM;
using FeMM.Grasshopper.Helpers;
using GH_IO.Serialization;
using Grasshopper.Kernel;
using Grasshopper.Kernel.Data;
using Grasshopper.Kernel.Special;
using Grasshopper.Kernel.Types;
using Maffeis.Utilities.Maths;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Versioning;
namespace FeMM.Grasshopper.Components.MeCheck2
{
#if NETCOREAPP
[SupportedOSPlatform("windows")]
#endif
public class BuildMeCheckModel : GH_Component
{
protected bool _run;
private GH_Model _model;
/// <summary>
/// Initializes a new instance of the ChecksComponent class.
/// </summary>
public BuildMeCheckModel()
: base("Build MeCheck Model", "BMCM", "Merge the FeMM models in to a single FeMM model with input phases", CategoryNameConstants.CATEGORY_CHECKS, CategoryNameConstants.SUBCATEGORY_MECHECK2)
{
_run = false;
_model = new GH_Model();
}
public override void CreateAttributes()
{
var attr = new ComponentAttributes.ComponentOneButtonAttributes(this, "Run");
attr.ButtonPressed += () =>
{
_run = true;
ExpireSolution(true);
};
m_attributes = attr;
}
/// <summary>
/// Registers all the input parameters for this component.
/// </summary>
protected override void RegisterInputParams(GH_InputParamManager pManager)
{
pManager.AddGenericParameter("FeMM Models", "FM", "The FEM models (more than one for stages)", GH_ParamAccess.list);
pManager.AddGenericParameter("Load Combinations", "LCB", "The load cases combinations", GH_ParamAccess.tree);
pManager.AddTextParameter("Only steel Load Cases", "OSPLC", "The load cases name to assign to the only steel phase", GH_ParamAccess.list);
pManager[2].Optional = true;
pManager.AddTextParameter("Infinite Time Load Cases", "InfTLC", "The load cases name to assign to the infinite time phase", GH_ParamAccess.list);
pManager[3].Optional = true;
pManager.AddTextParameter("Instant Time Load Cases", "InstTLC", "The load cases name to assign to the instant time phase", GH_ParamAccess.list);
pManager[4].Optional = true;
pManager.AddTextParameter("Infinite Time Strain Load Cases", "InfTSLC", "The load cases name to assign to the Phase infinite time strain phase", GH_ParamAccess.list);
pManager[5].Optional = true;
pManager.AddTextParameter("Instant Time Strain Load Cases", "InstTSSLC", "The load cases name to assign to the Phase instant time strain phase", GH_ParamAccess.list);
pManager[6].Optional = true;
}
/// <summary>
/// Registers all the output parameters for this component.
/// </summary>
protected override void RegisterOutputParams(GH_OutputParamManager pManager)
{
pManager.AddGenericParameter("Model", "M", "The FEM model", GH_ParamAccess.item);
}
/// <summary>
/// This is the method that actually does the work.
/// </summary>
/// <param name="DA">The DA object is used to retrieve from inputs and store in outputs.</param>
protected override void SolveInstance(IGH_DataAccess DA)
{
Message = "";
var models = new List<GH_Model>();
int n = 0;
var loadCaseOnlySteel = new List<string>();
var loadCaseInfiniteTime = new List<string>();
var loadCaseInstantTime = new List<string>();
var loadCaseStrainInfiniteTime = new List<string>();
var loadCaseStrainInstantTime = new List<string>();
if (!DA.GetDataList(n++, models))
return;
if (models.Any(i => i == null))
{
_run = false;
return;
}
if (models.Any(i => i.Value == null))
{
AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "Null model");
Message = "Error";
_run = false;
return;
}
// Retrieve all te super elements used in the model
List<SuperElementAttributeModel> superElementsBuffer = Common.Helpers.CommonModelHelper.GetSuperElements(models[0].Value);
var superElementsName = new List<string>();
for (int i = 0; i < superElementsBuffer.Count; i++)
superElementsName.Add(superElementsBuffer[i].Value);
// Connect the ValueList component on the analysis results input item
IEnumerable<IGH_Param> keys_analysisResultLists = Params.Input[n].Sources.Where(s => s.GetType() == typeof(GH_ValueList));
foreach (GH_ValueList vallist in keys_analysisResultLists)
{
if (vallist.ListMode != GH_ValueListMode.DropDown)
vallist.ListMode = GH_ValueListMode.DropDown;
ComponentsHelper.SetValueList(vallist, superElementsName);
vallist.NickName = "Super-Element";
}
bool has_combinations = DA.GetDataTree(n++, out GH_Structure<IGH_Goo> combinations);
var casesNamesSet = new HashSet<string>();
int m = 1;
for (int i = 0; i < models.Count; i++)
{
GH_Model model = models[i];
// Add the model load and combination cases from results
var modelLoadCases = new List<CaseModel>(model.Value.Elements.SelectMany(e => e.Results).Select(l => l.LoadCase).Distinct());
for (int j = 0; j < modelLoadCases.Count; j++)
{
CaseModel loadCase = modelLoadCases[j];
string lcase_name = $"{m}-{loadCase.Name}";
casesNamesSet.Add(lcase_name);
}
m++;
}
List<string> casesNames = [.. casesNamesSet];
casesNames.Sort();
DA.GetDataList(n, loadCaseOnlySteel);
{
IEnumerable<IGH_Param> keys_analysisResultListsCase = Params.Input[n].Sources.Where(s => s.GetType() == typeof(GH_ValueList));
foreach (GH_ValueList vallist in keys_analysisResultListsCase)
{
if (vallist.ListMode != GH_ValueListMode.CheckList)
vallist.ListMode = GH_ValueListMode.CheckList;
ComponentsHelper.SetValueList(vallist, casesNames);
vallist.NickName = Params.Input[n].NickName;
}
n++;
}
DA.GetDataList(n, loadCaseInfiniteTime);
{
IEnumerable<IGH_Param> keys_analysisResultListsCase = Params.Input[n].Sources.Where(s => s.GetType() == typeof(GH_ValueList));
foreach (GH_ValueList vallist in keys_analysisResultListsCase)
{
if (vallist.ListMode != GH_ValueListMode.CheckList)
vallist.ListMode = GH_ValueListMode.CheckList;
ComponentsHelper.SetValueList(vallist, casesNames);
vallist.NickName = Params.Input[n].NickName;
}
n++;
}
DA.GetDataList(n, loadCaseInstantTime);
{
IEnumerable<IGH_Param> keys_analysisResultListsCase = Params.Input[n].Sources.Where(s => s.GetType() == typeof(GH_ValueList));
foreach (GH_ValueList vallist in keys_analysisResultListsCase)
{
if (vallist.ListMode != GH_ValueListMode.CheckList)
vallist.ListMode = GH_ValueListMode.CheckList;
ComponentsHelper.SetValueList(vallist, casesNames);
vallist.NickName = Params.Input[n].NickName;
}
n++;
}
var casesNamesStrainSet = new HashSet<string>();
m = 1;
for (int i = 0; i < models.Count; i++)
{
GH_Model model = models[i];
// Add the model load and combination cases from results
var modelLoadCases = new List<CaseModel>();
for (int j = 0; j < model.Value.Elements.Count; j++)
{
for (int k = 0; k < model.Value.Elements[j].Loads.Count; k++)
{
if (model.Value.Elements[j].Loads[k] is CompositeBeamSlabStrainModel compositeBeamSlabStrainModel)
{
string lcase_name = $"{m}-{compositeBeamSlabStrainModel.LoadCase.Name}";
casesNamesStrainSet.Add(lcase_name);
}
}
}
m++;
}
List<string> casesNamesStrain = [.. casesNamesStrainSet];
casesNamesStrain.Sort();
DA.GetDataList(n, loadCaseStrainInfiniteTime);
{
IEnumerable<IGH_Param> keys_analysisResultListsCase = Params.Input[n].Sources.Where(s => s.GetType() == typeof(GH_ValueList));
foreach (GH_ValueList vallist in keys_analysisResultListsCase)
{
if (vallist.ListMode != GH_ValueListMode.CheckList)
vallist.ListMode = GH_ValueListMode.CheckList;
ComponentsHelper.SetValueList(vallist, casesNamesStrain);
vallist.NickName = Params.Input[n].NickName;
}
n++;
}
DA.GetDataList(n, loadCaseStrainInstantTime);
{
IEnumerable<IGH_Param> keys_analysisResultListsCase = Params.Input[n].Sources.Where(s => s.GetType() == typeof(GH_ValueList));
foreach (GH_ValueList vallist in keys_analysisResultListsCase)
{
if (vallist.ListMode != GH_ValueListMode.CheckList)
vallist.ListMode = GH_ValueListMode.CheckList;
ComponentsHelper.SetValueList(vallist, casesNamesStrain);
vallist.NickName = Params.Input[n].NickName;
}
n++;
}
if (!_run)
{
if (_model is not null && _model.IsValid)
{
//ModelHelper.RestoreModelGuids(models[0], ref _model);
//DA.SetData(0, _model);
//Message = "Loaded";
}
}
else
{
try
{
// Nuovo modello di output
var newModel = new ModelModel(models[0].Value.Units);
var stageOS = new LoadCaseModel.BridgeStage("Only Steel Phase") { BridgePhase = LoadCaseModel.BridgeStage.BridgePhases.OnlySteel };
var stagenInst = new LoadCaseModel.BridgeStage("Instant Time Loads Phase") { BridgePhase = LoadCaseModel.BridgeStage.BridgePhases.NInstant };
var stageninf = new LoadCaseModel.BridgeStage("Infinite Time Loads Phase") { BridgePhase = LoadCaseModel.BridgeStage.BridgePhases.NInfinite };
var stageStrainInst = new LoadCaseModel.BridgeStage("Instant Time Strain Phase") { BridgePhase = LoadCaseModel.BridgeStage.BridgePhases.StrainInstant };
var stageStrainInf = new LoadCaseModel.BridgeStage("Infinite Time Strain Phase") { BridgePhase = LoadCaseModel.BridgeStage.BridgePhases.StrainInfinite };
for (int j = 0; j < casesNames.Count; j++)
{
var loadCaseModel = new LoadCaseModel(j + 1, casesNames[j]);
if (loadCaseOnlySteel.Contains(loadCaseModel.Name))
loadCaseModel.Stages.Add(stageOS);
else if (loadCaseInfiniteTime.Contains(loadCaseModel.Name))
loadCaseModel.Stages.Add(stageninf);
else if (loadCaseInstantTime.Contains(loadCaseModel.Name))
loadCaseModel.Stages.Add(stagenInst);
newModel.LoadCases.Add(loadCaseModel);
}
// Add geometries from the first model
for (int i = 0; i < models[0].Value.Nodes.Count; i++)
{
var nodeModel = new NodeModel(models[0].Value.Nodes[i]);
newModel.AddElements(new NodeModel[] { nodeModel });
}
for (int i = 0; i < models[0].Value.Beams.Count; i++)
{
var beamModel = new BeamModel(models[0].Value.Beams[i]);
newModel.AddElements(new BeamModel[] { beamModel });
}
for (int i = 0; i < models[0].Value.Plates.Count; i++)
{
var plateModel = new PlateModel(models[0].Value.Plates[i]);
newModel.AddElements(new PlateModel[] { plateModel });
}
for (int mm = 1; mm < models.Count; mm++)
{
//for (int i = 0; i < models[mm].Value.Nodes.Count; i++)
//{
// for (int j = 0; j < models[mm].Value.Nodes[i].Loads.Count; j++)
// {
// newModel.Nodes[i].Loads.Add((LoadModel)models[mm].Value.Nodes[i].Loads[j].Clone());
// }
//}
for (int i = 0; i < models[mm].Value.Beams.Count; i++)
{
for (int j = 0; j < models[mm].Value.Beams[i].Loads.Count; j++)
{
newModel.Beams[i].Loads.Add((LoadModel)models[mm].Value.Beams[i].Loads[j].Clone());
}
}
//for (int i = 0; i < models[mm].Value.Plates.Count; i++)
//{
// for (int j = 0; j < models[mm].Value.Plates[i].Loads.Count; j++)
// {
// newModel.Plates[i].Loads.Add((LoadModel)models[mm].Value.Plates[i].Loads[j].Clone());
// }
//}
}
for (int i = 0; i < newModel.Nodes.Count; i++)
{
newModel.Nodes[i].Attributes.Clear();
newModel.Nodes[i].Results.Clear();
newModel.Nodes[i].Loads.Clear();
}
for (int i = 0; i < newModel.Beams.Count; i++)
{
newModel.Beams[i].Results.Clear();
}
for (int i = 0; i < newModel.Plates.Count; i++)
{
newModel.Plates[i].Attributes.Clear();
newModel.Plates[i].Results.Clear();
newModel.Plates[i].Loads.Clear();
}
//TODO: risistemare unità di misura
//}
HashSet<double>[] stationsHash = new HashSet<double>[newModel.Beams.Count];
for (int i = 0; i < newModel.Beams.Count; i++)
{
stationsHash[i] = [];
for (int mm = 0; mm < models.Count; mm++)
{
GH_Model model = models[mm];
BeamModel beam = model.Value.Beams[i];
for (int j = 0; j < beam.Results.Count; j++)
{
BeamForceResultModel force = (BeamForceResultModel)beam.Results[j];
double dist = Math.Round(force.NormalizedLength ? force.Station * beam.Length : force.Station, 15);
stationsHash[i].Add(dist);
}
}
}
double[][] stations = new double[newModel.Beams.Count][];
for (int i = 0; i < newModel.Beams.Count; i++)
stations[i] = [.. stationsHash[i]];
for (int i = 0; i < stations.Length; i++)
stations[i] = [.. stations[i].OrderBy(k => k)];
BeamForceResultModel[][][] results = new BeamForceResultModel[newModel.Beams.Count][][];
for (int mm = 0; mm < models.Count; mm++)
{
for (int i = 0; i < newModel.Beams.Count; i++)
{
double[] beamStations = stations[i];
results[i] = new BeamForceResultModel[beamStations.Length][];
for (int kk = 0; kk < beamStations.Length; kk++)
results[i][kk] = new BeamForceResultModel[newModel.LoadCases.Count];
}
}
// Add load cases and the tensions for the models
m = 1;
for (int mm = 0; mm < models.Count; mm++)
{
GH_Model model = models[mm];
// Add the frame forces
for (int i = 0; i < newModel.Beams.Count; i++)
{
BeamModel newBeam = newModel.Beams[i];
BeamModel oldBeam = model.Value.Beams[i];
double[] beamStations = stations[i];
for (int j = 0; j < oldBeam.Results.Count; j++)
{
BeamForceResultModel force = (BeamForceResultModel)oldBeam.Results[j];
double stationDist = Math.Round(force.NormalizedLength ? force.Station * oldBeam.Length : force.Station, 15);
string loadCaseName = force.LoadCase.Name;
int stationIndex = beamStations.ToList().IndexOf(stationDist);
int comboIndex = newModel.LoadCases.Select(ll => ll.Name).ToList().IndexOf($"{m}-{loadCaseName}");
var newForce = new BeamForceResultModel((CaseModel)newModel.LoadCases.First(k => k.Name == $"{m}-{force.LoadCase.Name}"), force.Station, 0, "", false)
{
AxialForce = force.AxialForce,
ShearForce = force.ShearForce,
Torque = force.Torque,
BendingMoment = force.BendingMoment,
};
results[i][stationIndex][comboIndex] = newForce;
}
}
m++;
}
for (int i = 0; i < newModel.Beams.Count; i++)
{
BeamModel beam = newModel.Beams[i];
//BeamModel oldBeam = model.Value.Beams[i];
double[] beamStations = stations[i];
for (int j = 0; j < beamStations.Length; j++)
{
for (int s = 0; s < newModel.LoadCases.Count; s++)
{
if (results[i][j][s] is null)
{
try
{
double stationDist = beamStations[j];
BeamForceResultModel forceMinus = null;
if (j == 0)
{
for (int jPrev = j; jPrev >= 0; jPrev++)
{
if (results[i][jPrev][s] is null)
continue;
else
{
forceMinus = results[i][jPrev][s];
break;
}
}
}
else
{
for (int jPrev = j - 1; jPrev >= 0; jPrev--)
{
if (results[i][jPrev][s] is null)
continue;
else
{
forceMinus = results[i][jPrev][s];
break;
}
}
}
BeamForceResultModel forcePlus = null;
if (j == results[i].Length - 1)
{
for (int jNext = j; jNext >= 0; jNext--)
{
if (results[i][jNext][s] is null)
continue;
else
{
forcePlus = results[i][jNext][s];
break;
}
}
}
else
{
for (int jNext = j + 1; jNext < results[i].Length; jNext++)
{
if (results[i][jNext][s] is null)
continue;
else
{
forcePlus = results[i][jNext][s];
break;
}
}
}
if (forcePlus == null || forceMinus == null)
{
AddRuntimeMessage(GH_RuntimeMessageLevel.Error, $"Null results: check the beam {beam.BeamId} in station {stationDist} " +
$"for case {newModel.LoadCases[s].Name}");
Message = "Error";
_run = false;
return;
}
double distPlus = Math.Round(forcePlus.NormalizedLength ? forcePlus.Station * beam.Length : forcePlus.Station, 15);
double distMinus = Math.Round(forceMinus.NormalizedLength ? forceMinus.Station * beam.Length : forceMinus.Station, 15);
double x = stationDist - distMinus;
double l = distPlus - distMinus;
double nForce = Interpolation.GetLinearInterpolation(distMinus, distPlus, forceMinus.AxialForce, forcePlus.AxialForce, stationDist);
double V1Force = Interpolation.GetLinearInterpolation(distMinus, distPlus, forceMinus.Vx, forcePlus.Vx, stationDist);
double V2Force = Interpolation.GetLinearInterpolation(distMinus, distPlus, forceMinus.Vy, forcePlus.Vy, stationDist);
double TForce = Interpolation.GetLinearInterpolation(distMinus, distPlus, forceMinus.Torque, forcePlus.Torque, stationDist);
//double M1Force = Interpolation.GetLinearInterpolation(distMinus, distPlus, forceMinus.Mx, forcePlus.Mx, stationDist);
//double M2Force = Interpolation.GetLinearInterpolation(distMinus, distPlus, forceMinus.My, forcePlus.My, stationDist);
double M2Force = forceMinus.My + (forcePlus.Vy - forceMinus.Vy) / l * Math.Pow(x, 2) / 2.0 + forceMinus.Vy * x;
double M1Force = forceMinus.Mx + (forcePlus.Vx - forceMinus.Vx) / l * Math.Pow(x, 2) / 2.0 + forceMinus.Vx * x;
var newForce = new BeamForceResultModel((CaseModel)newModel.LoadCases.First(k => k.Name == $"{newModel.LoadCases[s].Name}"), stationDist, 0, "", false)
{
AxialForce = nForce,
Vx = V1Force,
Vy = V2Force,
Torque = TForce,
Mx = M1Force,
My = M2Force,
};
results[i][j][s] = newForce;
}
catch (Exception ex)
{
AddRuntimeMessage(GH_RuntimeMessageLevel.Error, $"Error during results interpolation. Check null restults in the input models. {ex}");
Message = "Error";
_run = false;
return;
}
}
}
}
for (int j = 0; j < results[i].Length; j++)
{
for (int k = 0; k < results[i][j].Length; k++)
{
beam.Results.Add(results[i][j][k]);
}
}
}
for (int j = 0; j < casesNamesStrain.Count; j++)
{
var loadCaseModel = new LoadCaseModel(j + 1, casesNamesStrain[j]);
if (loadCaseStrainInstantTime.Contains(loadCaseModel.Name))
loadCaseModel.Stages.Add(stageStrainInst);
else if (loadCaseStrainInfiniteTime.Contains(loadCaseModel.Name))
loadCaseModel.Stages.Add(stageStrainInf);
newModel.LoadCases.Add(loadCaseModel);
}
m = 1;
for (int i = 0; i < models.Count; i++)
{
GH_Model model = models[i];
for (int j = 0; j < model.Value.Beams.Count; j++)
{
BeamModel beam = model.Value.Beams[j];
BeamModel newBeam = newModel.Beams[j];
for (int k = 0; k < beam.Loads.Count; k++)
{
if (beam.Loads[k] is CompositeBeamSlabStrainModel compositeBeamSlabStrainModel)
{
string lcase_name = $"{m}-{compositeBeamSlabStrainModel.LoadCase.Name}";
var clone = new CompositeBeamSlabStrainModel(compositeBeamSlabStrainModel);
LoadCaseModel loadCaseModelClone = (LoadCaseModel)newModel.LoadCases.Where(vv => vv is LoadCaseModel).FirstOrDefault(vv => vv.Name == lcase_name);
loadCaseModelClone.Name = lcase_name;
clone.LoadCase = loadCaseModelClone;
for (int l = 0; l < newBeam.Loads.Count; l++)
{
if (newBeam.Loads[l].LoadCase.Name == compositeBeamSlabStrainModel.LoadCase.Name)
{
newBeam.Loads[l] = clone;
}
}
}
}
}
m++;
}
// Set the load combinations
var load_combinations = new List<LoadCaseCombinationModel>();
if (has_combinations)
{
var cnames = new List<string>();
for (int i = 0; i < combinations.Branches.Count; i++)
{
List<IGH_Goo> row = (List<IGH_Goo>)combinations.get_Branch(i);
if (i == 0) // First rows: check cases name
{
cnames.AddRange(row.Cast<GH_String>().Where(c => c.Value != "").Select(c => c.Value));
IEnumerable<string> invalid_names = cnames.Where(c => !casesNames.Contains(c));
invalid_names = invalid_names.Where(c => !casesNamesStrain.Contains(c));
if (invalid_names.Count() > 0)
{
AddRuntimeMessage(GH_RuntimeMessageLevel.Warning, "Invalid cases name: " + string.Join(", ", invalid_names));
break;
}
}
else
{
string name = ((GH_String)row[0]).Value;
IEnumerable<double> incrms = row.Cast<GH_String>().Where(c => double.TryParse(c.Value, out double d)).Select(c => Convert.ToDouble(c.Value));
var loadCombinationModel = new LoadCaseCombinationModel(name);
for (int j = 0; j < incrms.Count(); j++)
loadCombinationModel.Values.Add(new LoadCaseModel(-1, cnames[j]), incrms.ElementAt(j));
newModel.Combinations.Add(loadCombinationModel);
}
}
}
newModel.Name = "Merged Model";
_model = new()
{
Value = newModel
};
ModelHelper.RestoreModelGuids(models[0], ref _model);
DA.SetData(0, _model);
Message = "Done";
_run = false;
}
catch (Exception e)
{
AddRuntimeMessage(GH_RuntimeMessageLevel.Error, $"Generic error: {e}");
Message = "Error";
_run = false;
return;
}
}
_run = false;
}
public override bool Write(GH_IWriter writer)
{
bool success = base.Write(writer);
if (!success)
return false;
//return _model.Write(writer);
return true;
}
public override bool Read(GH_IReader reader)
{
bool success = base.Read(reader);
if (!success)
return false;
//return _model.Read(reader);
return true;
}
/// <summary>
/// Provides an Icon for the component.
/// </summary>
protected override System.Drawing.Bitmap Icon => Properties.Resources.BuildMeCheckModelIcon;
/// <summary>
/// Gets the unique ID for this component. Do not change this ID after release.
/// </summary>
public override Guid ComponentGuid => new("7395c22b-8c32-4f0a-b761-6387990c895b");
}
}