How to speed up a Macro?

Johnny Dupont

How to speed up a Macro?

Hi all, 


I finally succeed in realizing a Catia Macro not so bad :D 

But my final problem is to speed it up a little!

I have two while loops interlocked, launching a lot of small optimizations and realizing a lot of operations such as lines/points creation, intersections, projections, creation of parameters/relations.
I tryed to suppress the maximum of Part.Update, in order to reduce the execution time.
I also suppressed parameters and deactivate relations once they are useless. Even if it is time consuming, I guess it is better than finishing the macro with more than 4000 parameters that needs to be evaluated at every update.
I saw  "CATIA.RefreshDisplay = False" which does not seems to work in my code since the display is still often updated.

Do you have any other tips to accelerate the code?


Thanks a lot for your previous help!
Bye 

Marc A Jeeves

RE: How to speed up a Macro?
(in response to Johnny Dupont)

So dont use update or append in the inner loop use compute, this way when the final element is appended in the outer loop, it will have all elements in the inner loop as aggrigate elements, also dont update the part untill the end use compute to do this on all elements.  Since the elmenets being generated are not updating existing children in the part  there is no need to continually update, since the script is building the parent and children.

 

Madaxe

Little Cthulhu

RE: How to speed up a Macro?
(in response to Marc A Jeeves)
Hi.
Just as Marc said, use Compute (for hybridshapes) or Part.UpdateObject (for any objects). Also you may want to temporary hide CATIA window with CATIA.Visible=false to avoid wasting time on re-painting window contents.

Johnny Dupont

RE: How to speed up a Macro?
(in response to Johnny Dupont)

Hi to both of you,

 

Thank you for your answer. I've been long to answer because I was trying to improve my code...
I replaced all the Part.Update to replace them by Object.Compute, but it is still long.

The problem is that the duration of my algorithm increases exponentially because it creates a lot of parameters and objects that are useful at the time of their creation, but become useless afterward. Thus, Catia has to recompute these parameters/objects at each steps for nothing since they do not change anymore.

Here are my questions :

- Is it possible to keep only the result of a object? For exemple the curve that represent the intersection of a plane and a surface which would be represented by its resulting equation.

- Is it possible to deactivate a parameter, so it keeps its value as a number and which is not updated anymore once it is deactivated?


In this blog (http://v5vb.wordpress.com/2009/12/07/deleting-objects/), it talks about "temporary geometry" which is not appended to the tree (with AppendHybridShape). Is the solution to my first question close from that? I did not find out much more information on this topic...


Thank you very much!

Marc A Jeeves

RE: How to speed up a Macro?
(in response to Johnny Dupont)

Hi Johnny,

So you don't have to append anything to the tree, as long as you keep track of the object/s in memory.  However you must run a CATDUA on the part at the end since these objects will remain in the database.

Also we are using .Net for most of our catia coding which gives more flexability, so we create custom objects which have properties and methods dedicated to a specific task.

What I'm trying to tell you is that creating your own VBA class objects and instantiating them to manage data in memory is better than creating paramters in the tree to manage temporary data.  You can also create types in VBA which is kind of a poor mans class, to manage your data both of these can be destroyed at the end.

It's better to calculate the math out in memory with cutom objects than making COM calls to CATIA.

Oh just so I'm not confusing anybody our VB.Net code still runs in process of CNEXT, which there are arguments for and against.

I added three additonal posts with some training I wrote about five years ago on Custom types and learning classes

 

Oh one last thign always destroy your objects as you go

Set oCATIA = Nothing

 

For example but you have to do this in reverse order of usage, otherwise objects get left in memory

Dim oCATIA as Application

Dim oDocuments as Documents

Set oCATIA = Catia

Set oDocuments = oCATIA.Documents

<Additional Code>

Set oDocuments = Nothing

Set oCATIA = Nothing

 

 

Madaxe

Edited By:
Marc A Jeeves[Gulfstream Aerospace Corporation] @ Apr 05, 2013 - 08:53 AM (America/Central)
Marc A Jeeves[Gulfstream Aerospace Corporation] @ Apr 05, 2013 - 08:55 AM (America/Central)

Marc A Jeeves

Creating Types in VBA
(in response to Marc A Jeeves)

I’ll start off with something everyone should be familiar with; a simple variable declaration:

  • Dim MyVariable As Integer

Simple enough, we’ve all used it before.
After a while however we find that the standard eight or so VB variables don’t cover all cases and in these cases we can create our own types known as a “User defined type” or for short “UDT”. A UDT is simply a collection of the basic variables type that we can refer to as a single object. To create a UDT we must first create the “Type declaration” which tells VB what we want the type to contain; here’s an example:

  • Private Type MyPointObject

MyPointX As Double
MyPointY As Double
MyPointZ As Double
MyPointName As String

End Type

 


 

Once the type has been declared we can declare a variable of this new type as easily as one of the standard types:

  •  Dim NewPoint As MyPointObject

A single ‘MyPointObject’ type can be passed round in exactly the same way as a variable and many unique instances of the type can be created simultaneously in the same way as we can create many Integer variables each with different values;

  • Dim MyPointA As MyPointObject
  • Dim MyPointB As MyPointObject

MyPointA.MyPointX = 23
MyPointA.MyPointY = 26
MyPointA.MyPointZ = 78
MyPointA.MyPointName = "Point.1"

MyPointB.MyPointX = 56
MyPointB.MyPointY = 98
MyPointB.MyPointZ = 99
MyPointB.MyPointName = "Point.2"

 Here you can see this visually, there's only one UDT declaration, but multiple instances of that UDT can be created from it based on the original template:


Marc A Jeeves

VBA Class Introduction
(in response to Marc A Jeeves)

Modules are used in VB mostly as a code repository where generic code is stored that is accessible application-wide. Modules are NOT objects; they’re nothing more than a place to store code. A class module on the other hand IS an object and this is probably their biggest difference from standard modules. The best explanation I can think of for a class module for those who have never worked with them before is a cross between a form without a UI (User interface) and a UDT on steroids.

If you’ve never used classes before then you’re probably a little confused as to why exactly you should use them when you could just use UDT’s or standard Modules in their place however hopefully after reading through this all should become clear or at least a little less hazy. Rather than trying to explain why to use a class and how their constructed and used, I’ll take you through step by step of building a simple number class, and don’t worry, as long as you’ve done a bit of programming before then it’s very unlikely you’re going to find anything new in any code you’ll find here, the point here is the principle not the code.

If you’ve not already fire up VB, start a new project and add a new class module, from the top tool bar Insert -> Class Module.  You should now be looking at the blank code window of the class. Nothing difficult so far - it looks just like a standard module, lets see what this thing can do.

The class we will build will be a point deviation class that will be able to perform some basic mathematic functions like taking the mean/sum/min/max/range etc. As such we’ll need an array to hold the points in, so well that to the class now:

  • Dim PointsList()

 In this case we’re just declaring an empty dynamic array and we’ll need some way of storing the number of points we have in the array so declare a variable to keep the count:

  • Dim ArraySize As Long

These two variables will be in each instance of the class module, think of it like a UDT with the array and variable in. This is where things get different though, these variables are ‘Private’ to the class instance and anything outside it can’t view the variables without us specifically telling the outside world about their existence. A UDT is completely public and this is one of the nice things about the class, you can expose only as much of the internal workings as are needed, all the complexity is dealt with internally which makes writing complex object driven applications far easier and intuitive.


 

In this case however we do want the number of numbers stored within the class to be exposed as a property of the class like an element of the UDT, but here’s another cool thing about classes – we can make the property read only so the value can be read but not changed directly, this will be handled elsewhere in the class.
To expose the property we create a little function known as a “Property Get” statement, which is nothing more than a simple function just with a fancy name.

  • Public Property Get Count() As Long

    Count = ArraySize ' Return the number count

End Property

 


 

The “Get” part means that the property can be read, if we wanted to make the property editable then we’d need to put in a “Property Let” statement which I’ll show you here for reference only, DON'T add it to the class:

  • Public Property Let Count(ByVal iNumCount As Long)

    ArraySize = iNumCount ' Set the number count

End Property


 

Now we’ll add the code to add a point to the array, I’ll not bother explaining the code as such as it’s just basic VB, have a look in help for anything you may not have come across before.

  • Public Sub AddPoint(ByVal mypoint As Point) ' Add a point
       
        ReDim Preserve PointsList(ArraySize)
        Set PointsList(ArraySize) = mypoint
        ArraySize = ArraySize + 1
       
    End Sub

This will re-declare the array, add our number into it and increment the counter. Before we give it a try, we’ll add a function to remove all the numbers as well:

  • Public Sub RemoveAll()

    ReDim MyPoints(0)
    MyArraySize = 0
   
End Sub


  

COMPLETED CLASS MODULE CODE

 

  • Dim PointsList()
  • Dim ArraySize As Long

 

 

  • Public Property Get Count() As Long

    Count = ArraySize ' Return the number count

End Property

  • Public Sub AddPoint(ByVal mypoint As Point) ' Add a point
       
        ReDim Preserve PointsList(ArraySize)
        Set PointsList(ArraySize) = mypoint
        ArraySize = ArraySize + 1
       
    End Sub

 

  • Public Sub RemoveAll()

    ReDim MyPoints(0)
    MyArraySize = 0
   
End Sub

 

 

Finally name the class “PointDeviation” and then we’re ready to give it a spin.  In the next section well test the initial class.

Marc A Jeeves

Testing The Class
(in response to Marc A Jeeves)

To test the initial class we will need to change some CATSettings, go to Tools -> Options -
> Infrastructure -> Part Infrastructure, the "Part Document" tab and turn on "Create A New Axis System.  Then create a new CATPart and add a geometrical set.  Inside of the geometrical set add three points, on three differant planes.

In the VB editor add a new module and insert the following code.

  • Sub CATMain()

    Dim MyCATIA As Application
    Dim MyPartDocument As PartDocument
    Dim MyPart As Part
    Dim MyHybridBodies As hybridBodies
    Dim MyHybridBody As hybridBody
    Dim MyHybridShapes As hybridShapes
    Dim MyHybridShape(2) As HybridShape
   
    Dim MyAxisSystems As axisSystems
    Dim MyAxisSystem As axisSystem
    Dim MaxDeviationXYZ

    
    Set MyCATIA = CATIA
    Set MyPartDocument = MyCATIA.ActiveDocument
    Set MyPart = MyPartDocument.Part
    Set MyHybridBodies = MyPart.hybridBodies
    Set MyHybridBody = MyHybridBodies.Item(1)
    Set MyHybridShapes = MyHybridBody.hybridShapes
    Set MyHybridShape(0) = MyHybridShapes.Item(1)
    Set MyHybridShape(1) = MyHybridShapes.Item(2)
    Set MyHybridShape(2) = MyHybridShapes.Item(3)
   
    Set MyAxisSystems = MyPart.axisSystems
    Set MyAxisSystem = MyAxisSystems.Item(1)

    'ADDITIONAL CODE INSERTED HERE'

End Sub


 

The test code creates objects for three points and an axis system and sets those objects with the points and the axis system found in the new CATPart.

 We can now declare a new instance of our class in the test module, this is done in two steps creating a variable and giving it the type that has the same name as the class module i.e. "PointDeviation".

  •  Dim MyPointDeviationTest As PointDeviation

 

This does nothing more than creates a space in memory of the type "PointDeviation".  Next the class has to be instanciated into this space this is achieved using the "New" keyword, when initialising the variable by using the "Set" keyword.

  • Set MyPointDeviationTest = New PointDeviation

 


 

Now we can use the class, if you type "PointDeviation" and hit the full stop key “.” you’ll see that there’s three things been exposed, two are subroutines and one is a property, you’ll see if has a different icon to the others.  Now that the class has been instanciated into the test module, the properties and methods that belong to the "PointDeviation" object can now be utilised lets start of by decalring a variable that will be used to track the size of the point collection, this will increment every time a new point is added using the "AddPoint" method belonging to the "PointDeviation" object:

  • Dim MyPointCount As Integer

 

This variable can now be made to equal the "Count" property of the "PointDeviation" object:

  • MyPointCount = MyPointDev.Count

 

Just as a quick test we’ll add the three points, these will be added to the collection belonging to the "PointDeviation" object, this will be achieved bby using the "AddPoint" method of the "PointDeviation" object, that was created earlier in the class, this will also allow us to test the number counter to make sure it’s working so far:

  • MyPointDev.AddPoint MyHybridShape(0)
  • MyPointDev.AddPoint MyHybridShape(1)
  • MyPointDev.AddPoint MyHybridShape(2)

 


COMPLETED TEST CODE

  •  Sub CATMain()

       Dim MyCATIA As Application
       Dim MyPartDocument As PartDocument
       Dim MyPart As Part
       Dim MyHybridBodies As hybridBodies
       Dim MyHybridBody As hybridBody
       Dim MyHybridShapes As hybridShapes
       Dim MyHybridShape(2) As HybridShape
   
       Dim MyAxisSystems As axisSystems
       Dim MyAxisSystem As axisSystem
       Dim MaxDeviationXYZ

    
       Set MyCATIA = CATIA
       Set MyPartDocument = MyCATIA.ActiveDocument
       Set MyPart = MyPartDocument.Part
       Set MyHybridBodies = MyPart.hybridBodies
       Set MyHybridBody = MyHybridBodies.Item(1)
       Set MyHybridShapes = MyHybridBody.hybridShapes
       Set MyHybridShape(0) = MyHybridShapes.Item(1)
       Set MyHybridShape(1) = MyHybridShapes.Item(2)
       Set MyHybridShape(2) = MyHybridShapes.Item(3)
   
       Set MyAxisSystems = MyPart.axisSystems
       Set MyAxisSystem = MyAxisSystems.Item(1)
   
       Dim MyPointDev As PointDeviation
       Set MyPointDev = New PointDeviation
   
       Dim MyPointCount As Integer
       MyPointCount = MyPointDev.Count
   
       MyPointDev.AddPoint MyHybridShape(0)
       MyPointDev.AddPoint MyHybridShape(1)
       MyPointDev.AddPoint MyHybridShape(2)

End Sub

By adding a watch to the MyPointDev object and running the code the collection can be seen containning the three points.  In the next section the max devition method will be added to the class object.

Little Cthulhu

RE: Testing The Class
(in response to Marc A Jeeves)
Marc is on fire :)
Parameters are SLOW, avoid them where possible. Do you really have to use optimizations?
Edited By:
Little Cthulhu[Sikorsky Aircraft] @ Apr 05, 2013 - 06:44 PM (Europe/Moscow)

Johnny Dupont

RE: Testing The Class
(in response to Little Cthulhu)

Wow, he is indeed on fire :D
Thank you, I'll take a look at it later!
But just to answer Cthulhu's question, I guess I have to use parameters...

I realize a geometric analysis of my part, basicaly consisting in slicing it with planes whose position is the result of an optimization and whose center of rotation is the center of gravity of this slice...
So yes, I guess I really have to use parameters in order to use the Catia's optimization objects and parameters such as =centerofgravity(mySlice)

Bye 

Little Cthulhu

RE: Testing The Class
(in response to Johnny Dupont)
If you wish, describe your whole algorythm, I'll see what can be moved to script and optimized without parameters.

Balla Zoltan

RE: Testing The Class
(in response to Little Cthulhu)

Hello together,

I know this is an old topic, but I also want to speed up my script a little bit.

My most time consuming process is to copy my Selected objects in a Object array using For...next  loop.

It is possible to assign the Selection to the Array without using the For....next loop

Something like Set oSeletierteBauteile=sSeletierteBauteile??? :)

Here is my code snippet.

Function Search_for_Visible_Parts() As Boolean
Dim m As Integer
ReDim oSeletierteBauteile(0)
Set sSeletierteBauteile = ActiveDoc.Selection
sSeletierteBauteile.Search "'Assembly Design'.Part.Visibility=Shown,all"
If sSeletierteBauteile.Count > 0 Then
    ReDim Preserve oSeletierteBauteile(sSeletierteBauteile.Count)
    For m = 1 To sSeletierteBauteile.Count
        Set oSeletierteBauteile(m) = sSeletierteBauteile.Item2(m).Value
    Next m
    sSeletierteBauteile.Clear
    Search_for_Visible_Parts = True
Else
    MsgBox "No Parts are visible on the screen!"
    Search_for_Visible_Parts = False
End If
End Function

Marc A Jeeves

RE: Testing The Class
(in response to Balla Zoltan)

Anytime you need to make multiple selections from the spec tree, where possible create a Class that represents each object in the tree that contains methods and properties that support the end goal. 

A lot of the time I will use a recursive loop to build a class structure in memory that represents what I have in CATIA and then work from this never making any selections. 

Or make all the selects in one go then build the class structure then filter the structure based on the data required.

The important thing is to get as much as possible into memory with the least amount of selections

Balla Zoltan

RE: Testing The Class
(in response to Marc A Jeeves)

but to load all these parts into the memory using a Class means also a For ... next loop right?

 

Marc A Jeeves

RE: Testing The Class
(in response to Little Cthulhu)

Here is a simplistic example of looping through a product structure and resetting instance ids you could do the same thing to build a class structure of data, this is very fast and does not require selection methods.

 

Sub CATMain()

    Dim oDocument As Document


    On Error Resume Next
   
        Set oDocument = CATIA.ActiveDocument
   
    On Error GoTo 0
   
    If oDocument Is Nothing Then
   
        MsgBox "There Is No Active Document In The Session, Exiting Script."
        Exit Sub
   
    Else
   
        DIGDOWN oDocument.Product
   
    End If

End Sub

Public Sub DIGDOWN(MyRootNode As Product)

    Dim RootProducts As Products
    Set RootProducts = MyRootNode.Products

    For Each Instance In RootProducts

        Set MyRootNode = Instance.ReferenceProduct
       
        On Error Resume Next
        Err.Number = 1
        Dim iIndex As Integer
        iIndex = 1
       
        Do While Err.Number <> 0
       
            Err.Number = 0
            Instance.Name = Instance.PartNumber & "." & iIndex
           
            If Err.Number <> 0 Then iIndex = iIndex + 1
           
        Loop
       
        On Error GoTo 0
       
        DIGDOWN MyRootNode

    Next

End Sub

Edited By:
Marc A Jeeves[Gulfstream Aerospace Corporation] @ Sep 25, 2017 - 08:44 AM (America/Central)

Thomas J Vanderwiel, Tooling KBE Engineer

RE: Testing The Class
(in response to Marc A Jeeves)

To speedup the selection process you can use  the CATIA.HSOSynchronized property. 

 CATIA.HSOSynchronized = False

      <Your selection code>

 CATIA.HSOSynchronized = True

From the CATIA VBA documentation:

"For selection performance purposes, returns or sets the HSO synchronization in comparison with the CSO.
Role: Precises if, for all Selection object instances, the HSO (Highlighted Set of Objects) is synchronized in comparison with the CSO (Current Set of Objects). "

 

Tom

Boeing

Balla Zoltan

RE: Testing The Class
(in response to Thomas J Vanderwiel, Tooling KBE Engineer)

actualy the time consuming process is by attaching the selection to the array. This takes a lot of time for example by a product with >3000 Parts. The selection itself works pretty quick.