Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using Microsoft.Extensions.DependencyInjection;
using Speckle.Converters.CSiShared.ToSpeckle.Helpers;
using Speckle.Converters.CSiShared.Utils;

namespace Speckle.Connectors.CSiShared.HostApp.Helpers;

Expand All @@ -15,7 +16,12 @@ public CsiResultsExtractorFactory(IServiceProvider serviceProvider)
public IApplicationResultsExtractor GetExtractor(string resultsKey) =>
resultsKey switch
{
"FrameForces" => _serviceProvider.GetRequiredService<CsiFrameForceResultsExtractor>(),
ResultsKey.BASE_REACT => _serviceProvider.GetRequiredService<CsiBaseReactResultsExtractor>(),
ResultsKey.FRAME_FORCES => _serviceProvider.GetRequiredService<CsiFrameForceResultsExtractor>(),
ResultsKey.JOINT_REACT => _serviceProvider.GetRequiredService<CsiJointReactResultsExtractor>(),
ResultsKey.PIER_FORCES => _serviceProvider.GetRequiredService<CsiPierForceResultsExtractor>(),
ResultsKey.SPANDREL_FORCES => _serviceProvider.GetRequiredService<CsiSpandrelForceResultsExtractor>(),
ResultsKey.STORY_DRIFTS => _serviceProvider.GetRequiredService<CsiStoryDriftsResultsExtractor>(),
_ => throw new InvalidOperationException($"{resultsKey} not accounted for in CsiResultsExtractorFactory")
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ CancellationToken cancellationToken
foreach (var resultType in requestedResultTypes)
{
var extractor = _resultsExtractorFactory.GetExtractor(resultType);
var objectNames = objectSelectionSummary[extractor.TargetObjectType];
objectSelectionSummary.TryGetValue(extractor.TargetObjectType, out var objectNames);
analysisResults[extractor.ResultsKey] = extractor.GetResults(objectNames);
}
rootObjectCollection["analysisResults"] = analysisResults;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using Speckle.Connectors.DUI.Settings;
using Speckle.Converters.CSiShared.Utils;

namespace Speckle.Connectors.CSiShared.Settings;

Expand All @@ -8,5 +9,5 @@ public class ResultTypeSetting(List<string> values) : ICardSetting
public string? Title { get; set; } = "Result Type";
public string? Type { get; set; } = "array";
public object? Value { get; set; } = values;
public List<string>? Enum { get; set; } = ["FrameForces"];
public List<string>? Enum { get; set; } = ResultsKey.All.OrderBy(x => x).ToList();
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,21 @@ public static IServiceCollection AddCsiConverters(this IServiceCollection servic

// Register property extractors
serviceCollection.AddScoped<CsiFramePropertiesExtractor>();
serviceCollection.AddScoped<CsiFrameForceResultsExtractor>();
serviceCollection.AddScoped<CsiJointPropertiesExtractor>();
serviceCollection.AddScoped<CsiShellPropertiesExtractor>();
serviceCollection.AddScoped<DatabaseTableExtractor>();
serviceCollection.AddScoped<DisplayValueExtractor>();
serviceCollection.AddScoped<ResultsArrayProcessor>();
serviceCollection.AddScoped<SharedPropertiesExtractor>();

// Register results extractors
serviceCollection.AddScoped<CsiBaseReactResultsExtractor>();
serviceCollection.AddScoped<CsiFrameForceResultsExtractor>();
serviceCollection.AddScoped<CsiJointReactResultsExtractor>();
serviceCollection.AddScoped<CsiPierForceResultsExtractor>();
serviceCollection.AddScoped<CsiSpandrelForceResultsExtractor>();
serviceCollection.AddScoped<CsiStoryDriftsResultsExtractor>();
serviceCollection.AddScoped<ResultsArrayProcessor>();

// Register connector caches
serviceCollection.AddScoped<CsiToSpeckleCacheSingleton>();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,15 @@
<Compile Include="$(MSBuildThisFileDirectory)Extensions\SpeckleApplicationIdExtensions.cs" />
<Compile Include="$(MSBuildThisFileDirectory)GlobalUsing.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ServiceRegistration.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ToSpeckle\Helpers\CsiBaseReactResultsExtractor.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ToSpeckle\Helpers\CsiFrameForceResultsExtractor.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ToSpeckle\Helpers\CsiFramePropertiesExtractor.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ToSpeckle\Helpers\CsiJointPropertiesExtractor.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ToSpeckle\Helpers\CsiJointReactResultsExtractor.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ToSpeckle\Helpers\CsiPierForceResultsExtractor.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ToSpeckle\Helpers\CsiShellPropertiesExtractor.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ToSpeckle\Helpers\CsiSpandrelForceResultsExtractor.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ToSpeckle\Helpers\CsiStoryDriftsResultsExtractor.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ToSpeckle\Helpers\CsiToSpeckleCacheSingleton.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ToSpeckle\Helpers\DatabaseTableExtractor.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ToSpeckle\Helpers\IApplicationResultsExtractor.cs" />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
using Speckle.Converters.Common;
using Speckle.Converters.CSiShared.Utils;

namespace Speckle.Converters.CSiShared.ToSpeckle.Helpers;

public class CsiBaseReactResultsExtractor : IApplicationResultsExtractor
{
private readonly IConverterSettingsStore<CsiConversionSettings> _settingsStore;
private readonly ResultsArrayProcessor _resultsArrayProcessor;

public string ResultsKey => "baseReact";
public ModelObjectType TargetObjectType => ModelObjectType.JOINT;
public ResultsConfiguration Configuration { get; } =
new(["LoadCase", "Wrap:StepNum"], ["FX", "FY", "FZ", "MX", "ParamMy", "MZ"]);

public CsiBaseReactResultsExtractor(
IConverterSettingsStore<CsiConversionSettings> settingsStore,
ResultsArrayProcessor resultsArrayProcessor
)
{
_settingsStore = settingsStore;
_resultsArrayProcessor = resultsArrayProcessor;
}

// NOTE: since these are global reactions, they're independent of the user selection, therefore discarded
public Dictionary<string, object> GetResults(IEnumerable<string>? _)
{
// Step 1: define api variables
int numberResults = 0;
string[] loadCase = [],
stepType = [];
double[] stepNum = [],
fx = [],
fy = [],
fz = [],
mx = [],
paramMy = [],
mz = [];
double gx = 0,
gy = 0,
gz = 0;

// Step 2: api call
int success = _settingsStore.Current.SapModel.Results.BaseReact(
ref numberResults,
ref loadCase,
ref stepType,
ref stepNum,
ref fx,
ref fy,
ref fz,
ref mx,
ref paramMy,
ref mz,
ref gx,
ref gy,
ref gz
);

if (success != 0 || numberResults == 0)
{
throw new InvalidOperationException("Base reaction extraction failed."); // shouldn't fail silently
}

// Step 3: organise arrays for dictionary processor
var rawArrays = new Dictionary<string, object>
{
["LoadCase"] = loadCase,
["StepNum"] = stepNum,
["FX"] = fx,
["FY"] = fy,
["FZ"] = fz,
["MX"] = mx,
["ParamMy"] = paramMy,
["MZ"] = mz
};

// Step 4: return sorted and processed dictionary
var resultsDictionary = _resultsArrayProcessor.ProcessArrays(rawArrays, Configuration);

// Step 5: add the extra centroid information
resultsDictionary["GX"] = gx;
resultsDictionary["GY"] = gy;
resultsDictionary["GZ"] = gz;

// Step 6: return
return resultsDictionary;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ public sealed class CsiFrameForceResultsExtractor : IApplicationResultsExtractor
private readonly IConverterSettingsStore<CsiConversionSettings> _settingsStore;
private readonly ResultsArrayProcessor _resultsArrayProcessor;

public string ResultsKey => "FrameForces";
public string ResultsKey => "frameForces";
public ModelObjectType TargetObjectType => ModelObjectType.FRAME;

public ResultsConfiguration Configuration { get; } =
Expand All @@ -29,22 +29,22 @@ public Dictionary<string, object> GetResults(IEnumerable<string>? objectNames =
var frameNames = objectNames?.ToList();
if (frameNames is null || frameNames.Count == 0)
{
throw new InvalidOperationException("Frame names are required for force extraction");
throw new InvalidOperationException("Frame(s) are required in the selection for results extraction");
}

// Step 2: single dictionary to accumulate all results
var allArrays = new Dictionary<string, List<object>>
{
["Elm"] = new(),
["ElmSta"] = new(),
["LoadCase"] = new(),
["StepNum"] = new(),
["P"] = new(),
["V2"] = new(),
["V3"] = new(),
["T"] = new(),
["M2"] = new(),
["M3"] = new()
["Elm"] = [],
["ElmSta"] = [],
["LoadCase"] = [],
["StepNum"] = [],
["P"] = [],
["V2"] = [],
["V3"] = [],
["T"] = [],
["M2"] = [],
["M3"] = []
};

// Step 3: define api variables
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
using Speckle.Converters.Common;
using Speckle.Converters.CSiShared.Utils;

namespace Speckle.Converters.CSiShared.ToSpeckle.Helpers;

public class CsiJointReactResultsExtractor : IApplicationResultsExtractor
{
private readonly IConverterSettingsStore<CsiConversionSettings> _settingsStore;
private readonly ResultsArrayProcessor _resultsArrayProcessor;

public string ResultsKey => "jointReact";
public ModelObjectType TargetObjectType => ModelObjectType.JOINT;
public ResultsConfiguration Configuration { get; } =
new(["Elm", "LoadCase", "Wrap:StepNum"], ["F1", "F2", "F3", "M1", "M2", "M3"]);

public CsiJointReactResultsExtractor(
IConverterSettingsStore<CsiConversionSettings> settingsStore,
ResultsArrayProcessor resultsArrayProcessor
)
{
_settingsStore = settingsStore;
_resultsArrayProcessor = resultsArrayProcessor;
}

public Dictionary<string, object> GetResults(IEnumerable<string>? objectNames = null)
{
// Step 1: validate input
var jointNames = objectNames?.ToList();
if (jointNames is null || jointNames.Count == 0)
{
throw new InvalidOperationException("Joint(s) are required in the selection for results extraction");
}

// Step 2: single dictionary to accumulate all results
var allArrays = new Dictionary<string, List<object>>
{
["Elm"] = [],
["LoadCase"] = [],
["StepNum"] = [],
["F1"] = [],
["F2"] = [],
["F3"] = [],
["M1"] = [],
["M2"] = [],
["M3"] = []
};

// Step 3: define api variables
int numberResults = 0;
string[] obj = [],
elm = [],
loadCase = [],
stepType = [];
double[] stepNum = [],
f1 = [],
f2 = [],
f3 = [],
m1 = [],
m2 = [],
m3 = [];

// Step 4: iterate through objectNames and get joint reaction results for those that are assigned restraints / springs and grounded
foreach (string jointName in jointNames)
{
// this only works if the joint has restraints or springs assignments, so check if it's a valid query first
bool[] restraints = [];
string springAssignment = string.Empty;
_settingsStore.Current.SapModel.PointObj.GetRestraint(jointName, ref restraints);
_settingsStore.Current.SapModel.PointObj.GetSpringAssignment(jointName, ref springAssignment);
if (restraints.All(r => !r) && string.IsNullOrEmpty(springAssignment))
{
continue; // skip this joint - it has neither restraints nor springs
}

int success = _settingsStore.Current.SapModel.Results.JointReact(
jointName,
eItemTypeElm.ObjectElm,
ref numberResults,
ref obj,
ref elm,
ref loadCase,
ref stepType,
ref stepNum,
ref f1,
ref f2,
ref f3,
ref m1,
ref m2,
ref m3
);

if (success != 0)
{
throw new InvalidOperationException($"Joint force extraction failed for frame {jointName}."); // shouldn't fail silently
}

// accumulate results
allArrays["Elm"].AddRange(elm.Cast<object>());
allArrays["LoadCase"].AddRange(loadCase.Cast<object>());
allArrays["StepNum"].AddRange(stepNum.Cast<object>());
allArrays["F1"].AddRange(f1.Cast<object>());
allArrays["F2"].AddRange(f2.Cast<object>());
allArrays["F3"].AddRange(f3.Cast<object>());
allArrays["M1"].AddRange(m1.Cast<object>());
allArrays["M2"].AddRange(m2.Cast<object>());
allArrays["M3"].AddRange(m3.Cast<object>());
}

// Step 5: organise arrays for dictionary processor
var rawArrays = allArrays.ToDictionary(kvp => kvp.Key, kvp => (object)kvp.Value.ToArray());

// Step 6: return sorted and processed dictionary
return _resultsArrayProcessor.ProcessArrays(rawArrays, Configuration);
}
}
Loading
Loading