import statement + functions

2675
11
01-31-2013 12:06 PM
ChristianGass1
New Contributor III
Greetings,

I have a set of metrics I need to derive from measurements of the geometry of a massing model. The method for calculating those metrics is defined as a function with cga. However, the massing model is created by one of a dozen imported cga files, with the parameter required for the function calculated using rules in those cga files. Is it possible define a function in a "master" cga file, and use that function in an imported cga file with a parameter defined in the imported cga file?

This is the logic of it, roughed out in CGA:
## importing.cga
attr function(parameter) = parameter*someCalculation
import importedcga: "rules/imported.cga"  (function)
import importedcga2: "rules/imported2.cga"  (function)
Rule --> 
case someCondition == True: importedcga.importedRule
case someOtherCondition == True: importedcga2.importedRule
else: NIL

## imported.cga
attr parameter = 0 #empty attribute (to be set within this cga's rule).
attr function = 0 #empty attribute (overwritten by the import statement in importing.cga)
importedRule --> 
set(parameter, geometry.area)
report("metric", function(parameter))


So far I haven't had much luck in actual finding a solution. The way around doing this is to keep a copy of all functions in each of the imported.cga files...but I was hoping to avoid that so I wouldn't have to edit them all if I need to add other metrics or adjust any of the constants used by the calculations.

Thank you in advance,

Christian
0 Kudos
11 Replies
by Anonymous User
Not applicable
If I'm reading this right, I think you just need one layer deeper of importing. Currently you have a single CGA file (importing.cga) which imports many CGA files (imported.cga #1 thru N). Those imported files can then import from a single file (what you called a master file). So you have three layers of CGA rather than two. I amended your code below:

## importing.cga
import importedcga: "rules/imported.cga"  #(function)
import importedcga2: "rules/imported2.cga"  #(function)
Rule --> 
case someCondition == True: importedcga.importedRule
case someOtherCondition == True: importedcga2.importedRule
else: NIL

## imported.cga
import masterFunction: "rules/masterFunction.cga"  #(function)
attr parameter = 0 #empty attribute (to be set within this cga's rule).
importedRule --> 
set(parameter, geometry.area)
report("metric", masterFunction.function(parameter))

## masterFunction.cga - All imported.cga files import this file.
attr function(parameter) = parameter*someCalculation


Here's a little diagram to show it:
[ATTACH=CONFIG]21283[/ATTACH]
0 Kudos
ChristianGass1
New Contributor III
Ah - that worked perfectly! Many thanks for the response and example. I have a much better understanding now of what the import statement can do.

The result is attached. The 'imported' cga files mass up the building envelopes for different land uses, with estimates of GFA, population, parking requirements, student generation, etc.:
[ATTACH=CONFIG]21321[/ATTACH]

-Christian
0 Kudos
MatthiasBuehler1
Frequent Contributor
Hi guys ..

Yes, this works.

Just usually, I don't import a master rule into an other 'god rule'. 🙂

I try to pass down all values needed from the master rule down to the slave rules, if somehow possible.

What's also not so beautiful is if each slave rule itself imports e.g. a 'general reporting' rule, you will see instances of that rule in the Inspector ( each selectable ), which is visually confusing.

Thus, note the structure in the following example .. I guess it gives the best overall import structures :


code in cga file the master file "a.cga", which is assigned to the shape, with Start Rule A :

import b : "b.cga"
import c : "c.cga"

A -->
    b.B

b.Mass -->
    c.ReportBottom

   

code in cga file "b.cga" :


B -->
    extrude(world.y, 10)
    Mass
    # note that Mass must remain an 'undefined rule', so you'll not be able to avoid the yellow warning.



code in cga file "c.cga" :
ReportBottom -->
    report("BottomArea", geometry.area(bottom) )



As you see in those 3 rule files, all content is 'distributed' from the master file 'a' to 'b' and then taken back to a to be sent to 'c' for reporting.

That way, you can create rules, which e.g. creates all Masses alone, all Roofs alone, all Facades alone and distribute all via the master rule file, then cycle it back.

This is advanced shit, boys !
0 Kudos
ChristianGass1
New Contributor III
Thank you for that Matthias. Looping back to the master script to aggregate reporting and reporting parameters will definitely simplify things a bit.

Working through this a bit more, it looks like my solution may need be a bit of a hybrid of both methods, if only to avoid the attribute name overrides that can occur when importing rules. Though I think I've worked out some logic to include within my rules that avoids the issue.

I am working with essentially two types of functions: those used for analyzing the geometry of models to adjust how massing occurs mid-rule (which do not need to have any parameters exposed in the inspector), and those used for reporting (which don't have exposed parameters at the moment, but certainly could, (e.g., adjustable population-per-dwelling unit assumptions)).

So I think my solution is to:
-store the geometry-analyzing functions in one cga, and import that into the "imported" cga's, as ChrisWilkinsGeo suggested. -for information to be reported, bring  it back to the master.cga, so that the parameters can be managed easily in the inspector, and then report it through the rules executed in another imported cga (containing reporting functions).

...

Well...all that may not be articulated very well, but it is clear(er) in my head now anyway, and my mock-up seems to be operating as expected. I'll experiment a bit more and draw up a diagram to share once I've sorted it.

-Christian
0 Kudos
MatthiasBuehler1
Frequent Contributor
Cool, a breakdown of your workflow may help other users too ! Including me !

Hope you have fun learning CGA !

Matt
0 Kudos
AndréCardoso
New Contributor III
Ha, this is very very cool, very useful!

I should come by the forums more often 😛



Hi guys ..

Yes, this works.

Just usually, I don't import a master rule into an other 'god rule'. 🙂

I try to pass down all values needed from the master rule down to the slave rules, if somehow possible.

What's also not so beautiful is if each slave rule itself imports e.g. a 'general reporting' rule, you will see instances of that rule in the Inspector ( each selectable ), which is visually confusing.

Thus, note the structure in the following example .. I guess it gives the best overall import structures :


code in cga file the master file "a.cga", which is assigned to the shape, with Start Rule A :

import b : "b.cga"
import c : "c.cga"

A -->
    b.B

b.Mass -->
    c.ReportBottom

   

code in cga file "b.cga" :


B -->
    extrude(world.y, 10)
    Mass
    # note that Mass must remain an 'undefined rule', so you'll not be able to avoid the yellow warning.



code in cga file "c.cga" :
ReportBottom -->
    report("BottomArea", geometry.area(bottom) )



As you see in those 3 rule files, all content is 'distributed' from the master file 'a' to 'b' and then taken back to a to be sent to 'c' for reporting.

That way, you can create rules, which e.g. creates all Masses alone, all Roofs alone, all Facades alone and distribute all via the master rule file, then cycle it back.

This is advanced shit, boys !
0 Kudos
ChristianGass1
New Contributor III

I try to pass down all values needed from the master rule down to the slave rules, if somehow possible.


^I'm finding this part of it a bit challenging still. I'd like to work towards using the master to distribute attribute values, but I'd also like to:
- store attributes and some logic in several cga files (we'll call them 'attributeStorage'; in my actual work this would be a rule file that contains all the dimensions and conditions described in a single land use zone)
- use some logic in a master cga file to identify which attributeStorage file to reference the attributes from
- use those attribute values in another rule

This is a simplified version of some test code where I've tried to do this, using the basic structure from Matt's example:
###############
#master.cga
import as1: "C:\filepath\attributeStorage1.cga"
import as2: "C:\filepath\attributeStorage2.cga"
import mr1: C:\filepath\massingRules1.cga
import mr2: C:\filepath\massingRules.cga

attr master_height = 0 #empty

startRule -->
[INDENT]case someLogic: [/INDENT]
[INDENT][INDENT]set(master_height, as1.stored_height) as1.startRule[/INDENT][/INDENT]
[INDENT]case someOtherLogic:[/INDENT]
[INDENT][INDENT]set(master_height, as2.stored_height) as2.startRule[/INDENT][/INDENT]
[INDENT]else: doNothing.
[/INDENT]


as1.as(type) --> as(type)
as2.as(type) --> as(type)

as(type) -->
[INDENT]case type == "type1": mr1.startRule
case type == "type2": mr2.startRule
else: doNothing.[/INDENT]


###############
#attributeStorage1.cga
attr stored_height = 10
attr type = "" #empty
startRule -->
[INDENT]case someLogic: set(type, "type1") as(type)
case someOtherLogic: set(type, "type2") as(type)
else: doNothing.
[/INDENT]


###############
#attributeStorage2.cga
attr stored_height = 20
attr type = "" #empty
startRule -->
[INDENT]case someLogic: set(type, "type1") as(type)
case someOtherLogic: set(type, "type2") as(type)
else: doNothing.
[/INDENT]


###############
#massingRules1.cga
attr master_height = 0 empty #overwritten when imported by master.cga (?)
startRule -->
[INDENT]extrude(master_height)
Massing.[/INDENT]


###############
#massingRules2.cga
attr master_height = 0 empty #overwritten when imported by master.cga (?)
startRule-->
[INDENT]extrude(master_height * 0.5)
Massing.[/INDENT]



The processing roughly works like this:
1. Master.cga contains applies some logic to determine which of the imported 'attributeStorage' cga files to reference.
2. The master cga resets an empty attribute based on the corresponding attribute in the imported 'attributeStorage' cga file.
4. The selected attributeStorage rule applies some logic to set another parameter
5. The master.cga looks at that rule passed back from attributeStorage to apply some logic to select which massingRule to reference.
6. The massingRule uses the parameter that was reset in step 2 to extrude.

This does work...but only really when I only have to pass one attribute ("master_height") around. It gets very unwieldy and repetitive if I have a dozen attributeStorage cga files storing two dozen attributes each.

To avoid trying to directly pass attributes I was hoping to take advantage of the fact that the attribute of an imported rule is overwritten by an attribute of an importing rule if they have the same name - but don't quite understand the conventions for preserving attributes (or not preserving them) as described in the help documentation for the the import statement. And while I can usually get the importing rule attribute to overwrite the imported attribute, I can't seem to use the convention correctly to preserve an attribute it so I can pass the the value to another imported rule.

I have a feeling I'm making this more complicated than it needs to be.

-Christian
0 Kudos
LoringTupper
New Contributor
Sorry, but I thnk I'm missing something. I assumed that if you import a rule that the rule would simply run when you call it. I have a series of rules that relate to property use and I want to call that rule for a shape where an attribute on the shape is used to indicate which imported property use rule to apply. Below is my code for the "master" rule:

version "2012.1"

// land use types
attr PROPERTY_USE = " "

## importing.cga
import ruleC2: "rules/C-2.cga"
import ruleC3: "rules/C-3.cga"
import ruleC3_23: "rules/C-3_23.cga"
import ruleCCCOR: "rules/CC-COR.cga"
import ruleCCMH: "rules/CC-MH.cga"
import ruleCCMHX: "rules/CC-MHX.cga"
import ruleCCOR1: "rules/C-COR1.cga"
import ruleCCX: "rules/CC-X.cga"
import ruleCM1: "rules/CM-1.cga"
import ruleCM2: "rules/CM-2.cga"
import ruleI2: "rules/I-2.cga"
import ruleRM7: "rules/RM-7.cga"
import ruleSCS: "rules/S-CS.cga"
import ruleOther: "rules/Other.cga"

@StartRule
Lot-->
case PROPERTY_USE == "C-2" : ruleC2.importedRule
case PROPERTY_USE == "C-3" : ruleC3.importedRule
case PROPERTY_USE == "C-3(23)" : ruleC3_23.importedRule
case PROPERTY_USE == "CC-COR" : ruleCCCOR.importedRule
case PROPERTY_USE == "CC-MH" : ruleCCMH.importedRule
case PROPERTY_USE == "CC-MHX" : ruleCCMHX.importedRule
case PROPERTY_USE == "C-COR1" : ruleCCOR1.importedRule
case PROPERTY_USE == "CC-X" : ruleCCX.importedRule
case PROPERTY_USE == "CM-1" : ruleCM1.importedRule
case PROPERTY_USE == "CM-2" : ruleCM2.importedRule
case PROPERTY_USE == "I-2" : ruleI2.importedRule
case PROPERTY_USE == "RM-7" : ruleRM7.importedRule
case PROPERTY_USE == "S-CS" : ruleSCS.importedRule
case PROPERTY_USE == "Other" : ruleOther.importedRule
else: NIL

For each of the "case" lines above I get a yellow exclamation triangle. When you place the cursor over the triangle you get a message like the following:
e.g. for ruleC2 the message is "Undefined rule:ruleC2.importedRule"

What am I missing here?
0 Kudos
by Anonymous User
Not applicable
Do you have a rule inside those imported CGA files named "importedRule" ?  We were using that term as part of pseudo-code in the above examples, so you would need to make that match the name of the rule in the imported file. Is that the issue, or something else?
0 Kudos