SolidWorks Simulation API - AddForce3

Mam walec i utworzyłem okrągłą powierzchnię za pomocą narzędzia do wypaczania. Chcę zasymulować cylinder pod kątem przemieszczenia i na tym etapie chcę przyłożyć siłę do wybranej przeze mnie powierzchni kołowej. Chcę przyłożyć jednostajną siłę w kierunku Z układu współrzędnych około 400N. Po uruchomieniu tego kodu otrzymałem kod błędu 6 dla AddForce3. Czy ktoś mógłby mi pomóc? Zrobiłem to w C#. Początkowo staram się jedną twarzą i siłą. Zrobię to z wieloma twarzami i siłą, kiedy to się uda. Poniżej podałem zdjęcie cylindra.

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();
    }
}

Witam
W dokumencie widzimy, że:
Jeśli ForceType = swsForceType_e.swsForceTypeNormal, określ:

  • Kompozycje z tablicą sześciu wartości: [1.0, 1.0, 1.0, 1.0, 1.0, 1.0]
  • Ucode z 0
    Powinniśmy więc spróbować z Ucode na 0 zamiast 4.

Następnie błąd wskazuje na nieprawidłową tablicę. Może to być również parametr DispArray , który nie akceptuje wartości null.

Zaktualizowałem kod jak poniżej. Teraz dostałem kod błędu 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 Czy mógłbyś mi również w tym pomóc?

Dobry wieczór @Krishna_Prasanth_Thiruvalluvar ,

Parametr (beamArray) przekazywany do funkcji AddForce3 powinien być tablicą zawierającą ściany lub krawędzie bryły Solidworks.
W kodzie odnosi się to do samej treści woluminu, a nie do jego powierzchni ani krawędzi. Zapoznaj się z poniższymi instrukcjami:

W Twoim przypadku najprostszym sposobem na stworzenie działań związanych z podążaniem za Z jest:

  • Wybierz krawędź lub oś o kierunku Z lub powierzchnię o normalnej wartości Z i przypisz ją do parametru ReferenceGeometry .
  • wybrać ściany, które podtrzymują siłę, i przekazać je w postaci tablicy do parametru (DispArray);
  • Zdefiniuj wartość uCode jako addytywną kombinację 1, 2 i 4, w zależności od żądanych składników. Dla samego kierunku Z: uCode = 4;
  • zdefiniuj wartości komponentów i przekaż je do tablicy (ComponentValues) (potrzebne są tylko pierwsze trzy).

Składnia VBA:

Ustaw siłę = 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)

Czy powinienem użyć tylko selBeam, czy też zarówno selBeam, jak i selFace powinny być używane do wyboru żądanej powierzchni w celu przyłożenia siły normalnej? Myliłem się w pierwotnym pytaniu, ponieważ chcę, aby normalna siła działała na dowolną powierzchnię cylindra. Czy mógłbyś mi pomóc, jak powinienem postępować dalej?

Ponieważ jest to teraz normalna siła, UCode powinna mieć wartość 0. A co z pozostałymi parametrami?

Witam

Połączone makro w języku VBA tworzy siłę normalną na każdej z poprzednio wybranych ścian na obiekcie SW.
Aby wysiłek był normalny z każdej strony, konieczne jest:

  • czy typ nakładu pracy to swsForceTypeNormal,
  • że uCode = 0
  • że wartość siły (123,0) jest przekazywana do parametru TorqueNFVal
  • i że właściwość ReferenceGeometry jest pusta.

Bez komentarzy i bez gwarancji... :wink:

AddForce.swp (60,5 KB)

Zdumiewający! Bardzo dziękuję. Zmodyfikowałem kod C# w oparciu o VBA, a następnie przyłożyłem do niego siłę.

Moim kolejnym zadaniem jest eksport przemieszczenia w określonym punkcie. Spróbowałem więc użyć metody GetDisplacementComponentForAllStepsAtNode i metody GetDisplacementAtPoints. Ale nie udało mi się uzyskać wyniku zgodnie z oczekiwaniami.

Korzystając z metody GetDisplacementComponentForAllStepsAtNode, znalazłem najbliższy węzeł punktu, który mnie interesuje, a następnie podałem ten numer węzła do metody, aby wyświetlić wartość przemieszczenia w konsoli.

Korzystając z metody GetDisplacementAtPoints, bezpośrednio wprowadziłem współrzędne najbliższego węzła interesującego mnie punktu, a następnie spróbowałem wyświetlić je na konsoli. Ale to też nie zadziałało. Jak mogę to umożliwić? Chcę wyeksportować wartości przemieszczeń w .csv pliku. Chciałem więc zrobić ten krok.

Poniższy kod jest wykonywany po utworzeniu siatki, a następnie uruchomieniu symulacji. Znalazłem maksymalne i minimalne przemieszczenie, a następnie punkt, w którym chcę zmierzyć przemieszczenie, jest teraz wymieniony bezpośrednio w kodzie. Znalazłem najbliższy węzeł i wypróbowałem wyżej wymienione metody. Kod daje kod błędu 4, gdy używam pierwszej metody

        // 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).");
        }

Dobry wieczór

Problem z metodą GetDisplacementComponentForAllStepsAtNode jest prawdopodobnie związany z tym, że badanie jest statyczne.

Dla węzła przesyłanego przez parametr NNodeNum funkcja ta jest przeznaczona do zwracania wartości przemieszczenia dla kolejnych kroków obliczeniowych wykonywanych przez solver.
W przypadku badania statycznego istnieje tylko jeden obliczony krok odpowiadający żądanemu stanowi końcowemu, a funkcja kończy się niepowodzeniem z kodem błędu 4.
Animacja w wynikach to prosta interpolacja między początkowym stanem niezamówionym a żądanym stanem końcowym.

W przypadku wykonywania badania nieliniowego, solver wykonuje obliczenia w kolejnych przyrostach, przy czym każdy krok daje wyniki, a metoda GetDisplacementComponentForAllStepsAtNode działa i zwraca tablicę przemieszczeń...

Dzień dobry

Och, to teraz ma sens. Ale chcę zrobić badanie statyczne i uzyskać dispalecent w . Plik CSV? Czy mogę więc użyć metody GetDisplacementAtPoints? Jeśli tak, proszę o pomoc z kodem.