FreeCAD as pre-post processor for MBDyn

About the development of the FEM module/workbench.

Moderator: bernd

JamesLiu
Posts: 26
Joined: Sat Apr 28, 2018 6:23 am

Re: FreeCAD as pre-post processor for MBDyn

Post by JamesLiu »

Is it possible to post-process MBDyn results without FCStd model file?
josegegas
Posts: 241
Joined: Sat Feb 11, 2017 12:54 am
Location: New Zealand

Re: FreeCAD as pre-post processor for MBDyn

Post by josegegas »

JamesLiu wrote: Wed Oct 20, 2021 10:23 am Is it possible to post-process MBDyn results without FCStd model file?
No, but it´s an interesting feature that could be implemented.
josegegas
Posts: 241
Joined: Sat Feb 11, 2017 12:54 am
Location: New Zealand

Re: FreeCAD as pre-post processor for MBDyn

Post by josegegas »

Hi.

I want to be able to store any quantity as a property for a scripetd object, including any random units. So I thought to do this:

from FreeCAD import Units
obj=FreeCAD.ActiveDocument.addObject("App::FeaturePython","InternalObjectName")
obj.addProperty('App::PropertyQuantity', 'ThePropertyName', 'Subsection', 'Description for tooltip')
obj.ThePropertyName = Units.Quantity(1.0,Units.Unit(0,1))

However it seems that 'App::PropertyQuantity' cannot get any unit:

Traceback (most recent call last):
File "<input>", line 1, in <module>
ArithmeticError: Not matching Unit!

I need for instance to store moments of inertia or angular velocity and acceleration, so I do requires specific units....

Any suggestions?

Cheers!
T-Garnier
Posts: 18
Joined: Sat Jun 27, 2020 5:30 am

Re: FreeCAD as pre-post processor for MBDyn

Post by T-Garnier »

Hi Jose,

I found this thread, maybe it can help you.
https://www.forum.freecadweb.org/viewto ... 10&t=47992
josegegas
Posts: 241
Joined: Sat Feb 11, 2017 12:54 am
Location: New Zealand

Re: FreeCAD as pre-post processor for MBDyn

Post by josegegas »

Yes, that works perfectly. I´ll paste the example here in case it's useful:

Code: Select all

from FreeCAD import Units
from femobjects import base_fempythonobject

class MyNewObject(base_fempythonobject.BaseFemPythonObject):
    Type = "Fem::MyNewObject"
    def __init__(self, obj):
        super(MyNewObject, self).__init__(obj)
        obj.addProperty(
            "App::PropertyQuantity",
            "MyNewProperty",
            "MyPropertyGroup",
            "Set my new PropertyQuantity"
        )
        obj.MyNewProperty = Units.VacuumPermittivity



newobj = App.ActiveDocument.addObject("Fem::ConstraintPython", "FunnyObject")
MyNewObject(newobj)
newobj.MyNewProperty = Units.Quantity("1 s^4*A^2 / (m^3*kg)")
newobj.MyNewProperty
I think the documentation:

https://wiki.freecadweb.org/FeaturePyth ... tyQuantity

has to be updated to explain how to use "App::PropertyQuantity"....

Thanks
josegegas
Posts: 241
Joined: Sat Feb 11, 2017 12:54 am
Location: New Zealand

Re: FreeCAD as pre-post processor for MBDyn

Post by josegegas »

Here is a strange thing I just noticed.

The scripted object above works perfectly fine, however if you save the FreeCAD file and open it again, the units will be gone... The initial units of the property disappear after saving, closing and opening the file again.

What may be wrong?
josegegas
Posts: 241
Joined: Sat Feb 11, 2017 12:54 am
Location: New Zealand

Re: FreeCAD as pre-post processor for MBDyn

Post by josegegas »

Here is the relevant part of my code:

Code: Select all

from FreeCAD import Units
import FreeCAD

class Rigidbody: 
    def __init__(self, obj): 
        obj.addProperty("App::PropertyQuantity",
                        "absolute_angular_velocity_X",
                        "Initial conditions: absolute angular velocity [deg/s]",
                        "X component of the absolute initial angular velocity").absolute_angular_velocity_X = 10.0
        
        obj.absolute_angular_velocity_X = FreeCAD.Units.Unit('deg/s') 
 
    
 
a = FreeCAD.ActiveDocument.addObject("Part::FeaturePython","MyObject")
Rigidbody(a)
This works perfectly, except that when the FreeCAD document is saved, closed and open again, the units of the "absolute_angular_velocity_X" property have disappeared.

Any ideas why?
T-Garnier
Posts: 18
Joined: Sat Jun 27, 2020 5:30 am

Re: FreeCAD as pre-post processor for MBDyn

Post by T-Garnier »

I think I spotted this problem when i was working on the other workbench but did not continue to investigate due to all major task I had.

Maybe be overwriting one of the following methods you could reattribute the unit to each object?
OnDocumentRestore
__setstate__

Or maybe the __getstate__ method to modify the way the object is saved ?
josegegas
Posts: 241
Joined: Sat Feb 11, 2017 12:54 am
Location: New Zealand

Re: FreeCAD as pre-post processor for MBDyn

Post by josegegas »

Got the solution. Units have to be restored every time the document is loaded:

Code: Select all

    def onDocumentRestored(self, obj):
        obj.absolute_angular_velocity_X = FreeCAD.Units.Unit('deg/s')
My guess is that this is so that units can be changed in case the user has selected another unit system. The default is mm/kg/s/deg

I wonder why is that other properties (App::PropertyDistance, App::PropertyAngle, etc) do not have the same behavior. The units for these are stored and do not have to be restored on document load. I also wonder why these exist at all, as we can use App::PropertyQuantity for all the properties...
josegegas
Posts: 241
Joined: Sat Feb 11, 2017 12:54 am
Location: New Zealand

Re: FreeCAD as pre-post processor for MBDyn

Post by josegegas »

Hi. I´m having an issue with a couple of my scripted objects. The problem seems to be related to the onChanged method. I use this method to change one property of the object according to the values entered or selected by the user. It works perfectly, but when I close and open the FreeCAD model I get the next error:

Code: Select all

    if(fp.type == 'const, <const_coef>'):
<class 'AttributeError'>: 'FeaturePython' object has no attribute 'type'
The thing is that the object does have an attribute "type". Here is the whole object:

Code: Select all

import FreeCAD

class Drive:
    def __init__(self, obj, label): 
        
        obj.addExtension("App::GroupExtensionPython", self)
        
        obj.addProperty("App::PropertyString","label","Drive","label",1).label = label
        
        #function type
        obj.addProperty("App::PropertyEnumeration","type","Drive","type")
        obj.type=['const, <const_coef>',
                  'cosine, <initial_time>, <angular_vel>, <amplitude>, half, <initial_value>',
                  'cosine, <initial_time>, <angular_vel>, <amplitude>, one, <initial_value>',
                  'cosine, <initial_time>, <angular_vel>, <amplitude>, forever, <initial_value>',
                  'cosine, <initial_time>, <angular_vel>, <amplitude>, <number_of_cycles>, <initial_value>',                              
                  'cubic, <const_coef>, <linear_coef>, <parabolic_coef>, <cubic_coef>',
                  'direct',
                  'double ramp, <a_slope>, <a_initial_time>, <a_final_time>, <d_slope>, <d_initial_time>, forever, <initial_value>',
                  'double ramp, <a_slope>, <a_initial_time>, <a_final_time>, <d_slope>, <d_initial_time>, <d_final_time>, <initial_value>',
                  'double step, <initial_time>, <final_time>, <step_value>, <initial_value>',
                  'linear, <const_coef>, <slope_coef>',
                  'ramp, <slope>, <initial_time>, forever, <initial_value>',
                  'ramp, <slope>, <initial_time>, <final_time>, <initial_value>',
                  'sine, <initial_time>, <angular_vel>, <amplitude>, half, <initial_value>',
                  'sine, <initial_time>, <angular_vel>, <amplitude>, one, <initial_value>',
                  'sine, <initial_time>, <angular_vel>, <amplitude>, forever, <initial_value>',
                  'sine, <initial_time>, <angular_vel>, <amplitude>, <number_of_cycles>, <initial_value>',
                  'step, <initial_time>, <step_value>, <initial_value>',
                  'string',
                  'time',
                  'timestep',
                  'unit']
                  

        #Slope parameters:
        obj.addProperty("App::PropertyFloat","a_slope","Slope parameters","a_slope").a_slope = 2.0
        obj.addProperty("App::PropertyFloat","slope","Slope parameters","slope").slope = 0.1
        obj.addProperty("App::PropertyFloat","slope_coef","Slope parameters","slope_coef").slope_coef = 0.1
        obj.addProperty("App::PropertyFloat","d_slope","Slope parameters","d_slope").d_slope = -2.0               
                
        #coefficient parameters
        obj.addProperty("App::PropertyFloat","const_coef","Coefficient parameters","const_coef").const_coef = 10.0
        obj.addProperty("App::PropertyFloat","linear_coef","Coefficient parameters","linear_coef").linear_coef = 1.0
        obj.addProperty("App::PropertyFloat","parabolic_coef","Coefficient parameters","parabolic_coef").parabolic_coef = 1.0
        obj.addProperty("App::PropertyFloat","cubic_coef","Coefficient parameters","cubic_coef").cubic_coef = 1.0 
        
        #Drive parameters
        obj.addProperty("App::PropertyFloat","step_value","Drive parameters","step_value").step_value = 10.0        
        obj.addProperty("App::PropertyFloat","angular_vel","Drive parameters","angular_vel").angular_vel = 3.11      
        obj.addProperty("App::PropertyFloat","amplitude","Drive parameters","amplitude").amplitude = 10.0
        obj.addProperty("App::PropertyFloat","initial_value","Drive parameters","initial_value").initial_value = 0.0
        obj.addProperty("App::PropertyInteger","number_of_cycles","Drive parameters","number_of_cycles").number_of_cycles = 2
        
        #Time parameters:
        obj.addProperty("App::PropertyQuantity","a_initial_time","Time parameters","a_initial_time").a_initial_time = 1.0
        obj.a_initial_time = FreeCAD.Units.Unit('s') 
        
        obj.addProperty("App::PropertyQuantity","d_initial_time","Time parameters","d_initial_time").d_initial_time = 4.0
        obj.d_initial_time = FreeCAD.Units.Unit('s')
        
        obj.addProperty("App::PropertyQuantity","a_final_time","Time parameters","a_final_time").a_final_time = 2.0
        obj.a_final_time = FreeCAD.Units.Unit('s')
        
        obj.addProperty("App::PropertyQuantity","d_final_time","Time parameters","d_final_time").d_final_time = 5.0
        obj.d_final_time = FreeCAD.Units.Unit('s')
        
        obj.addProperty("App::PropertyQuantity","initial_time","Time parameters","initial_time").initial_time = 2.0
        obj.initial_time = FreeCAD.Units.Unit('s')
        
        obj.addProperty("App::PropertyQuantity","final_time","Time parameters","final_time").final_time = 4.0
        obj.final_time = FreeCAD.Units.Unit('s')
        
        
        obj.addProperty("App::PropertyString","expression","Drive","expression",1).expression = '1.5*sin(2.*Time)'
        
        obj.Proxy = self      
                               
        FreeCAD.ActiveDocument.recompute()

    def onChanged(self, fp, prop):
        if(fp.type == 'const, <const_coef>'):
            fp.expression = 'const, ' + str(fp.const_coef)
                        
        if(fp.type == 'cosine, <initial_time>, <angular_vel>, <amplitude>, half, <initial_value>'):
            fp.expression = 'cosine, ' + str(fp.initial_time.Value) + ', ' + str(fp.angular_vel) + ', ' + str(fp.amplitude) + ', half, ' + str(fp.initial_value)

        if(fp.type == 'cosine, <initial_time>, <angular_vel>, <amplitude>, one, <initial_value>'):
            fp.expression = 'cosine, ' + str(fp.initial_time.Value) + ', ' + str(fp.angular_vel) +', ' + str(fp.amplitude) + ', one, ' + str(fp.initial_value)

        if(fp.type == 'cosine, <initial_time>, <angular_vel>, <amplitude>, forever, <initial_value>'):
            fp.expression = 'cosine, ' + str(fp.initial_time.Value) + ', ' + str(fp.angular_vel) + ', ' + str(fp.amplitude) + ', forever, ' + str(fp.initial_value)

        if(fp.type == 'cosine, <initial_time>, <angular_vel>, <amplitude>, <number_of_cycles>, <initial_value>'):
            fp.expression = 'cosine, ' + str(fp.initial_time.Value) + ', ' + str(fp.angular_vel) + ', ' + str(fp.amplitude) + ', ' + str(fp.number_of_cycles) + ', ' + str(fp.initial_value)

        if(fp.type == 'cubic, <const_coef>, <linear_coef>, <parabolic_coef>, <cubic_coef>'):
            fp.expression = 'cubic, ' + str(fp.const_coef) + ', ' + str(fp.linear_coef) + ', ' + str(fp.parabolic_coef) + ', ' + str(fp.cubic_coef)

        if(fp.type == 'direct'):
            fp.expression = 'direct'

        if(fp.type == 'double ramp, <a_slope>, <a_initial_time>, <a_final_time>, <d_slope>, <d_initial_time>, forever, <initial_value>'):
            fp.expression = 'double ramp, ' + str(fp.a_slope) + ', ' + str(fp.a_initial_time.Value) + ', ' + str(fp.a_final_time.Value) + ', ' + str(fp.d_slope) + ', ' + str(fp.d_initial_time.Value) + ', forever, ' + str(fp.initial_value)

        if(fp.type == 'double ramp, <a_slope>, <a_initial_time>, <a_final_time>, <d_slope>, <d_initial_time>, <d_final_time>, <initial_value>'):
            fp.expression = 'double ramp, ' + str(fp.a_slope) + ', ' + str(fp.a_initial_time.Value) + ', ' + str(fp.a_final_time.Value) + ', ' + str(fp.d_slope) + ', ' + str(fp.d_initial_time.Value) + ', ' + str(fp.d_final_time.Value) + ', ' + str(fp.initial_value)

        if(fp.type == 'double step, <initial_time>, <final_time>, <step_value>, <initial_value>'):
            fp.expression = 'double step, ' + str(fp.initial_time.Value) + ', ' + str(fp.final_time.Value) + ', ' + str(fp.step_value) + ', ' + str(fp.initial_value)
            
        if(fp.type == 'linear, <const_coef>, <slope_coef>'):
            fp.expression = 'linear, ' + str(fp.const_coef) + ', ' + str(fp.slope_coef)

        if(fp.type == 'ramp, <slope>, <initial_time>, forever, <initial_value>'):
            fp.expression = 'ramp, ' + str(fp.slope) + ', ' + str(fp.initial_time.Value) + ', forever, ' + str(fp.initial_value)

        if(fp.type == 'ramp, <slope>, <initial_time>, <final_time>, <initial_value>'):
            fp.expression = 'ramp, ' + str(fp.slope) + ', ' + str(fp.initial_time.Value) + ', ' + str(fp.final_time.Value) + ', ' + str(fp.initial_value)

        if(fp.type == 'sine, <initial_time>, <angular_vel>, <amplitude>, half, <initial_value>'):
            fp.expression = 'sine, ' + str(fp.initial_time.Value) + ', ' + str(fp.angular_vel) + ', ' + str(fp.amplitude) + ', half, ' + str(fp.initial_value)

        if(fp.type == 'sine, <initial_time>, <angular_vel>, <amplitude>, one, <initial_value>'):
            fp.expression = 'sine, ' + str(fp.initial_time.Value) + ', ' + str(fp.angular_vel) + ', ' + str(fp.amplitude) + ', one, ' + str(fp.initial_value)

        if(fp.type == 'sine, <initial_time>, <angular_vel>, <amplitude>, forever, <initial_value>'):
            fp.expression = 'sine, ' + str(fp.initial_time.Value) + ', ' + str(fp.angular_vel) + ', ' + str(fp.amplitude) + ', forever, ' + str(fp.initial_value)

        if(fp.type == 'sine, <initial_time>, <angular_vel>, <amplitude>, <number_of_cycles>, <initial_value>'):
            fp.expression = 'sine, '+ str(fp.initial_time.Value) + ', ' + str(fp.angular_vel) + ', ' + str(fp.amplitude) + ', ' + str(fp.number_of_cycles) + ', ' + str(fp.initial_value)
        
        if(fp.type == 'step, <initial_time>, <step_value>, <initial_value>'):
            fp.expression = 'step, ' + str(fp.initial_time.Value) + ', ' + str(fp.step_value) + ', ' + str(fp.initial_value)

        if(fp.type == 'string'):
            fp.expression = 'string, "' + fp.string + '"'

        if(fp.type == 'time'):
            fp.expression = 'time'

        if(fp.type == 'timestep'):
            fp.expression = 'timestep'
            
        if(fp.type == 'unit'):
            fp.expression = 'unit'                 
            

    def execute(self, fp):
        '''Do something when doing a recomputation, this method is mandatory'''
        FreeCAD.Console.PrintMessage("DRIVE: " +fp.label+ " successful recomputation...\n")
                              
    def onDocumentRestored(self, obj):
        obj.a_initial_time = FreeCAD.Units.Unit('s')
        obj.d_initial_time = FreeCAD.Units.Unit('s')
        obj.a_final_time = FreeCAD.Units.Unit('s')
        obj.d_final_time = FreeCAD.Units.Unit('s')
        obj.initial_time = FreeCAD.Units.Unit('s')
        obj.final_time = FreeCAD.Units.Unit('s')
What am I getting wrong?
Post Reply