Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ADSECGH-101: Update serviceability result component #137

Open
wants to merge 17 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
edd5aec
feat(SlsResulFunction.cs): add function class for SLS result component
SandeepArup Mar 10, 2025
75217d7
feat(ResultsSLS.cs): component migrated to use new approach
SandeepArup Mar 11, 2025
72ac17d
feat(SlsResultFunctionTest): test for SLS results
SandeepArup Mar 11, 2025
6b04a35
Merge branch 'main' into task/ADSECGH-101
SandeepArup Mar 11, 2025
4e0e1b5
test(ResultsSLS.cs): code refactored and test added
SandeepArup Mar 11, 2025
e6af288
Merge branch 'main' into task/ADSECGH-101
SandeepArup Mar 11, 2025
256185a
fix(SlsResultFunction): file name corrected
SandeepArup Mar 12, 2025
2cfceab
Merge branch 'task/ADSECGH-101' of github.com:arup-group/AdSec-Grassh…
SandeepArup Mar 12, 2025
92cef00
fix(SlsResultFunctionTests.cs): make file name singular
SandeepArup Mar 12, 2025
9bec26a
refactor(IFunction): remove abbreviation related function
SandeepArup Mar 12, 2025
0527283
fix(SlsResultFunction): update function to use correct unit
SandeepArup Mar 12, 2025
edf3463
refactor(ComponentAdapter): Refactor code to refresh component
SandeepArup Mar 12, 2025
ba26520
test(SlsResultTests): test that units refresh correctly
SandeepArup Mar 12, 2025
1bf429e
refactor(ComponentAdapter): include case when nick name has been changed
SandeepArup Mar 12, 2025
e02cc9b
refactor(ResultsSLS.cs): refactor to update parameter on pre-solve in…
SandeepArup Mar 13, 2025
1a7658f
refactor(SlsResultTests): test modified and code refactored to update…
SandeepArup Mar 13, 2025
65a7d1f
refactor(IFunction): remove unused code
SandeepArup Mar 13, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion AdSecCore/Functions/FindCrackLoadFunction.cs
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ public void Compute() {
sls = solution.Solution.Serviceability.Check(baseLoad);

SectionLoad.Value = sls.Load;
MaximumCracking.Value = sls.MaximumWidthCrack;
MaximumCracking.Value = new CrackLoad() { Load = sls.MaximumWidthCrack, Plane = solution.SectionDesign.LocalPlane };
}

}
Expand Down
3 changes: 3 additions & 0 deletions AdSecCore/Functions/IFunction.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,10 @@ public interface IFunction {
}

public abstract class Function : IFunction {
public List<string> ErrorMessages { get; set; } = new List<string>();
public List<string> WarningMessages { get; set; } = new List<string>();
public List<string> RemarkMessages { get; set; } = new List<string>();

public abstract FuncAttribute Metadata { get; set; }
public abstract Organisation Organisation { get; set; }
public virtual Attribute[] GetAllInputAttributes() { return Array.Empty<Attribute>(); }
Expand Down
16 changes: 14 additions & 2 deletions AdSecCore/Functions/ParametersGeneric.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
using Oasys.AdSec;
using System;

using Oasys.AdSec;
using Oasys.AdSec.DesignCode;
using Oasys.AdSec.Mesh;
using Oasys.Profiles;
Expand Down Expand Up @@ -38,6 +40,11 @@ public class SectionSolution {
public IServiceability Serviceability => Solution.Serviceability;
}

public class CrackLoad {
public ICrack Load { get; set; }
public OasysPlane Plane { get; set; } = OasysPlane.PlaneYZ;
}

public class DoubleParameter : ParameterAttribute<double> { }
public class DoubleArrayParameter : BaseArrayParameter<double> { }
public class IntegerArrayParameter : BaseArrayParameter<int> { }
Expand All @@ -58,7 +65,12 @@ public class SubComponent {

public class IntegerParameter : ParameterAttribute<int> { }
public class LoadParameter : ParameterAttribute<ILoad> { }
public class CrackParameter : ParameterAttribute<ICrack> { }
public class CrackParameter : ParameterAttribute<CrackLoad> { }
public class DeformationParameter : ParameterAttribute<IDeformation> { }
public class GenericParameter : ParameterAttribute<object> { }
public class CrackArrayParameter : BaseArrayParameter<CrackLoad> { }
public class SecantStiffnessParameter : ParameterAttribute<IStiffness> { }
public class IntervalArrayParameter : BaseArrayParameter<Tuple<double, double>> { }


}
175 changes: 175 additions & 0 deletions AdSecCore/Functions/SlsResultFunction.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@

using System;
using System.Collections.Generic;

using AdSecGHCore.Constants;

using Oasys.AdSec;

using OasysUnits;
using OasysUnits.Units;

namespace AdSecCore.Functions {
public class SlsResultFunction : Function {

public SectionSolutionParameter SolutionInput { get; set; } = new SectionSolutionParameter {
Name = "Results",
NickName = "Res",
Description = "AdSec Results to perform serviceability check",
Access = Access.Item,
Optional = false,
};

public GenericParameter LoadInput { get; set; } = new GenericParameter {
Name = "Load",
NickName = "Ld",
Description = "AdSec Load (Load or Deformation) for which the strength results are to be calculated.",
Access = Access.Item,
Optional = false,
};

public LoadParameter LoadOutput { get; set; } = new LoadParameter {
Name = "Load",
NickName = "Ld",
Description = $"The section load under the applied action.{Environment.NewLine}If the applied deformation is outside the capacity range of the section, the returned load will be zero.",
Access = Access.Item,
Optional = false,
};

public CrackArrayParameter CrackOutput { get; set; } = new CrackArrayParameter {
Name = "Cracks",
NickName = "Crks",
Description = $"Crack results are calculated at bar positions or section surfaces depending on the Design Code specifications.{Environment.NewLine}If the applied action is outside the capacity range of the section, the returned list will be empty. See MaximumCrack output for the crack result corresponding to the maximum crack width.",
Access = Access.List,
};

public CrackParameter MaximumCrackOutput { get; set; } = new CrackParameter {
Name = "MaximumCrack",
NickName = "MaxCrk",
Description = $"Crack results are calculated at bar positions or section surfaces depending on the Design Code specifications.{Environment.NewLine}If the applied action is outside the capacity range of the section, the returned list will be empty. See MaximumCrack output for the crack result corresponding to the maximum crack width.",
Access = Access.Item,
};

public DoubleParameter CrackUtilOutput { get; set; } = new DoubleParameter {
Name = "CrackUtil",
NickName = "Uc",
Description = $"The ratio of the applied load (moment and axial) to the load (moment and axial) in the same direction that would cause the section to crack. Ratio > 1 means section is cracked.{Environment.NewLine}The section is cracked when the cracking utilisation ratio is greater than 1. If the applied load is outside the capacity range of the section, the cracking utilisation will be maximum double value.",
Access = Access.Item,
};

public DeformationParameter DeformationOutput { get; set; } = new DeformationParameter {
Name = "Deformation",
NickName = "Def",
Description = "The section deformation under the applied action",
Access = Access.Item,
};

public SecantStiffnessParameter SecantStiffnessOutput { get; set; } = new SecantStiffnessParameter {
Name = "SecantStiffness",
NickName = "Es",
Description = "The secant stiffness under the applied action",
Access = Access.Item,
};

public IntervalArrayParameter UncrackedMomentRangesOutput { get; set; } = new IntervalArrayParameter {
Name = "Uncracked Moment Ranges",
NickName = "Mrs",
Description = "The range of moments",
Access = Access.List,
};

public override FuncAttribute Metadata { get; set; } = new FuncAttribute {
Name = "Find Crack Load",
NickName = "CrackLd",
Description = "Increases the load until set crack width is reached",
};

public override Organisation Organisation { get; set; } = new Organisation {
Category = CategoryName.Name(),
SubCategory = SubCategoryName.Cat7(),
};


public override Attribute[] GetAllInputAttributes() {
return new Attribute[] {
SolutionInput,
LoadInput,
};

}

public override Attribute[] GetAllOutputAttributes() {
return new Attribute[] {
LoadOutput,
CrackOutput,
MaximumCrackOutput,
CrackUtilOutput,
DeformationOutput,
SecantStiffnessOutput,
UncrackedMomentRangesOutput
};
}

public void DeformationDescription(StrainUnit strainUnit, CurvatureUnit curvatureUnit) {
var strainAbbreviation = Strain.GetAbbreviation(strainUnit);
var curvatureAbbreviation = $"{strainAbbreviation}{Curvature.GetAbbreviation(curvatureUnit)}";
DeformationOutput.Description = $"The section deformation under the applied action. The output is a vector representing:{Environment.NewLine}X: Strain [{strainAbbreviation}]{Environment.NewLine}Y: Curvature around zz (so in local y-direction) [{curvatureAbbreviation}]{Environment.NewLine}Z: Curvature around yy (so in local z-direction) [{curvatureAbbreviation}]";
}

public void SecantStiffnessDescription(AxialStiffnessUnit axialUnit, BendingStiffnessUnit bendingUnit) {
SecantStiffnessOutput.Description = $"The secant stiffness under the applied action. The output is a vector representing:{Environment.NewLine}X: Axial stiffness [{AxialStiffness.GetAbbreviation(axialUnit)}],{Environment.NewLine}Y: The bending stiffness about the y-axis in the local coordinate system [{BendingStiffness.GetAbbreviation(bendingUnit)}],{Environment.NewLine}Z: The bending stiffness about the z-axis in the local coordinate system [{BendingStiffness.GetAbbreviation(bendingUnit)}]";
}

public void UncrackedMomentRangesDescription(MomentUnit momentUnit) {
UncrackedMomentRangesOutput.Description = $"The range of moments (in the direction of the applied moment, assuming constant axial force) over which the section remains uncracked. Moment values are in [{Moment.GetAbbreviation(momentUnit)}]";
}

public override void Compute() {
var momentUnit = ContextUnits.Instance.MomentUnit;
// get solution input
var solution = SolutionInput.Value;
IServiceabilityResult sls = null;
switch (LoadInput.Value) {
case ILoad load:
sls = solution.Serviceability.Check(load);
break;
case IDeformation deformation:
sls = solution.Serviceability.Check(deformation);
break;
default:
ErrorMessages.Add("Invalid Load Input");
return;
}

LoadOutput.Value = sls.Load;
DeformationOutput.Value = sls.Deformation;


var cracks = new List<CrackLoad>();
foreach (var crack in sls.Cracks) {
cracks.Add(new CrackLoad() { Load = crack, Plane = solution.SectionDesign.LocalPlane });
}
CrackOutput.Value = cracks.ToArray();

MaximumCrackOutput.Value = new CrackLoad() { Load = sls.MaximumWidthCrack, Plane = solution.SectionDesign.LocalPlane };
CrackUtilOutput.Value = sls.CrackingUtilisation.As(RatioUnit.DecimalFraction);
if (CrackUtilOutput.Value > 1) {
if (CrackOutput.Value.Length == 0) {
WarningMessages.Add("The section is failing and the cracks are so large we can't even compute them!");
} else {
RemarkMessages.Add("The section is cracked");
}
}
DeformationOutput.Value = sls.Deformation;
SecantStiffnessOutput.Value = sls.SecantStiffness;

var momentRanges = new List<Tuple<double, double>>();
foreach (var range in sls.UncrackedMomentRanges) {
var interval = new Tuple<double, double>(range.Min.As(momentUnit), range.Max.As(momentUnit));
momentRanges.Add(interval);
}
UncrackedMomentRangesOutput.Value = momentRanges.ToArray();
}
}

}
100 changes: 100 additions & 0 deletions AdSecCoreTests/SlsResultFunctionTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
using AdSecCore;
using AdSecCore.Builders;
using AdSecCore.Functions;

using Oasys.AdSec;

using OasysUnits;
using OasysUnits.Units;

namespace AdSecCoreTests.Functions {
public class SlsResultFunctionTest {
private readonly SlsResultFunction _component;
private static SectionSolution? Solution { get; set; } = null;
public SlsResultFunctionTest() {
_component = new SlsResultFunction();
if (Solution == null) {
Solution = new SolutionBuilder().Build();
}
_component.SolutionInput.Value = Solution;
_component.LoadInput.Value = ILoad.Create(Force.FromKilonewtons(100), Moment.FromKilonewtonMeters(100), Moment.Zero);
}

[Fact]
public void ShouldHaveCorrectMetadata() {
Assert.Equal("Find Crack Load", _component.Metadata.Name);
Assert.Equal("CrackLd", _component.Metadata.NickName);
Assert.Equal("Increases the load until set crack width is reached", _component.Metadata.Description);
}


[Fact]
public void ShouldHaveCorrectInputAttributes() {
var inputs = _component.GetAllInputAttributes();
Assert.Equal(2, inputs.Length);
Assert.IsType<SectionSolutionParameter>(inputs[0]);
Assert.IsType<GenericParameter>(inputs[1]);
}

[Fact]
public void ShouldHaveCorrectOutputAttributes() {
var outputs = _component.GetAllOutputAttributes();
Assert.Equal(7, outputs.Length);
Assert.IsType<LoadParameter>(outputs[0]);
Assert.IsType<CrackArrayParameter>(outputs[1]);
Assert.IsType<CrackParameter>(outputs[2]);
Assert.IsType<DoubleParameter>(outputs[3]);
Assert.IsType<DeformationParameter>(outputs[4]);
Assert.IsType<SecantStiffnessParameter>(outputs[5]);
Assert.IsType<IntervalArrayParameter>(outputs[6]);
}

[Fact]
public void ShoulHaveValidDeformationDescription() {
_component.DeformationDescription(StrainUnit.Ratio, CurvatureUnit.PerMeter);
var description = _component.DeformationOutput.Description;
Assert.Contains("[εm⁻¹]", description);
Assert.Contains("[εm⁻¹]", description);
}

[Fact]
public void ShouldHaveValidSecantStiffnessDescription() {
_component.SecantStiffnessDescription(AxialStiffnessUnit.Newton, BendingStiffnessUnit.NewtonSquareMeter);
var description = _component.SecantStiffnessOutput.Description;
Assert.Contains("[N]", description);
Assert.Contains("[N·m²]", description);
Assert.Contains("[N·m²]", description);
}

[Fact]
public void ShouldHaveValidUncrackedMomentRangesDescription() {
_component.UncrackedMomentRangesDescription(MomentUnit.NewtonMeter);
Assert.Contains("[N·m]", _component.UncrackedMomentRangesOutput.Description);
}

[Fact]
public void ShouldComputeCorrectly() {
_component.Compute();
var expectedLoad = ILoad.Create(Force.FromKilonewtons(100), Moment.FromKilonewtonMeters(100), Moment.Zero);
var expectedDeformation = IDeformation.Create(Strain.FromRatio(0.0014), Curvature.FromPerMeters(0.0064), Curvature.FromPerMeters(0.0029));
Assert.True(IsLoadEqual(expectedLoad, _component.LoadOutput.Value));
Assert.True(IsDeformationEqual(expectedDeformation, _component.DeformationOutput.Value));
Assert.Equal(0.00208, _component.MaximumCrackOutput.Value.Load.Width.Value, new DoubleComparer());
Assert.Equal(5.8156, _component.CrackUtilOutput.Value, new DoubleComparer());
Assert.Single(_component.RemarkMessages);
Assert.Equal(69, _component.CrackOutput.Value.Length);
}

private static bool IsLoadEqual(ILoad expected, ILoad calculated) {
return expected.X.Value.Equals(calculated.X.Value) && expected.YY.Value.Equals(calculated.YY.Value) && expected.ZZ.Value.Equals(calculated.ZZ.Value);
}

private static bool IsDeformationEqual(IDeformation expected, IDeformation calculated) {
var tolernaceStrain = Strain.FromRatio(0.00001);
var tolernaceCurvature = Curvature.FromPerMeters(0.0001);
return expected.X.Equals(calculated.X, tolernaceStrain) && expected.YY.Equals(calculated.YY, tolernaceCurvature) && expected.ZZ.Equals(calculated.ZZ, tolernaceCurvature);
}


}
}
Loading
Loading