Example API Connection Optimization with Templates and Parameters - idea-statica/ideastatica-public GitHub Wiki
Status: 👷♂️ Work In Progress
Example Aim
The aim of this example is to provide an insight into how operation parameters can be used to optimize many 'instances' of the same connection type through the use of connection templates and user-defined operation parameters. We will look at using the IDEAStatiCa ConnectionHiddenCheckClient API to iteratively modify connection parameters in order to get to an optimized/desired solution.
In this example, we will look at optimizing multiple weld sizes for a Tube - Tube - Tube Connection as shown below.
Background
IDEA StatiCa allows the ability to control specific operation parameters values through the use of 'user-defined' operation parameters. This enables a simple approach to enable optimization of connection through the manipulation of specific parameters using the IDEAStatiCa Plugin API.
Templates now also can contain and pass these parameters to any Connection file they are applied to. This provides an extreme advantage in the instance where a lot of similar connections share similar operations, although may have slightly different loading or section sizing. Instead of having to create and assign the parameters individually they can automatically be set and defined through the use of a template.
Reference Model and Template
1. Define the Connection Operations
2. Setting Manual Parameters
In this example, we will set parameters for each of the weld thicknesses for the two accompanying welds.
Currently, parameters must be manually set in a connection project.
For information on setting an .ideaCon project parameters please see this guide. The Operation Parameter Reference Guide can also be used to provide information on more complex parameter referencing and generation.
3. Export the Template
Currently, you can export a template when in developer mode (User mode 16).
Use the provided button to export the template to a .ideaConTemp file.
Simple Optimization Procedure
We will now create the simple optimization procedure using c# code and the ConnectionHiddenCheckClient. This is a simple representation of how you can perform this procedure.
The code below has been simplified for the example. It can be modulated to enable class-specific optimization procedures that can be stored and used as required.
1. Read the available parameters from the Template File
This step is only required if the user wants to read and set values of the parameters in an external program without the need to open the Connection Project through the API prior to setting up an optimization procedure.
2. Define the Parameter/s to Optimize
In this example, we set an OptimisationParameter
. This is a parameter that will change as we look for the desired solution.
The abstract class OptimizationParameter
will store the imported parameter. The constructor allows for the parameter to be created prior to the Connection file being opened by using a SearchName
.
When the file is opened and the parameters in the file are extracted a search is performed to ensure the parameter is present in the file prior to continuing. The OptimizationParameter
class also serves as a wrapper to retrieve information about the defined parameter.
public abstract class OptimizationParameter
{
protected Parameter parameter;
public bool optimized = false;
public string Name
{
get { return parameter.identifier; }
}
public double Value
{
get { return Double.Parse(parameter.value); }
}
public int Index
{
get { return (parameter.id - 1); }
}
public string SearchName;
public OptimizationParameter(string paramName)
{
SearchName = paramName;
}
internal bool FindandSetParameter(Parameter[] parametersToSearch)
{
try
{
parameter = parametersToSearch.FirstOrDefault(x => String.Compare(x.identifier, SearchName, true) == 0);
return true;
}
catch
{
throw new Exception("Search Parameter not found in avaliable Project Parmeters");
}
}
}
We can now define additional classes relating to particular optimization parameters. This defines specifics on how a certain parameter is to be updated as we loop through an optimisation procedure. We can also set here a reference to how the outputed result will affect the optimization.
Here a WeldThicknessOptiziationParameter
class is created. In the constructor, we provide an index to the weldResultRef. This is the index of the weld result which directly relates to the weld thickness parameter we have defined.
Referencing weld results need to be achieved manually, and hopefully can be improved in the future.
Methods of setInitial() and Increment() are added to the WeldThicknessOptiziationParameter
which serve to update the stored user-defined parameter.
public class WeldThinknessOptimizationParameter : OptimizationParameter //inheret for the serialation
{
public int ConnectionResultWeldRef;
public WeldThinknessOptimizationParameter(string paramName, int weldResultRef) : base(paramName)
{
ConnectionResultWeldRef = weldResultRef;
}
public override SimpleResult ExtractReferenceResult(ConnectionCheckRes connectionResult)
{
List<CheckResWeld> weldResults = connectionResult.CheckResWeld;
try
{
CheckResWeld weldResult = weldResults[ConnectionResultWeldRef];
return new SimpleResult(weldResult.CheckStatus, weldResult.UnityCheck);
}
catch
{
throw new Exception("Weld Result not Avaliable");
}
}
public void SetInitial(double start)
{
parameter.value = start.ToString();
}
public void Increment(double increment)
{
parameter.value = (Value + increment).ToString();
}
}
Serialising Parameters
In the above OptimizationParameter
class parameters are stored as deserialized objects. This allows us to complete changes to the retrieved parameters easily before Applying them. Below is the Parameter
class used to deserialize project parameters.
Some parameter types will provide a second level JSON string as the value, This can also be deserialized as #########.
For more information on the serialization of user-defined parameters refer [here].
public class Parameter
{
public int id { get; set; }
public string identifier { get; set; }
public string description { get; set; }
public string parameterType { get; set; }
public string value { get; set; }
}
Running the Optimization
Now we have the basis for running our optimization we can pull it all together to set up a simple optimization procedure.
We can use some of the available features of the IDEA API to Save to the project at each step.
class Program
{
static void Main(string[] args)
{
string ideaStaticaInstallDir = args[0];
// create the instance of the factory
ConnHiddenClientFactory calcFactory = new ConnHiddenClientFactory(ideaStaticaInstallDir);
//create the instance of the IDEA StatiCa Client
ConnectionHiddenCheckClient client = calcFactory.Create();
//Gets paths of resource in project.
string RunningPath = AppDomain.CurrentDomain.BaseDirectory;
string IdeaConFileName = string.Format("{0}Resources\\Tube-Tube Weld Optimisation.ideaCon", Path.GetFullPath(Path.Combine(RunningPath, @"..\..\")));
//path to executing assembly bin folder
Assembly assembly = Assembly.GetExecutingAssembly();
string baseConFileDirectory = Path.GetDirectoryName(assembly.Location);
try
{
//Open project
client.OpenProject(IdeaConFileName);
try
{
ConnectionInfo conInfo = client.GetProjectInfo().Connections.First();
string conIdentifier = conInfo.Identifier;
//Set the Optimization Parameters - No API interaction Required
List<WeldThinknessOptimizationParameter> weldParamsToOpt = new List<WeldThinknessOptimizationParameter>();
weldParamsToOpt.Add(new WeldThinknessOptimizationParameter("ColWeld", 0));
weldParamsToOpt.Add(new WeldThinknessOptimizationParameter("ChordWeld", 1));
//Parameter Store
Parameter[] projectParameters;
//Get Project Parameters JSON String
string conParamsJson = client.GetParametersJSON(conInfo.Identifier);
//Deserialize Parameters
projectParameters = JsonConvert.DeserializeObject<Parameter[]>(conParamsJson);
//Search and Set Parameters to Optimization Params
foreach (var weldParam in weldParamsToOpt)
weldParam.FindandSetParameter(projectParameters);
//Set Weld Thickness Optimization Values
double startValue = 0.003; //Start Weld Thickness
double incrementValue = 0.0005; //Increment Value - Values to Increment
double maxValue = 0.01; //Max Value of Weld Thickness
//Set Optimisation Options
bool saveIterations = true;
int maxIterations = 5;
//Perform Optimization
onsole.WriteLine(string.Format("Starting Optimization Procedure"));
for (int iteration = 0; iteration < maxIterations; iteration++)
{
Console.WriteLine(string.Format("Optimization Iteration {0}", iteration + 1));
//If first run, set initial values else increment. Stop if max weld size is hit.
if (iteration == 0)
foreach (var parameter in weldParamsToOpt)
parameter.SetInitial(startValue);
else
foreach (var parameter in weldParamsToOpt)
if (!parameter.optimized)
if (parameter.Value < maxValue)
parameter.Increment(incrementValue);
else
Console.WriteLine(string.Format("Max Value of Weld Hit. Optimization Stopped"));
Console.WriteLine("Trying Parameter Values:");
foreach (var parameter in weldParamsToOpt)
Console.WriteLine(parameter.Name + ": Is Optimized = " + parameter.optimized + ", Weld Thickness = " + parameter.Value);
//serialize updated parameters
string updatedParameters = JsonConvert.SerializeObject(projectParameters);
//apply updated parameters to project
client.ApplyParameters(conIdentifier, updatedParameters);
//calculate the connection with new parameters
ConnectionResultsData results = client.Calculate(conIdentifier);
//Get first connection result from result Data
ConnectionCheckRes ConCheckRes = results.ConnectionCheckRes[0];
//Check parameters and set whether optimised
foreach (var parameter in weldParamsToOpt)
{
//Get status of directly referenced weld result
bool status = parameter.ExtractReferenceResult(ConCheckRes);
parameter.optimized = status;
Console.WriteLine(parameter.Name + ": Is Optimised = " + parameter.optimized + ", Weld Thickness = " + parameter.Value);
}
//Choose to save each Iteration results
if (saveIterations)
{
string filepath = Path.Combine(baseConFileDirectory, string.Format("Tube-Tube-WeldOptimisation_{0}.ideaCon", iteration+1));
client.SaveAsProject(filepath);
}
//Exit Optimisation Conditions
bool exitOptimization = false;
foreach (var opParam in weldParamsToOpt)
{
if (!opParam.optimized)
break;
exitOptimization = true;
}
if (exitOptimization)
{
//client.Save();
break;
}
}
}
finally
{
client.CloseProject();
}
}
finally
{
if (client != null)
client.Close();
}
Console.WriteLine("End");
}
}
Further Information
The ability to add parameters to a project and then modify them through an optimization loop provides an endless amount of ways to start looking at ways you can optimize connection designs. Here we have looked at a rather simple example here. Mainly because there is a direct relationship between the weld size and the design. We can push these optimization parameters further to understand how other components may interact with other changes in the connection. For example, if a section size is changed, how does that affect the bolt force? Or weld design? Or both.
We will continue to develop the Connection API to enable optimization procedures, such as the one demonstrated here. Please get in touch if you have any comments or would like to discuss further.