GiD - The personal pre and post processor

Annex I: Using functions

The following section is of purely practical nature. It contains examples of the most common functions from the areas CustomLib deals with.

Example: Using functions based on Interpolated Data
The linear interpolation uses two or more pairs of input data points that approximate a function. To define functions based on interpolated data, use the function dialog box, which can be opened from the data tree automatically clicking on the button ? as follows,

An example of the <value/> node field in the .spd file is the following:

<container n="my_load" pn="My load">
    <value n="disc_load" pn="Discrete load" min_two_pnts="1" single_value="1" function="[my_loads_function_time %W]" function_func="" state="normal" v="1.0">
        <function>
            <functionVariable n="interpolator_func" pn="Interpolation function" variable="x" units="s">
                <value n="point" pn="Point" v="0.0,0.0"/>
                <value n="point" pn="Point" v="10.0,1.0"/>
                <value n="point" pn="Point" v="1.0e9,1.0"/>
            </functionVariable>
        </function>
    </value>
</container>

And in a.tcl define the proc

proc my_loads_function_time { domNode } {
    set loads [list [list scalar]]    
    lappend loads [list interpolator_func x x T]
    return [join $loads ,]
}


Notice that both <function/> and <functionVariable/> nodes are required to define an interpolation function.

Note: The nodes of type <value n="point"/> can be omitted to start with an empty table of input data points.

Function dialog box allows to enter  pairs of input data points that approximate a function


It is possible to show different types of graphs, and now is allowed to have multiple series (more than one y column for the x column)

attribute function_graph_type  possible values: xy (default), bar, pie, polar

attribute function_graph_logx boolean to set logarithmic axis x, and function_graph_logy to set logarithmic axis y (valid for xy graphs only)

attribute function_graph_bar_stacked boolean to show bar graphs with multiple series stacked or not (valid for bar graphs only)

attribute function_graph_bar_horizontal boolean to show bar graphs horizontal instead default vertical (valid for bar graphs only)


Example: graph xy with multiple series and logarithmic x and y axis

   <container n="POLYFLAM_RABS_90000_UV5" pn="POLYFLAM® RABS 90000 UV5">
    <value n="shear_rate" pn="Shear rate curve" min_two_pnts="1" single_value="1" pn_function="Viscosity_(230ºC),Viscosity_(240ºC),Viscosity_(250ºC)" unit_magnitude="Viscosity" units="Pa*s" function="[my_loads_function_time %W]" function_func="" function_graph_type="xy" function_graph_logx="1" function_graph_logy="1" state="normal" v="1.0">
      <function>
        <functionVariable n="interpolator_func" pn="Interpolation function" variable="x" units="1/s">
          <value n="point" pn="Point" v="10,2412.01,1387.9,810.038" />
          <value n="point" pn="Point" v="100,891.705,668.442,485.431" />
          <value n="point" pn="Point" v="500,296.806,244.764,201.39" />
          <value n="point" pn="Point" v="1000,178.143,149.199,125.746" />
          <value n="point" pn="Point" v="5000,53.0574,45.0246,38.7688" />
          <value n="point" pn="Point" v="10000,31.3575,26.6552,23.0168" />
        </functionVariable>
      </function>
    </value>
  </container>



Example: graph of bars with two series in vertical and not stacked

  <container n="bar_demo" pn="bar demo">
    <value n="other_curve" pn="time Velocity curve" min_two_pnts="1" single_value="1" pn_function="speed,other" unit_magnitude="Velocity" units="" 
    function="[my_loads_function_time %W]" function_func="" function_graph_type="bar" function_graph_bar_horizontal="0" function_graph_bar_stacked="0" state="normal" v="1.0">
      <function>
        <functionVariable n="interpolator_func" pn="Interpolation function" variable="x" units="s">
          <value n="point" pn="Point" v="0.0,0.13,0.2" />
          <value n="point" pn="Point" v="5.0,0.32,0.15" />
          <value n="point" pn="Point" v="8.0,0.22,0.57" />
          <value n="point" pn="Point" v="10.0,0.9,1.4" />
        </functionVariable>
      </function>
    </value>
  </container>

Example: polar graph

    <container n="polar_demo" pn="polar demo">
    <value n="polar_curve" pn="time Velocity curve" min_two_pnts="1" single_value="1" pn_function="speed" unit_magnitude="Velocity" units="" 
    function="[my_loads_function_time %W]" function_func="" function_graph_type="polar" state="normal" v="1.0">
      <function>
        <functionVariable n="interpolator_func" pn="Interpolation function" variable="x" units="degree">
          <value n="point" pn="Point" v="0.0,0.13" />
          <value n="point" pn="Point" v="45.0,0.32" />
          <value n="point" pn="Point" v="160.0,0.22" />
          <value n="point" pn="Point" v="230.0,0.5" />
          <value n="point" pn="Point" v="360.0,0.9" />
        </functionVariable>
      </function>
    </value>
  </container>

Example: pie chart

  <container n="pie_demo" pn="pie demo">
    <value n="rate_curve" pn="time Velocity curve" min_two_pnts="1" single_value="1" pn_function="speed" unit_magnitude="Velocity" units="" function="[my_loads_function_time %W]" function_func="" function_graph_type="pie" state="normal" v="1.0">
      <function>
        <functionVariable n="interpolator_func" pn="Interpolation function" variable="x" units="s">
          <value n="point" pn="Point" v="slow,0.13" />
          <value n="point" pn="Point" v="medium,0.32" />
          <value n="point" pn="Point" v="fast,0.22" />
          <value n="point" pn="Point" v="very fast,0.9" />
        </functionVariable>
      </function>
    </value>
  </container>


Example : Using functions based on Interpolated Data, methods for entering data
It is possible to select automatically the method for entering data (Single value, Linear ramp or Equation). For functions of one variable, you can select between the following interpolation methods by default:

  • Single value: The linear interpolation uses two or more pairs of input data points that approximate a function.
  • Linear ramp: Calculates two or more 'Linear ramp' pairs of input data points that approximate a function.
  • Equation: Calculates two or more pairs of input data points that satisfy a given equation.

Use the function dialog box, which can be opened from the data tree clicking on the button ? as follows,

Function dialog box allows to calculate input data points that satisfy a given equation.

Function dialog box allows to calculate input data points that satisfy a sinusoidal load equation.

<value n="Factor" pn="Factor" v="1.0" help="This factor, that can be a number or a formula, multiplies the vector load" function="[loads_function Punctual_Load]" function_func="CompassFEM::function_loads"/>

<proc n="loads_function" args="load_name">    
      return [chk_loads_function $domNode $load_name]       
</proc>

proc function_loads { ftype what n pn frame domNode funcNode \
    units_var ov_var } {
    switch $ftype {       
        sinusoidal_load {
            return [function_loads_sinusoidal $what $n $pn $frame $domNode \
            $funcNode $units_var $ov_var]
        }
        custom_editor {
            return [function_custom_editor $what $n $pn $frame $domNode \
            $funcNode $units_var $ov_var]
        }
    }    
}

proc chk_loads_function {domNode load_name} {
    set loads [list [list scalar]]
    lappend loads [list sinusoidal_load t] 
    return [join $loads ,]
}

proc function_custom_editor { what n pn f domNode funcNode \
    units_var ov_var } {
  # Create your own child window implemented in Tcl/Tk..
}

proc function_loads_sinusoidal { what n pn f domNode funcNode \
    units_var ov_var } {

    global ProblemTypePriv

    switch $what {
        create {
            set help [= "This is a a sinusoidal load that depends on the time"]

            set f1 [ttk::frame $f.f1]

            set idx 0
            foreach i [list amplitude circular_frequency phase_angle initial_time end_time] \
                n [list [= "Amplitude (%s)" A] \
                    [= "Frequency (%s)" f] [= "Phase angle (%s)" \u3a6] \
                    [= "Initial time (%s)" t0] [= "End time (%s)" t1]] \
                m [list - Frequency Rotation T T] \
                u [list - 1/s rad s s] \
                v [list 1.0 1.0 0.0 0.0 0.0] {

                ttk::label $f1.l$idx -text $n:
                gid_groups_conds::register_popup_help $f1.l$idx $help

                if { $m ne "-" } {
                    set ProblemTypePriv($i) $v
                    set ProblemTypePriv(${i}_units $u

                    gid_groups_conds::entry_units $f1.sw$idx \
                        -unit_magnitude $m \
                        -value_variable ProblemTypePriv($i) \
                        -units_variable ProblemTypePriv(${i}_units)
                } else {
                    ttk::entry $f1.sw$idx -textvariable ProblemTypePriv($i)
                    set ProblemTypePriv($i) $v
                }
                grid $f1.l$idx $f1.sw$idx -sticky w -padx 2 -pady 2
                grid configure $f1.sw$idx -sticky ew
                incr idx
            }
            if { ![info exists ProblemTypePriv(l_sin_img)] } {
                set ProblemTypePriv(l_sin_img) [image create photo \
                        -file [file join $ProblemTypePriv(problemtypedir) images \
                            sinusoidal_load.gif]]
            }

            ttk::label $f1.l -text "f(t)=A\u00b7sin(2\u00b7\u03C0\u00b7f\u00b7t+\u03a6)" \
                -relief solid -padding 3 -width 20 \
                -anchor w
            grid $f1.l -sticky w -padx 6 -pady 6

            label $f.image -image $ProblemTypePriv(l_sin_img) -bd 1 -relief solid

            grid $f1 $f.image -sticky nw -padx 8 -pady 2
            grid configure $f.image -sticky new

            grid columnconfigure $f 1 -weight 1
            grid rowconfigure $f 0 -weight 1

            if { $funcNode ne "" } {
                set xp {functionVariable[@variable="t" and
                    @n="sinusoidal_load"]}
                set fvarNode [$funcNode selectNodes $xp]
            } else { set fvarNode "" }
            if { $fvarNode ne "" } {
                foreach i [list amplitude circular_frequency phase_angle initial_time end_time] \
                    pn [list [= "Amplitude (%s)" A] \
                        [= "Frequency (%s)" f] [= "Phase angle (%s)" \u3a6] \
                        [= "Initial time (%s)" t0] [= "End time (%s)" t1]] \
                    m [list - Frequency Rotation T T] {

                    set xp [format_xpath {string(value[@n=%s]/@v)} $i]
                    set ProblemTypePriv($i) [$fvarNode selectNodes $xp]
                    if { $m ne "-" } {
                        set xp [format_xpath {string(value[@n=%s]/@units)} $i]
                        set ProblemTypePriv(${i}_units) \
                            [gid_groups_conds::units_to_nice_units [$fvarNode selectNodes $xp]] 
                    }
                }
            }
            return [= "Sinusoidal load"]
        }
        apply {
            set idx 0
            set f1 $f.f1
            foreach i [list amplitude circular_frequency phase_angle initial_time end_time] \
                pn [list [= "Amplitude (%s)" A] \
                    [= "Frequency (%s)" f] [= "Phase angle (%s)" \u3a6] \
                    [= "Initial time (%s)" t0] [= "End time (%s)" t1]] \
                m [list - Rotation Rotation T T] {
                if { ![string is double -strict $ProblemTypePriv($i)] } {
                    if { $m ne "-" } { set e $f1.sw$idx.e } else { set e $f1.sw$idx }
                    tk::TabToWindow $e
                    error [= "Value %s is not OK" $pn]
                }
                incr idx
            }
            set xp {functionVariable[@variable="t"]}
            if { [$funcNode selectNodes $xp] eq "" } {
                set fvarNode [$funcNode appendChildTag functionVariable]
            } else {
                set fvarNode [$funcNode selectNodes $xp]
                foreach i [$fvarNode childNodes] { $i delete }
            }
            $fvarNode setAttribute n sinusoidal_load pn [= "Sinusoidal load"] \
                variable "t"
            foreach i [list amplitude circular_frequency phase_angle initial_time end_time] \
                pn [list [= "Amplitude (%s)" A] \
                    [= "Frequency (%s)" f] [= "Phase angle (%s)" \u3a6] \
                    [= "Initial time (%s)" t0] [= "End time (%s)" t1]] \
                m [list - Frequency Rotation T T] {

                set v [$fvarNode appendChildTag value [list attributes() \
                            n $i pn $pn v $ProblemTypePriv($i)]]
                if { $m ne "-" } {
                    set newunits [gid_groups_conds::nice_units_to_units \
                            $ProblemTypePriv(${i}_units)]
                    $v setAttribute unit_magnitude $m \
                        units $newunits
                }
            }
        }
    }
}


Example: Editable multiline text for entering mathematical expressions
The following example allows to enter a numerical or math expression, such as a formula, into an editable multiline text box. CustomLib will display automatically the resulting math expression in the data tree. Moreover, the user will be able to overwrite this expression with a different formula using Ramdebugger editor. The 'Edit' button opens Ramdebugger, the graphical debugger for the scripting lenguage Tcl-Tk.

Editable multiline text box called 'TCL code' and 'Edit' button.

It is possible to create and modify the function inside Ramdebugger editor. The TCL-TK source code is colorized and supports automatic

The <condition/> node field in the .spd file is as follows,

<condition n="custom_constraints" pn="Custom constraints" ov="point,line,surface,volume" state="normal" ov_default="surface" ovm="" help="A constraint defined by using the TCL extension language">
        <dependencies node="value[@n='over_what']" att1="v" v1="node" att2="state" v2="disabled" condition="@ov='point'"/>
        <dependencies node="value[@n='over_what']" att1="state" v1="normal" condition="@ov='line' or @ov='surface' or @ov='volume'"/>
        <value n="units" pn="Units set" v="N-m-kg" values="N-m-kg,N-cm-kg,N-mm-kg"/>
        <value n="tcl_code" pn="TCL code" v="" fieldtype="long text"/>
        <value n="over_what" pn="Over" v="node" values="node,element" dict="node,node,element,element" editable="0" help="Condition will be applied to either over every selected element or every selected node"/>
        <edit_command n="edit_custom_data" pn="Edit" proc="edit_custom_data constraints" edit_type="callback"/>
</condition>

<proc n="edit_custom_data" args="custom_type callback">      
     custom_data_edit $domNode $dict $custom_type $callback      
</proc>

proc custom_data_edit { domNode dict custom_type callback } {

    if { ![interp exists ramdebugger] } { interp create ramdebugger }
    ramdebugger eval [list set argv [list -noprefs -rgeometry 600x500+300+300 \
                -onlytext]]
    package require RamDebugger

    if { [dict exists $dict tcl_code] } {
        set data [string trim [dict get $dict tcl_code]]
    } else {
        set xp {string(value[@n="tcl_code"]/@v)}
        set data [string trim [$domNode selectNodes $xp]]
    }
    if { $data eq "" } {
        set data [format "#    %s\n#    %s\n" [= "Enter TCL code to define a load"] \
                [= "Use menu 'Custom data' for help"]]
    }
    interp alias ramdebugger EditEndInRamDebugger "" CompassFEM::custom_data_edit_update \
        $callback
    ramdebugger eval [list RamDebugger::OpenFileSaveHandler "*custom data*" \
            $data EditEndInRamDebugger]

    set menu ""

    set file [file join $::ProblemTypePriv(problemtypedir) scripts custom_bc_examples.txt]
    set fin [open $file r]
    set data [read $fin]
    close $fin

    set elms ""
    set rex {\s*#\s*type:\s*(\S.*\S)\s+name:\s*(\S.*\S)\s*$}
    foreach "idxsL idxsType idxsName" [regexp -inline -all -line -indices $rex $data] {
        if { $elms ne "" } {
            lset elms end end [expr {[lindex $idxsL 0]-1}]
        }
        set type [eval [list string range $data] $idxsType]
        set name [eval [list string range $data] $idxsName]
        lappend elms [list $type $name [lindex $idxsL 0] ""]
    }
    if { $elms ne "" } {
        lset elms end end [expr {[string length $data]-1}]
    }
    set subMenus ""
    foreach i $elms {
        foreach "type name idx1 idx2" $i break
        lappend subMenus [list command "$name ($type)" {} \
                [= "View example '%s' (%s)" $name $type] "" \
                -command [list open_new_window_show $idx1 $idx2]]
    }
    lappend subMenus [list separator]
    set idx2 [expr {[string length $data]-1}]
    lappend subMenus [list command [= "All examples"] {} \
                [= "View all examples"] "" \
                -command [list open_new_window_show 0 $idx2]]
    lappend menu [list cascad [= Examples] {} examples 0 $subMenus]

    set cmd {
        set ip [RamDebugger::OpenFileInNewWindow -ask_for_file 0]
        set fin [open %FILE r]
        set data [read $fin]
        close $fin
        set d [string range $data $idx1 $idx2]
        $ip eval [list $::RamDebugger::text insert insert $d]
        $ip eval [list RamDebugger::MarkAsNotModified]
    }
    set cmd [string map [list %FILE [list $file]] $cmd]
    ramdebugger eval [list proc open_new_window_show [list idx1 idx2] $cmd]

    lappend menu [list separator]

    foreach "n nargs" [list coords 2 conec 1 nnode 0 elem_num 0 elem_normal 1 \
            epsilon 0 facLoad 0] {
        set name [= "Insert command '%s'" $n]
        set cmd {
            set t $::RamDebugger::text
            $t insert insert [list %N%]
            $t insert insert "("
            $t insert insert [string repeat , %NARGS%]
            $t insert insert ")"
            $t mark set insert "insert-[expr {%NARGS%+1}]c"
        }
        set cmd [string map [list %N% $n %NARGS% $nargs] \
                $cmd]
        lappend menu [list command $name "" "" "" -command $cmd]
    }
    lappend menu [list separator]

    foreach "n nfull" [list \
            add_to_load_vector "add_to_load_vector ?-substitute? ?-local? nodenum loadvector" \
            addload "addload ?-local? pressure|triangular_pressure|punctual_load args"] {
        set name [= "Insert command '%s'" $n]
        set cmd {
            $::RamDebugger::text insert insert [list %NFULL%]
        }
        set cmd [string map [list %NFULL% $nfull] $cmd]
        lappend menu [list command $name "" "" "" -command $cmd]
    }
    switch $custom_type {
        constraints { set title [= "Constraints data"] }
        properties { set title [= "Properties data"] }
        loads { set title [= "Loads data"] }
        default { set title [= "Custom data"] }
    }
    ramdebugger eval [list RamDebugger::AddCustomFileTypeMenu $title $menu]
}


Example: Create your own custom editor window for entering mathematical expressions


The user can create any number of custom windows in the user interface. A child window is opened automatically to display information to the user and/or get information from the user. This is a great way to add custom windows for your own purposes.
The Function Editor window can be opened by locating in the data tree the field to modify, and choosing the edit button (e.g. ?).

Example of equation defined on a field of the data tree using a Function Editor window

This will open the Function Editor window and load the current expression into it, which can be empty.

The <value/> node field in the .spd file is as follows,

<value n="Density" pn="Density" v="" unit_magnitude="M/L^3" units="kg/m^3" help="Density of the fluid" function="[loads_function editor]" pn_function="Density" function_func="function_loads"/>

proc function_loads { ftype what n pn frame domNode funcNode \
    units_var ov_var } {
    switch $ftype {       
        editor {
            return [function_editor $what $n $pn $frame $domNode \
            $funcNode $units_var $ov_var]
        }
    }  
}

proc function_editor { what n pn f domNode funcNode \
    units_var ov_var } {        
   # Create your own child window implemented in Tcl/Tk.
}

<proc n="loads_function" args="load_name">  
      return [chk_loads_function $domNode $load_name]       
</proc>

proc chk_loads_function { domNode load_name  } {
    set loads [list [list scalar]]
    if { [lsearch "editor" $load_name] != -1 } {      
        lappend loads [list editor ""]
        return [join $loads ,]
    }
   return [join $loads ,]
} 




COPYRIGHT © 2022 · GID · CIMNE