Table of Contents

A list of examples

Some examples of multi scale usage (mostly syntax and prof of concept):

Well it is a copy of their content because I cannot upload rgg files. deal with it.

They are not ordered, they mostly come from Ong PhD.

Files 4, 5, 6 are the most simple ones (if you want to get started) and File 8 is the most complete.

File 1

/* ex_msc1.rgg: simple example with 3 scales */
 
scaleclass SPlant;
scaleclass SAx;
scaleclass SOrgan;
 
module Plant extends Sphere
  // {{ setLayer(2); }}
;
 
module Ax extends Cylinder
   //{{ setLayer(1); }}
;
 
module B;  /* bud of main axis */
module C;  /* bud of lateral axis */
 
protected void init()
   [
   @256; TypeAxiom, s:SRoot ==> p:Plant /> a:Ax /> {# b:B c:C f:F0 rh:RH ru:RU l:L d:D #}, 
		s /> sp:SPlant /> sa:SAx /> so:SOrgan, sp +> p, sa +> a, so +> {# b c f rh ru l d #};
 
   Axiom ==> p:Plant a:Ax L(10) D(0.5) B
             { p[radius] = 0.1; a[length] = 0.2; };
   ]
 
public void run()
   [
   B ==> F0 RH(180) [ RU(45) a:Ax C ] B
         { a[length] = 0.2; };
   C ==> F0 C;
 
   p:Plant ::> p[radius] += 5;
 
   a:Ax ::> a[length] += 10;
   ]

File 2

/* ex_msc2b.rgg: simple example with 2 scales,
   implemented with type graph and s-o-s */
 
scaleclass SGU;
scaleclass SOrgan;
 
module A;
module GU extends Cylinder
   {{ setLayer(1); }};
 
module B;  /* bud of main axis */
 
protected void init()
   [
   @256; TypeAxiom, s:SRoot ==> {# g:GU a:A #} /> {# b:B f:F #} ,
         s /> sg:SGU /> so:SOrgan,
         sg +> g, sg +> a, so +> {# b f #};
   Axiom ==> A;
   ]
 
public void run()
   [
   A ==> g:GU /> B [ <+ ^ ]
         { g[length] = 0.2; };
   (* v:GU /> *) B ==> g:GU [ < v ] F(10) F(10) B 
         { g[length] = 20; };
   ]

File 3

scaleclass STree(super.rgg);
scaleclass SAxis(super.rgg);
scaleclass SOrgan(super.rgg);
 
//modules at tree scale
module Trunk(super.length) extends F;
module Crown(super.length, super.baseRadius, super.topRadius) 
   extends Frustum;
module Tree(float ht, float htbc, float cw, float htcw) 
   //height(ht), height to base of crown(htbc), crown width(cw), 
   //height at max crown width(htcw) 
==> Trunk(htbc) Crown(htcw-htbc,cw/5.0,cw) Crown(ht-htcw,cw,cw/5.0);
//modules at axis scale
module Axis(float length, float diameter, int guCount, int age, int order);
 
//modules at organ scale
module GU(int order, super.length, super.diameter, int rank) extends F
{
	//variables for bending
	float mass = 0.5; // kg - mass of branch section marked by this GU
	Point3d pos = new Point3d(); 
	   // 3d coords - location during bending simulation 
	   // (independent of scene graph location)
	Point3d dPos = new Point3d();
	   // 3d coords - delta of location (vector) during bending simulation
	Point3d vel = new Point3d(); 
	   // cm/s - velocity in 3 directions (particle on the left, 
	   //particle on the right, gravity)
}
module Bud(int order, int type, int rank) extends Sphere(0.1);
 
//observer signal code - "extrapolate" tree scale from organ scale developments
int SIGNAL_TREE1=0;
int SIGNAL_AXIS1=1;
int SIGNAL_ORGAN1=2;
 
//structural parameters
static int GUType_l = 0; //long
static int GUType_m = 1; //medium
static int GUType_s = 2; //short
static int GUType_f = 3; //floral
static float GULenMin[] = {20,5,1,1};	
   //min length for long,med,short,flowering GUs
static float GULenMax[] = {30,20,5,5};
   //max length for long,med,short,flowering GUs
static float GUFSMMin[][] = {{0.0,0.5,0,0.9},{0,0.0,0.4,0.8},
  {0,0,0.0,0.5},{0,0.0,0.5,0}};
static float GUFSMMax[][] = {{0.5,0.9,0,1.0},{0,0.4,0.8,1.0},
  {0,0,0.5,1.0},{0,0.5,1.0,0}};
static float GUDiaInit = 0.3;
static int AxisAgeMortality = 30;
 
//bending mechanism - variables used for the simulation of bending on one axis
static int ParticleCount = 3;
static int SpringCount = ParticleCount-1;
static GU Particles[] = new GU[ParticleCount];
static float Springs[] = new float[SpringCount];
static float Frame_RATE = 1.0/30.0;		// s/step
static float Particle_MASS = 0.5;
static float Particle_VELOCITY = 0;
static float Spring_STIFFNESS = 50.0; 	//kg/s^2
static float Spring_DAMPING = 0.5; 		//kg/s
static float Gravity_ACCEL = -980.0; //m/s^2
static float Gravity_VELOCITY = Gravity_ACCEL * Frame_RATE; //m/s^2
static Point3d Gravity_DISP = new Point3d(0,0, 
      Gravity_VELOCITY * Frame_RATE); //m/s^2
static int LEFT=0;
static int RIGHT=1;
static int GRAVITY=2;
 
 
protected void init ()
[
  //Construct structure-of-scales (sos) and type graph 
  @256; TypeAxiom, sr:SRoot ==>>  {# t:Tree tr:Trunk c:Crown #} /> {# a:Axis #}  />  {# gu:GU b:Bud rh:RH ru:RU #} 
          //structure-of-scales (sos) nodes
		  , sr /> st:STree(this) /> sa:SAxis(this) /> so:SOrgan(this)  
	       , st +> {# t tr c #}, sa +> {# a #},so +> {# gu b rh ru #}			
           //connecting s-o-s nodes to type graph nodes
         {
         st.observe(so,SIGNAL_TREE1, "runTree");			
           //register tree scale dependency on organ scale
         sa.observe(so,SIGNAL_AXIS1, "runAxis");			
           //register axis scale dependency on organ scale
         so.observe(sa,SIGNAL_ORGAN1, "runOrgan");			
            //register organ scale dependency on axis scale
	 };
 
   //Construct initial instanced graph
   Axiom ==> [t:Tree][a:Axis(0,0,0,0,0)][b:Bud(0,0,0)], t /> a /> b;
]
 
public void run ()
[
	//execute rules that develop the tree's organs
	Bud(order,type,rank), (order<=1) ==>
	{
	   int typeNew = nextGUType(type);
	   float lenNew1 = random(GULenMin[typeNew],GULenMax[typeNew]);
	   float lenNew2 = random(GULenMin[typeNew],GULenMax[typeNew]);
	}
	GU(order, lenNew1,GUDiaInit,rank) 
		if(typeNew==GUType_f)(RH(137) [Axis(0,GUDiaInit,0,0, 
		   order+1) RU(40) Bud(order+1,type,0)])
	GU(order,lenNew2,GUDiaInit,rank+1) Bud(order,typeNew,rank+2);
 
	{derive();}
 
	//notify macro scales to extrapolate development 
	//from fine scale developments
	@256; so:SOrgan ::> {so.notify(SIGNAL_TREE1);}
	@256; so:SOrgan ::> {so.notify(SIGNAL_AXIS1);}
]
 
/**
* Tree scale - update height, crown width, etc. according to 
  organ scale developments
*/
protected void runTree()
[
   {println("runTree");}
   {
      float ht=0;	//new height of tree
      float htbc=Float.MAX_VALUE; //new height to base of crown of tree
      float cw=0;	//new crown width of tree
      float cwtemp=0;	//temp variable containing distance to trunk of a particular GU.
      float htcw=0;
 
      htbc = min(location((* GU(order,len,dia,rank), (order > 0) *)).z);
	if(htbc <0.1)
	   println("strange");
   }
 
   //get new macro scale values (height, crown width, etc.) from fine scale
   b:Bud ::> {
      //max GU height
      Point3d loc = endlocation(b);
      if(loc.z > ht)
         ht=loc.z;
 
      //distance to origin
      cwtemp = Math.sqrt((loc.x*loc.x)+(loc.y*loc.y));
      if(cwtemp > cw){
         cw = cwtemp;
         htcw = loc.z;
         }
   }
 
   //update macro scale (tree) with new values
   t:Tree ::> {
      t[ht] = ht;
      t[htbc] = htbc;
      t[cw] = cw;
      t[htcw] = htcw;
   }
]
 
/**
* Axis scale - dependent on organ scale developments to update 
length, diameter, bending
*/
protected void runAxis()
[
   //{println("runAxis");}
 
   //update length,diameter,GU count of axes
   a:Axis ::> {
      a[length]=sum((* a GU *).length);
      a[diameter]=diaFromLen(a[length]);
      a[guCount] = (int)count((* a GU *));
      a[age]++;}
 
   //remove old axes - mortality
   a:Axis, (a[age]>AxisAgeMortality && a[order]==1) ::> 
       {killAxis(a);} //note: recursive is killing is necessary
 
   //bending simulation - separate call from length,diameter 
   //updates to avoid computing bending of dead branches
   a:Axis, ((a[guCount] >= ParticleCount) && (a[order]==1) ) ::> {runAxisBend(a);}
 
   sa:SAxis ::> {sa.notify(SIGNAL_ORGAN1);} 
       //notify organ scale updates based ona axis changes
]
 
/**
* Axis scale - simulates bending of an axis using selected points 
  (GUs) along axis
*/
private void runAxisBend(Axis a)
{
   //select GUs according to rank along axes (of order 1)    0-----1-----2
   for(int i=0; i<ParticleCount;++i)
   {
      int posAlongAxis;
      if(i==0)
         posAlongAxis = 0;
      else if(i==ParticleCount-1)
         posAlongAxis = a.guCount-1;
      else{
         float ratioAlongAxis = (float)i/(float)(ParticleCount-1);
         posAlongAxis = (int)(ratioAlongAxis * (a.guCount-1));
      }
      [
      a g:GU, (g[rank]==posAlongAxis) ::> {
      Particles[i]=g;
      //println(g[rank]);
 
      //reset original position, velocity and delta position in particles 
      Particles[i].vel.x = 0; Particles[i].vel.y = 0; 
         Particles[i].vel.z = 0;
      Particles[i].dPos.x = 0; Particles[i].dPos.y = 0; 
         Particles[i].dPos.z = 0;
      Point3d l = location(g);
      Particles[i].pos.x = l.x; Particles[i].pos.y = l.y; 
         Particles[i].pos.z = l.z;
      //println(Particles[i].pos);
      }
      ]
   }
 
   //update mass for each particle //KIV
 
   //assume a spring connects each pair of consecutive particle
   //update lengths of springs according to distance between them
   for(int i=0; i<SpringCount;++i)
	{
	Springs[i] = Particles[i].pos.distance(Particles[i+1].pos);
	}
 
   //simulate bending for one second (upscaling is done by simply 
   //assuming the one second displacement is for a year)
   //for each particle
   for(int i=0; i<ParticleCount;++i)
	{
	//compute displacement towards left particle
	if(i!=0)
	   {
           Point3d d = displacementTowards(Particles[i], Particles[i-1], 
             Springs[i-1],LEFT,RIGHT);
           Particles[i].dPos.add(d);
           //println(Particles[i].dPos);
           }
 
        //compute displacement towards right particle
	if(i<ParticleCount)
	   {
	   Point3d d = displacementTowards(Particles[i], Particles[i+1], 
	      Springs[i],RIGHT,LEFT);
	   Particles[i].dPos.add(d);
           //println(Particles[i].dPos);
           }
 
        //compute displacement due to gravity
        Particles[i].dPos.add(Gravity_DISP);
 
	}
 
   //update positions of all particles
   for(int i=0; i<ParticleCount;++i)
	{
	Particles[i].pos.add(Particles[i].dPos);
	[
	  ==>> ^ Translate(Particles[i].pos.x, Particles[i].pos.y, 
	      Particles[i].pos.z) Sphere(1.0);
	]
	}
 
   //update RU nodes in organ scale to match simulated bend
}
 
/**
* Axis scale - Computes displacement of selected GU towards another.
*/
private Point3d displacementTowards(GU a, GU b, float springLen, 
   int velIndexA, int velIndexB)
{
	//Point3d loca = location(a);
	Point3d loca = new Point3d(a.pos);
	//Point3d locb = location(b);
	Point3d locb = new Point3d(b.pos);
 
	//vector from a to b
	Point3d ab = new Point3d(locb);
	ab.sub(loca);
 
	//vector magnitude
	float vLen = loca.distance(locb);
 
	//unit vector from a to b
	Point3d abUnit = new Point3d(ab);
	abUnit.x = abUnit.x/vLen;
	abUnit.y = abUnit.y/vLen;
	abUnit.z = abUnit.z/vLen;
 
	//compute force (spring) of a towards b
	float fSpring = Spring_STIFFNESS * (vLen-springLen);
 
	//compute force (damping) of a towards b
	float velab = 
	  (velIndexA==LEFT)?a[vel].x:((velIndexA==RIGHT)?a[vel].y:a[vel].z);
	float velba = 
	  (velIndexB==LEFT)?b[vel].x:((velIndexB==RIGHT)?b[vel].y:b[vel].z);
	float fDamp = Spring_DAMPING * (-velba-velab);
 
	//compute acceleration (m/s^2) of pa towards pb using F=ma
	float acc = (fSpring+fDamp)/a[mass];
	//println("accel: " + acc);
 
	//compute velocity (m/s) of pa towards pb - 
	//stored in member variable of pa, using acceleration
	float vel = acc * Frame_RATE;
	if(velIndexA==LEFT)
		a[vel].x = vel;
	else if(velIndexA==RIGHT)
		a[vel].y = vel;
	else
		a[vel].z = vel;
 
	//compute displacement using velocity
	float disp = vel * Frame_RATE;
	abUnit.x *= disp;
	abUnit.y *= disp;
	abUnit.z *= disp;
 
	return abUnit;
}
 
/**
* Axis scale - recursive killing method
*/
private void killAxis(Axis a)
[
	a [b:Axis] ::> {killAxis(b);} //kill higher order ones first
	a /> Node ==>> ;
]
 
/**
* Organ scale method. Updates diameters of GUs (tapering) 
  according to diameter at axis scale.
*/
protected void runOrgan()
[
	a:Axis g:GU ::> {g[diameter]= GUDiaInit + 
	  (1.0f-((float)(g[rank])/(float)a[guCount]))*
	     (a[diameter]-GUDiaInit);}
]
 
/**
* Returns next GU type based on current GU type and 
  FSM transition table
*/
private int nextGUType(int typeCurr)
{
float r = random(0.0,1.0);
if((r >= GUFSMMin[typeCurr][GUType_l])&&
   (r <= GUFSMMax[typeCurr][GUType_l]))
   return GUType_l;
else if((r >= GUFSMMin[typeCurr][GUType_m])&&
   (r <= GUFSMMax[typeCurr][GUType_m]))
   return GUType_m;
else if((r >= GUFSMMin[typeCurr][GUType_s])&&
   (r <= GUFSMMax[typeCurr][GUType_s]))
   return GUType_s;
else
   return GUType_f; 
}
 
/**
* Returns diameter in cm given height or length in cm
*/
private float diaFromLen(float len)
{
	return Math.pow((len/100.0f),1.2);
}

File 4

scaleclass ScaleA;
scaleclass ScaleB;
 
module A;
module B;
 
protected void init ()
[
	@256; TypeAxiom, s:SRoot ==> a:A /> b:B, s  /> sa:ScaleA /> sb:ScaleB, sa [a], sb [b];
 
	Axiom ==> [a:A] b:B, a /> b;
]
 
public void run ()
[
	B ==> B B;
]

File 5

scaleclass ScaleTree;
scaleclass ScaleOrgan;
 
module Tree;
module Bud;
module Internode;
 
protected void init ()
[
 
	@256; TypeAxiom, s:SRoot ==> t:Tree /> {# b:Bud i:Internode #}, 
					s /> st:ScaleTree /> so:ScaleOrgan,
					st +> t,
					so +> {# b i #};
 
	Axiom ==> [t:Tree] b:Bud, t /> b;
 
]
 
public void run ()
[
	Bud ==> Internode Bud;
]

File 6

scaleclass ScaleTree;
scaleclass ScaleOrgan;
 
module Tree;
module Bud extends Sphere(0.1);
module Internode extends F;
 
protected void init ()
[
	@256; TypeAxiom, s:SRoot ==> t:Tree /> {# b:Bud i:Internode #}, 
						    s /> st:ScaleTree /> so:ScaleOrgan, 
							st +> t,
							so +> {# b i #};
 
	Axiom ==> [t:Tree] b:Bud, t /> b;
]
 
public void run ()
[
	Bud ==> Internode Bud;
]

File 7

module A extends Cylinder(3, 1);
module B extends Cylinder(3, 0.5);
module C extends Sphere(2);
 
scaleclass S1;
scaleclass S2;
 
protected void init()
   [
    @256; TypeAxiom, s:SRoot ==> c:C /> {# a:A b:B #},
           s /> s1:S1 /> s2:S2 ,
           s2 +> {# a b #}, s1 +> c;
   Axiom ==> A;
   ]
 
 public void run()
   [
   A ==>  c:C A, B </ c;
   ]

File 8

/* treebend2.rgg, W.K., 22.06.2015;
   derived from: treebend.rgg;
   branchbend.rgg; parts from Yongzhi Ong */
 
const float SEG_LEN = 10.0;
const float CFORCE = 0.0002;
const float P_FRUIT = 0.5;
const float OFFSET = 0.4;
const float rIncr = 0.5;
const float initR = 2.0;
const float fsize = 15;
const float lsize = 20;
const int axisMortAge = 10;
 
static float tMatrix[][] =
   {{0.2, 0.2, 0.3, 0.3},
    {0.0, 0.0, 1.0, 0.0},
    {0.0, 0.0, 0.0, 1.0},
    {1.0, 0.0, 0.0, 0.0}};
static float guLength[] =
   { 40.0, 20.0, 5.0, 35.0 };
 
scaleclass STree(super.rgg);
//scaleclass SAxis(super.rgg);
//scaleclass SOrgan(super.rgg);
 
//module STree(RGG r);
module SAxis(RGG r);
module SOrgan(RGG r);
 
module GU(super.length, super.baseRadius, super.topRadius, 
   int rank, int state, Shader color) 
   extends Frustum.(setShader(color), setTransform(0, 0, -OFFSET))
   { float tippos; };
/* state: 0=long, 1=medium, 2=short, 3=floral */
module Leaf(float length, float width, int age)
   ==> F(6, 0.5, 2) Parallelogram(length, width).(setShader(GREEN));
module FBud(int rank, int age)
   { float pos; };
module Fruit(float size, int rank) 
   ==> RG F(12+size, 2, 6) Sphere(size).(setShader(RED));
module Bud(int rank, int state) extends Sphere(2).(setShader(GREEN));
module TBud(int rank) extends Sphere(5);
 
module Axis
   {
   float length;
   int nbSeg;
   int age;
   };
module AxisBase;
module AxisBud(int rank) extends Sphere(4)
   {{ setShader(YELLOW); setLayer(1); }};
module AGU(super.length, super.baseRadius, super.topRadius, 
   int rank, Shader color) 
   extends Frustum.(setShader(color), setTransform(0, 0, -OFFSET),
                    setLayer(1));
module ARH(super.angle) extends RH;
module ARU(super.angle) extends RU;
module Rx;
module Load(float size, int index) ==>
   b:Box(size, size, size)
   {{ b.setShader(BLUE); b.setLayer(1); }};
module Segment(int index) extends Cylinder(SEG_LEN, 1.5)
   {{ setShader(GRAY); setLayer(1); }};
module RBend(super.argument, int index) extends RV(argument);
 
module Trunk(super.length) extends F(length, 18, 6)
   {{ setLayer(2); }};
module Crownpart(super.length, super.baseRadius, super.topRadius)
   extends Frustum
   {{ setLayer(2); setShader(EGA_6); }};
module Tree(float ht, float htbc, float cw, float htcw)
   ==> Trunk(htbc) Crownpart(htcw-htbc, cw/5.0, cw)
       Crownpart(ht-htcw, cw, cw/5.0);
 
protected Shader coloration(int state)
   {
   if (state == 0) return EGA_4;
   if (state == 1) return PINK;
   if (state == 2) return ORANGE;
   if (state == 3) return MAGENTA;
   return BLACK;
   }
 
public int segIndex(Axis a, float p)
   {
   int k = 0;
   if (a.length > 0)
      k = (int) Math.floor(p*((float) a.nbSeg) / a.length);
   if (k >= a.nbSeg)
      k = a.nbSeg - 1;
   return k;
   }
 
public Segment findSeg(Axis a, float p)
   {
   int k;
   Segment res;
   k = segIndex(a, p);
   if (! empty((* a -descendants-> s:Segment, (s[index] == k) *)) )
	  res = first((* a -descendants-> s:Segment, (s[index] == k) *));
   else
	  res = new Segment(-1);
   return res;
   }
 
protected void init()
   [
   @256; TypeAxiom, sr:SRoot ==> {# t:Tree tr:Trunk cp:Crownpart #} />
						  {# a:Axis abu:AxisBud agu:AGU l:Load s:Segment rb:RBend  bo:Box arh:ARH aru:ARU #} />
                			  {# ab:AxisBase gu:GU lf:Leaf fb:FBud f:Fruit b:Bud tb:TBud rh:RH ru:RU rp:RP rx:Rx ff:F pa:Parallelogram rg:RG sp:Sphere #} ,
                			sr />  st:STree(this) /> sa:SAxis(this) /> so:SOrgan(this), 
				        st +> {# t tr cp #},
				        sa +> {# a abu agu l s rb bo arh aru #},
				        so +> {# ab gu lf fb f b tb rh ru rp rx ff pa rg sp #}
        {
       // sa.observe(so, 1, "bend");
        //so.observe(sa, 2, "adjust");
       // st.observe(so, 3, "runTree");
        };
   Axiom ==> [ tb:TBud(0) ] [ abu:AxisBud(0) ] [ t:Tree(0, 0, 0, 0) ],
             t /> abu /> tb;
   ]
 
public void run()
   {
   secondary(); derive();
   growGU(); derive();
   makeAxis(); derive();
   growFruits(); derive();
     [
   // @256; so:SOrgan ::> so.notify(1);
    //@256; so:SOrgan ::> so.notify(3);
	 ]
   }
 
 
 
protected void growGU()
   [
   AxisBud(rank) TBud ==> {float angle = random(-4, 4);}
              AGU(50.0, initR+rIncr, initR, rank, YELLOW)
              GU(50.0, initR+rIncr, initR, rank, 4, LIGHT_GRAY) 
              ARH(137) RH(137) ARU(angle) RU(angle)
              [ ARU(70) RU(70) a:Axis AxisBase 
                       { a.length = 0.0; a.nbSeg = 0; a.age = 0; }
                Bud(0, 0) ] 
                AxisBud(rank+1) TBud(rank+1);
 
   (* a:Axis /> AxisBase -descendants-> *) Bud(i, tp) ==> 
              Rx if (tp == 3) ( [ f:FBud(i, 0) { f.pos = a.length; } ] )
              g:GU(guLength[tp]+OFFSET, initR+rIncr, initR, i, 
                 tp, coloration(tp))
              { a.length += guLength[tp];
                g.tippos = a.length; }
              [ RH(i*137) RU(-60) Leaf(25, 20, 0) ]
              Bud(i+1, distribution(tMatrix[tp]));
 
   ]
 
protected void makeAxis()
   [
   a:Axis ==> a
      {
      a.age++;
      a.nbSeg = (int) Math.floor(a.length / SEG_LEN);
      if (a.nbSeg <= 0) a.nbSeg = 1;
      }
      [
      /* Translate(100, 0, 0)      preliminary */
      for (int j=0; j < a.nbSeg; j++)
          ( RBend(0, j) Segment(j) )
      ];                        /* branch prelim. */
   ]
 
protected void growFruits()
   [
   (* a:Axis /> AxisBase -descendants-> *) f:FBud(i, age) ==> fn:FBud(i, age+1) 
        { fn.pos = f.pos; }
        if ((age==0) || probability(P_FRUIT)) 
           ( Fruit(fsize, 0), 
             findSeg(a, f.pos) +> Load(lsize, segIndex(a, f.pos)) );
   ]
 
protected void secondary()
   [
   a:Axis, (a.age >= axisMortAge) ==>> ;
   Fruit ==>> ;
   g:GU(l, br, tr, i, tp, c) ==> gn:GU(l, br+rIncr, tr+rIncr, i, tp, c) 
                                 { gn.tippos = g.tippos; };
   Leaf(l, w, age), (age < 2) ==> Leaf(l, w, age+1);
   Leaf(l, w, age), (age >= 2) ==> ;
   Segment ==>> ;
   RBend ==>> ;
   RP ==> Rx;
   ]
 
public void bend()
   [
   r:RBend(s, i) ==> 
      RBend(s + CFORCE * sum( (* r -descendants-> l:Load *)[size]
            * (l[index] - r[index])), i);
   //sa:SAxis ::> sa.notify(2);  /* notify organ scale adjustment */
   ]
 
public void adjust()
   {
   for (applyUntilFinished())
      [  // begin workaround
      (* a:Axis /> AxisBase *) Rx g:GU ==>
         RP(endlocation(findSeg(a, g.tippos)), 1.0) g;
	  (* a:Axis /> AxisBase -descendants-> RP GU *) Rx [ fb:FBud f:Fruit ] g:GU ==>
         RP(endlocation(findSeg(a, g.tippos)), 1.0) [ fb f ] g;
      (* a:Axis /> AxisBase -descendants-> RP GU *) Rx g:GU ==>
         RP(endlocation(findSeg(a, g.tippos)), 1.0) g;
      ]  // end workaround
/* replace the workaround by the following version when bug is removed:
      [
      (* a:Axis AxisBase *) Rx (* g:GU *) ==>
         RP(endlocation(findSeg(a, g.tippos)), 1.0);
      (* a:Axis -descendants-> RP GU *) Rx (* g:GU *) ==>
         RP(endlocation(findSeg(a, g.tippos)), 1.0);
      ]
*/      
   }
 
public void runTree()
[
   {
   float ht = 0;	         //new height of tree
   float htbc = Float.MAX_VALUE; //new height to base of crown of tree
   float cw = 0;                 //new crown width of tree
   float cwtemp = 0;   //temp variable containing distance to trunk of a particular GU
   float htcw = 0;               //heigth at maximal crown width
   htbc = min(location((* GU(l, br, tr, i, tp, c), (tp != 4) *)).z);
		/* if(htbc < 0.1) println("strange"); */
   }
   //get new macro scale values (height, crown width, etc.) from fine scale
   tb:TBud ::> { ht = endlocation(tb).z; }
   b:Bud ::> {  //distance to origin
                Point3d loc = endlocation(b);
		cwtemp = Math.sqrt((loc.x*loc.x)+(loc.y*loc.y));
		if(cwtemp > cw)
		   { cw = cwtemp; htcw = loc.z; }
	    }
   //update macro scale (tree) with new values
   t:Tree ::> { t[ht] = ht;
		t[htbc] = htbc;
		t[cw] = cw;
		t[htcw] = htcw; }
]