SolidWorks Simulation API - AddForce3

I have a cylinder and I have created a circular face using warp tool. I want simulate the cylinder for displacement and in this step, I want to apply force on the circular face I have selected. I want to apply uniform force in the Z direction of the coordinate system about 400N. When I run this code, I got error code 6 for the AddForce3. Could someone please help me? I did this in C#. I’m initially trying with one face and force. I will make it with multiple face and force when this works out. I gave the image of the cylinder below.

using SldWorks;
using SolidWorks.Interop.cosworks;
using SolidWorks.Interop.sldworks;
using SolidWorks.Interop.swconst;
using System;
using System.IO;
using System.Threading;
using ISldWorks = SolidWorks.Interop.sldworks.ISldWorks;
using ModelDoc2 = SolidWorks.Interop.sldworks.ModelDoc2;
using SelectionMgr = SolidWorks.Interop.sldworks.SelectionMgr;

class Program
{
    static void Main()
    {
        Console.WriteLine("Starting SolidWorks...");
        var swApp = Activator.CreateInstance(Type.GetTypeFromProgID("SldWorks.Application")) as ISldWorks;
        if (swApp == null)
        {
            Console.WriteLine("Failed to start SolidWorks.");
            return;
        }

        swApp.Visible = true;
        Console.WriteLine("SolidWorks launched.");
        Thread.Sleep(5000);

        string partFilePath = @"C:\Users\Student\Tasks\API Tasks\L1_4 Task07.SLDPRT";
        if (!System.IO.File.Exists(partFilePath))
        {
            Console.WriteLine("File not found: " + partFilePath);
            return;
        }

        int errors = 0, warnings = 0;
        ModelDoc2 model = swApp.OpenDoc6(partFilePath,
                                         (int)swDocumentTypes_e.swDocPART,
                                         (int)swOpenDocOptions_e.swOpenDocOptions_Silent,
                                         "", ref errors, ref warnings);

        if (model == null)
        {
            Console.WriteLine("Failed to open part file.");
            return;
        }

        Console.WriteLine("Part file opened.");

        Thread.Sleep(2500);

        string simDllPath = @"C:\Program Files\SOLIDWORKS Corp\SOLIDWORKS\Simulation\cosworks.dll";
        int loadResult = swApp.LoadAddIn(simDllPath);
        Console.WriteLine($"Simulation Add-in load result: {loadResult}");

        var simAddIn = swApp.GetAddInObject("CosmosWorks.CosmosWorks") as CwAddincallback;
        if (simAddIn == null)
        {
            Console.WriteLine("Failed to load Simulation Add-in object.");
            return;
        }
            
        CosmosWorks cosmos = simAddIn.CosmosWorks;
        CWModelDoc simDoc = cosmos?.ActiveDoc;
        if (simDoc == null)
        {
            Console.WriteLine("Simulation document not active.");
            return;
        }

        Thread.Sleep(1500);

        ICWStudyManager studyMgr = simDoc.StudyManager;
        studyMgr.ActiveStudy = 0;
        CWStudy study = studyMgr.GetStudy(0);
        if (study == null)
        {
            Console.WriteLine("No study found.");
            return;
        }

        Thread.Sleep(1500);

        // ==================== APPLY FORCE LOAD ====================
        Console.WriteLine("Applying force load...");

        // Get ModelDocExtension for face selection
        object selFace = null;
        
        SelectionMgr swSelMgr = model.SelectionManager;

        model.Extension.SelectByID2("", "FACE", 4.848210781, -0.473088237, 1.944270691, false, 0, null, 0);
        selFace = (object)swSelMgr.GetSelectedObject6(1, -1);

        if (selFace == null)
        {
            Console.WriteLine("Failed to select face. Check face name.");
        }
        else
        {
            // Get Loads and Fixtures manager
            ICWLoadsAndRestraintsManager loadMgr = study.LoadsAndRestraintsManager;

            if (loadMgr == null)
            {
                Console.WriteLine("Failed to get Loads/Fixtures manager.");
            }
            else
            {
                int loadErr = 0;

                double[] data = new double[6];
                // Create the force
                data[0] = 1.0;
                data[1] = 1.0;
                data[2] = 1.0;
                data[3] = 1.0;
                data[4] = 1.0;
                data[5] = 1.0;

                object[] forceArray = { data[0], data[1], data[2], data[3], data[4], data[5] };

                CWForce force = loadMgr.AddForce3(
                    (int)swsForceType_e.swsForceTypeNormal,        // Load type: force
                    (int)swsSelectionType_e.swsSelectionFaceEdgeVertexPoint,     // Apply on faces
                    -1,                                             // No reference direction
                    0,                                              // Not table-driven
                    0,                                              // Not table-driven
                    0,                                              // No rows
                    new object[0],                                  // DistValue irrelevant
                    new object[0],                                  // ForceValue irrelevant
                    false,                                          // Uniform loading
                    false,                                          // Not a beam
                    0,                                              // No non-uniform def
                    0,                                              // No non-uniform type
                    4,                                              // Ucode: 0 = Normal
                    400.0,                                          // Force magnitude (N)
                    (forceArray),                                   // Comps array [Fx, Fy, Fz...]
                    false,                                          // FlipOrigin = false
                    false,                                          // Not curved beam
                    null,                                           // DispArray not used
                    selFace,                                        // RefGeom not used
                    false,                                          // PerUnitLength = false
                    out loadErr                                     // Error code
                );


                if (force == null || loadErr != 0)
                {
                    Console.WriteLine($"Failed to apply force. Error code: {loadErr}");
                }
                else
                {
                    Console.WriteLine("Force of 400 N in +Z applied successfully.");
                }
            }
        }

        Console.WriteLine("Done. Press any key to exit.");
        Console.ReadKey();
    }
}

Hello
We see in the doc that:
If ForceType = swsForceType_e.swsForceTypeNormal Then Specify:

  • Comps with an array of six values: [1.0, 1.0, 1.0, 1.0, 1.0, 1.0]
  • Ucode with 0
    So we should try with Ucode at 0 instead of 4.

Then the error indicates an Invalid array. It can also be the DispArray parameter which does not accept a null value.

I updated the code as below. Now I got the error code 3.

        object selFace = null;
        object selBeam = null;

        SelectionMgr swSelMgr = model.SelectionManager;

        model.Extension.SelectByID2("", "SOLIDBODY", 1.83008089, 0.343248073, 1.970325039, false, 0, null, 0);
        selBeam = (object)swSelMgr.GetSelectedObject6(1, -1);

        model.Extension.SelectByID2("", "FACE", 4.848210781, -0.473088237, 1.944270691, false, 0, null, 0);
        selFace = (object)swSelMgr.GetSelectedObject6(1, -1);

        object[] beamArray = { selBeam };

        if (selFace == null)
        {
            Console.WriteLine("Failed to select face. Check face name.");
        }
        else
        {
            // Get Loads and Fixtures manager
            ICWLoadsAndRestraintsManager loadMgr = study.LoadsAndRestraintsManager;

            if (loadMgr == null)
            {
                Console.WriteLine("Failed to get Loads/Fixtures manager.");
            }
            else
            {
                int loadErr = 0;

                double[] data = new double[6];
                // Create the force
                data[0] = 1.0;
                data[1] = 1.0;
                data[2] = 1.0;
                data[3] = 1.0;
                data[4] = 1.0;
                data[5] = 1.0;

                object[] forceArray = { data[0], data[1], data[2], data[3], data[4], data[5] };
                

                CWForce force = loadMgr.AddForce3(
                    (int)swsForceType_e.swsForceTypeNormal,        // Load type: force
                    (int)swsSelectionType_e.swsSelectionFaceEdgeVertexPoint,     // Apply on faces
                    -1,                                             // No reference direction
                    0,                                              // Not table-driven
                    0,                                              // Not table-driven
                    0,                                              // No rows
                    new object[0],                                  // DistValue irrelevant
                    new object[0],                                  // ForceValue irrelevant
                    false,                                          // Uniform loading
                    false,                                          // Not a beam
                    0,                                              // No non-uniform def
                    0,                                              // No non-uniform type
                    0,                                              // Ucode: 0 = Normal
                    400.0,                                          // Force magnitude (N)
                    (forceArray),                                   // Comps array [Fx, Fy, Fz...]
                    false,                                          // FlipOrigin = false
                    false,                                          // Not curved beam
                    (beamArray),                                    // DispArray
                    selFace,                                        // RefGeom not used
                    false,                                          // PerUnitLength = false
                    out loadErr                                     // Error code
                );

@m_blt Could you also please help me with this?

Good evening @Krishna_Prasanth_Thiruvalluvar ,

The (beamArray) parameter you pass to the AddForce3 function should be an array containing faces or edges of a Solidworks body.
In your code, this refers to the volume body itself, not its faces or edges. See the following instructions:

In your case, the easiest way to create Z-following efforts is to:

  • Select an edge or axis of Z direction, or a face of normal Z, and assign it to the ReferenceGeometry parameter.
  • select the faces that support the force, and pass them in the form of an array to the parameter (DispArray);
  • Define the uCode value as an additive combination of 1, 2, and 4, depending on the desired components. For the Z direction alone: uCode = 4;
  • define the values of the components and pass them into the array (ComponentValues) (only the first three are needed).

VBA Syntax:

Set force = loadMgr.AddForce3(swsForceTypeForceOrMoment, _
swsSelectionFaceEdgeVertexPoint, 0, 0, 0, 0, (DistanceValues), (ForceValues), _
False, False, 0, 0, 1 + 2 + 4, 0, (ComponentValues), False, False, (DispArray), _
ReferenceGeometry, False, loadErr)

Should I use only the selBeam or both selBeam and selFace be used to select the desired face to apply the normal force? I was wrong in the original question since I want a normal force acting on any face of the cylinder. Could you help me how I should proceed further?

Since it is a normal force now, UCode should be 0. What about the other parameters?

Hello

The joined macro, in VBA, creates a normal force at each of the previously selected faces on a SW body.
For the effort to be normal on each side, it is necessary to:

  • whether the effort type is swsForceTypeNormal,
  • that uCode = 0
  • that the value of the force (123.0) is passed into the TorqueNFVal parameter
  • and that ReferenceGeometry is empty.

No comments and no guarantees... :wink:

AddForce.swp (60.5 KB)

Amazing! Thank you so much. I modified the C# code based on the VBA and then I got the force applied on it.

My next task is to export the displacement at a specific point. So I tried to use GetDisplacementComponentForAllStepsAtNode Method and GetDisplacementAtPoints Method. But I couldn’t get the result as expected.

Using the GetDisplacementComponentForAllStepsAtNode Method, I found the nearest node of the point I’m interested in and then fed this node number to the method to display the displacement value at console.

Using the GetDisplacementAtPoints Method, I directly fed the coordinates of the nearest node of the point I’m interested in and then tried to display them on the console. But it also didn’t work. How can I make this possible? I’m interested in exporting the displacement values in .csv file. So I wanted to do this step.

The below code is done after the Meshing and then running the Simulation. I found the maximum and minimum displacement, then the point I want to measure the displacement is mentioned now directly in the code. I found the nearest node and tried the above mentioned methods. The code gives error code 4 when I use first method

        // Create displacement plot
        CWResults results = study.Results;
        Thread.Sleep(2000);
        if (results == null)
        {
            Console.WriteLine("No results available.");
            return;
        }

        int errCode;
        CWPlot dispPlot = results.CreatePlot(
            (int)swsPlotResultTypes_e.swsResultDisplacementOrAmplitude,
            (int)swsDisplacementComponent_e.swsDisplacementComponentURES,
            (int)swsUnit_e.swsUnitSI,
            false,
            out errCode);

        if (dispPlot == null || errCode != 0)
        {
            Console.WriteLine($"Failed to create displacement plot. Error: {errCode}");
            return;
        }
                
        // Optional: Change units to millimeters
        errCode = dispPlot.SetComponentUnitAndValueByElem(
            (int)swsDisplacementComponent_e.swsDisplacementComponentURES,
            (int)swsLinearUnit_e.swsLinearUnitMillimeters,
            false);
        if (errCode != 0)
        {
            Console.WriteLine("Failed to set units for displacement plot.");
        }

        dispPlot = results.GetPlot("Displacement1", out errCode);

        // Activate plot
        errCode = dispPlot.ActivatePlot();
        if (errCode != 0)
        {
            Console.WriteLine("Failed to activate displacement plot.");
            return;
        }
        Thread.Sleep(1500);

        object[] dispResults = (object[])dispPlot.GetMinMaxResultValues(out errCode);
        if (errCode != 0 || dispResults == null || dispResults.Length < 4)
        {
            Console.WriteLine("Failed to get displacement results.");
            return;
        }

        double minDisp = Convert.ToDouble(dispResults[1]);
        double maxDisp = Convert.ToDouble(dispResults[3]);

        Console.WriteLine($"Resultant Displacement:\n  Min: {minDisp} mm\n  Max: {maxDisp} mm");

        Thread.Sleep(1500);

        // Step 1: Get all mesh nodes
        object[] nodesRaw = (object[])mesh.GetNodes();

        double[] targetPoint = new double[] { 4500, -280, 1980 }; // millimeters

        double minDistance = double.MaxValue;
        int closestNodeId = -1;
        double[] closestNodeCoords = new double[3];

        for (int i = 0; i < nodesRaw.Length; i += 4)
        {
            int nodeId = Convert.ToInt32(nodesRaw[i]);  // Node ID

            // Coordinates as floats, cast to double
            double x = Convert.ToDouble(nodesRaw[i + 1]) * 1000.0;
            double y = Convert.ToDouble(nodesRaw[i + 2]) * 1000.0;
            double z = Convert.ToDouble(nodesRaw[i + 3]) * 1000.0;

            double dx = x - targetPoint[0];
            double dy = y - targetPoint[1];
            double dz = z - targetPoint[2];
            double distance = Math.Sqrt(dx * dx + dy * dy + dz * dz);

            if (distance < minDistance)
            {
                minDistance = distance;
                closestNodeId = nodeId;
                closestNodeCoords[0] = x;
                closestNodeCoords[1] = y;
                closestNodeCoords[2] = z;
            }
        }

        Console.WriteLine("Closest node to target point:");
        Console.WriteLine($"Node ID: {closestNodeId}");
        Console.WriteLine($"Coordinates: X = {closestNodeCoords[0]}, Y = {closestNodeCoords[1]}, Z = {closestNodeCoords[2]}");
        Console.WriteLine($"Distance to target: {minDistance} mm");

        Thread.Sleep(2000);

        // Verify we have a valid node ID
        if (closestNodeId == -1)
        {
            Console.WriteLine("No valid node found near the target point.");
            return;
        }

        object dispValuesObj = results.GetDisplacementComponentForAllStepsAtNode(
            (int)swsDisplacementComponent_e.swsDisplacementComponentURES,
            80066,
            null,
            (int)swsLinearUnit_e.swsLinearUnitMillimeters,
            out int dispErrCode
        );

        Console.WriteLine("Raw dispValuesObj output:");

        // Check for errors first
        if (dispErrCode != 0)
        {
            Console.WriteLine($"Failed to get displacement. Error code: {dispErrCode}");
            return;
        }

        // Check if we got DBNull
        if (dispValuesObj == DBNull.Value)
        {
            Console.WriteLine("No displacement data available for this node.");
            return;
        }

        // Now try to cast to Array
        Array dispArray = null;
        try
        {
            dispArray = (Array)dispValuesObj;
        }
        catch (InvalidCastException)
        {
            Console.WriteLine("Invalid data type returned. Expected array.");
            return;
        }

        if (dispArray != null && dispArray.Length > 0)
        {
            for (int i = 0; i < dispArray.Length; i++)
            {
                object value = dispArray.GetValue(i);
                Console.WriteLine($"  Index {i}: {value}");
            }
            object firstValue = dispArray.GetValue(0);
            double dispAtPoint = Convert.ToDouble(firstValue);
            Console.WriteLine(
                $"Displacement at point ({closestNodeCoords[0]}, {closestNodeCoords[1]}, {closestNodeCoords[2]}): {dispAtPoint} mm"
            );
        }
        else
        {
            Console.WriteLine("No displacement values returned (array was null or empty).");
        }

Good evening

The problem with the GetDisplacementComponentForAllStepsAtNode method is probably related to the fact that the study is static.

For the node transmitted by the NNodeNum parameter, this function is intended to return the values of the displacement, for the successive computational steps performed by the solver.
In the case of a static study, there is only one calculated step corresponding to the requested final state, and the function fails with error code 4.
Animation in the results is a simple interpolation between the initial unsolicited state and the requested final state.

If you are performing a nonlinear study, the solver performs the calculation in successive increments, with each step yielding results, and the GetDisplacementComponentForAllStepsAtNode method works and returns the displacement array...

Good afternoon,

Oh that makes sense now. But I want to do Static study and get the dispalecent in the .CSV file? So can I use GetDisplacementAtPoints Method? If yes, please help me with the code.