Have an idea?

Visit Sawtooth Software Feedback to share your ideas on how we can improve our products.

Conditional PERL Math

I have a grid question with three columns, one is amount of miles driven, the second is the miles per gallon of the car, and the third is a drop down of fuel types. I need to run some math with those numbers, and a little different math depending on fuel type. Here is what I am working with...

[% Begin Unverified Perl

if(GETVALUE("S1_r1_c3")==1)
    {
        my $vehicleOne =(GETVALUE("S1_r1_c1")/GETVALUE("S1_r1_c1"))*.01118+(GETVALUE("S1_r1_c1")*.0000563);
    }
    elsif(GETVALUE("S1_r1_c3")==2)
        {
            my $vehicleOne =(GETVALUE("S1_r1_c1")/GETVALUE("S1_r1_c1"))*.01279+(GETVALUE("S1_r1_c1")*.0000563);
        }
if(GETVALUE("AdditionalCar")==1)
    {
    if(GETVALUE("S2_r1_c3")==1)
        {
            my $vehicleTwo =(GETVALUE("S2_r1_c1")/GETVALUE("S2_r1_c1"))*.01118+(GETVALUE("S2_r1_c1")*.0000563);
        }
        elsif(GETVALUE("S2_r1_c3")==2)
            {
                my $vehicleTwo =(GETVALUE("S2_r1_c1")/GETVALUE("S2_r1_c1"))*.01279+(GETVALUE("S2_r1_c1")*.0000563);
            }
    }
       
SETVALUE("vehicleCO2", $vehicleOne+$vehicleTwo);


End Unverified %]
asked Feb 23, 2017 by Ron H.

1 Answer

+1 vote
I haven't ran the code myself, but the thing that jumps out to me is a scoping problem.  Here's code with that exemplifies this problem:

if (1 == 1) {
    my $x = 1;
}
SETVALUE("passin", $x);


This code won't run.  Because the variable is initialized inside the "if," it exists only inside of the "if."  To fix that code, I would initialize the variable before the "if":

my $x;
if (1 == 1) {
    $x = 1;
}
SETVALUE("passin", $x);


So to fix the scope problem in your code, add this before the first "if":

my $vehicleOne = 0;
my $vehicleTwo = 0;


And then remove the "my" from inside the "if" and "elsif" codes.
answered Feb 23, 2017 by Zachary Platinum Sawtooth Software, Inc. (78,750 points)
I'm also trying to understand the functioning behind this ...
(GETVALUE("S1_r1_c1")/GETVALUE("S1_r1_c1"))*.01118

This will be 1 * .01118 = 0.01118.

Is the nesting of your brackets amiss also?
Yeah, something's off about the math.  Perhaps the second one is supposed to be "_c2" instead of "_c1."
Ah, I knew I was running into a local/global variable issue, but my lack of PERL and JS knowledge kept me from working it out. This resolved the issue. I had changed the code some since I posted this, but was still applicable even where I was at in the end. Thanks so much!
Yes, that second reference was to be _c2. This code below is what I have in place now and it appears to be working correctly.
[% Begin Unverified Perl
my $vehicleOne = 0;
my $vehicleTwo = 0;
if(GETVALUE("S1_r1_c3")==1)
    {
        $vehicleOne =((GETVALUE("S1_r1_c1")/GETVALUE("S1_r1_c2"))*.01118)+(GETVALUE("S1_r1_c1")*.0000563);
    }
    elsif(GETVALUE("S1_r1_c3")==2)
    {
        $vehicleOne =((GETVALUE("S1_r1_c1")/GETVALUE("S1_r1_c2"))*.01279)+(GETVALUE("S1_r1_c1")*.0000563);
    }
if(GETVALUE("AdditionalCar")==1)
    {
    if(GETVALUE("S2_r1_c3")==1)
        {
            $vehicleTwo =((GETVALUE("S2_r1_c1")/GETVALUE("S2_r1_c2"))*.01118)+(GETVALUE("S2_r1_c1")*.0000563);
        }
    elsif(GETVALUE("S2_r1_c3")==2)
        {
            $vehicleTwo =((GETVALUE("S2_r1_c1")/GETVALUE("S2_r1_c2"))*.01279)+(GETVALUE("S2_r1_c1")*.0000563);
        }
    }
    
my $intVar = $vehicleOne + $vehicleTwo;
return $intVar;


End Unverified %]
Now that looks so much better.
While that code worked, I tried to add in a couple more lines of math for some additional grid entries and now it doesn't seem to be picking it up. These two new grid entries are numeric entry boxes only. Any ideas where my issue is?

[% Begin Unverified Perl
my $vehicleOne = 0;
my $vehicleTwo = 0;
my $publicTrans = 0;
my $airTravel = 0;

if(GETVALUE("S1_r1_c3") == 1)
    {
        $vehicleOne = ((GETVALUE("S1_r1_c1")/GETVALUE("S1_r1_c2"))*.01118)+(GETVALUE("S1_r1_c1")*.0000563);
    }
    elsif(GETVALUE("S1_r1_c3") == 2)
    {
        $vehicleOne = ((GETVALUE("S1_r1_c1")/GETVALUE("S1_r1_c2"))*.01279)+(GETVALUE("S1_r1_c1")*.0000563);
    }
    elsif (GETVALUE("S1_r1_c3") == 3)
    {
        $vehicleOne == 0;
    }
if(GETVALUE("AdditionalCar") == 1)
    {
    if(GETVALUE("S2_r1_c3") == 1)
        {
            $vehicleTwo = ((GETVALUE("S2_r1_c1")/GETVALUE("S2_r1_c2"))*.01118)+(GETVALUE("S2_r1_c1")*.0000563);
        }
    elsif(GETVALUE("S2_r1_c3") == 2)
        {
            $vehicleTwo = ((GETVALUE("S2_r1_c1")/GETVALUE("S2_r1_c2"))*.01279)+(GETVALUE("S2_r1_c1")*.0000563);
        }
    elsif(GETVALUE("S2_r1_c3") == 3)
        {
            $vehicleTwo == 0;
        }
if(GETVALUE("S3_r1_c1") != 0)
    {
        $publicTrans = (GETVALUE("S3_r1_c1") * 0.0002230);
    }
if(GETVALUE("S4_r1_c1") != 0)
    {
        $airTravel = (GETVALUE("S4_r1_c1") * 0.0001790);
    }
}
    
my $intVar = $vehicleOne + $vehicleTwo + $publicTrans + $airTravel;
return $intVar;


End Unverified %]


It may be easier to find the problem if you adjust the tabbing to be more like this:

[% Begin Unverified Perl
my $vehicleOne = 0;
my $vehicleTwo = 0;
my $publicTrans = 0;
my $airTravel = 0;

if(GETVALUE("S1_r1_c3") == 1)
{
    $vehicleOne = ((GETVALUE("S1_r1_c1")/GETVALUE("S1_r1_c2"))*.01118)+(GETVALUE("S1_r1_c1")*.0000563);
}
elsif(GETVALUE("S1_r1_c3") == 2)
{
    $vehicleOne = ((GETVALUE("S1_r1_c1")/GETVALUE("S1_r1_c2"))*.01279)+(GETVALUE("S1_r1_c1")*.0000563);
}
elsif (GETVALUE("S1_r1_c3") == 3)
{
    $vehicleOne == 0;
}
if(GETVALUE("AdditionalCar") == 1)
{
    if(GETVALUE("S2_r1_c3") == 1)
    {
        $vehicleTwo = ((GETVALUE("S2_r1_c1")/GETVALUE("S2_r1_c2"))*.01118)+(GETVALUE("S2_r1_c1")*.0000563);
    }
    elsif(GETVALUE("S2_r1_c3") == 2)
    {
        $vehicleTwo = ((GETVALUE("S2_r1_c1")/GETVALUE("S2_r1_c2"))*.01279)+(GETVALUE("S2_r1_c1")*.0000563);
    }
    elsif(GETVALUE("S2_r1_c3") == 3)
    {
        $vehicleTwo == 0;
    }
    if(GETVALUE("S3_r1_c1") != 0)
    {
        $publicTrans = (GETVALUE("S3_r1_c1") * 0.0002230);
    }
    if(GETVALUE("S4_r1_c1") != 0)
    {
        $airTravel = (GETVALUE("S4_r1_c1") * 0.0001790);
    }
}
    
my $intVar = $vehicleOne + $vehicleTwo + $publicTrans + $airTravel;
return $intVar;
End Unverified %]


The likely cause of the problem is now apparent: your S3 and S4 code is only going to run if the respondent has an additional car.  You probably want the S3 and S4 "if" codes to run outside the additional car "if."
Thank you! Sorry for all the newb questions here, should have caught that.  One last issue. I created a pass in field for a variable called "transportationCO2" and then added this to the end of the code:

my $intVar = $vehicleOne + $vehicleTwo + $publicTrans + $airTravel;
return $intVar;

SETVALUE("transportationC02", $intVar)


Can you see why it won't apply the intVar value to this variable?
You're welcome, and no worries.  This forum is open to all levels of programming experience.  For your code, two things stand out:

First, you need a semicolon at the end of your SETVALUE line of code.  JavaScript lets users get away with not using semicolons in most cases, but most other programming languages are much less forgiving.

Second, you need to switch lines 2 and 4.  A "return" statement ends a block of code.  Code that appears after the "return" will not be ran.
Hi Zachary,
Now I'm getting a sawtooth error 269 and when I check the error log I am being told the following:

" msg= Database error. Error in "SetValue" function. Cannot update data row. Cannot find "transC02" in database. "

Despite being defined in the pass-in field (as decimal number).
Just a comment ...

Is the variable "transportationC02" or "transC02"? Make sure you are consistent with the name of this variable.
Hi Paul,
Yeah, the pass in variable and the variable noted in the code match. I had it as TransportationCO2 previously, but then changed to TransCO2 - case and spelling the same between them.
I found another post here about error 269 and their resolution had to do with placing the SETVALUE within an if statement. I worked this out below, and voila, it did in fact resolve the problem.

my $intVar = $vehicleOne + $vehicleTwo + $publicTrans + $airTravel;
if("$intVar" > 0)
{
    SETVALUE("transportationCO2", $intVar);
}
if("$intVar" == 0)
{
    SETVALUE("transportationCO2", 0);
}
return $intVar;
If you are using SetValue outside Perl, it would be something like this ...

[%SetValue(transportationCO2, 0)%]

This is simply SSI Scripting without any conditions applied. When you need to apply conditions (e.g. if $intVar==0), that's where the Perl creeps in.
This project is killing me!!!
I know there is likely a scope issue here, but I cannot seem to track down why I can't set a value with the code below.

[% Begin Unverified Perl

my $foodA = 0;
my $foodB = 0;
my $meat = 0;
my $dairy = 0;
my $fruit = 0;
my $grains = 0;
my $other = 0;
my $dietType = 0;

if(GETVALUE("S3Q1_r1_c1") == 1)
{
    if(GETVALUE("S3Q3_r1_c1") > 0)
    {
        $meat = ((GETVALUE("S3Q3_r1_c1") / 100) * (GETVALUE("S3Q2_r1_c1") * .00000553 * 30));
    }
    if(GETVALUE("S3Q3_r2_c1") > 0)
    {
        $dairy = ((GETVALUE("S3Q3_r2_c1") / 100) * (GETVALUE("S3Q2_r1_c1") * .000004 * 30));
    }
    if(GETVALUE("S3Q3_r3_c1") > 0)
    {
        $fruit = ((GETVALUE("S3Q3_r3_c1") / 100) * (GETVALUE("S3Q2_r1_c1") * .00000335 * 30));
    }
    if(GETVALUE("S3Q3_r4_c1") > 0)
    {
        $grains = ((GETVALUE("S3Q3_r4_c1") / 100) * (GETVALUE("S3Q2_r1_c1") * .00000145 * 30));
    }
    if(GETVALUE("S3Q3_r5_c1") > 0)
    {
        $other = ((GETVALUE("S3Q3_r5_c1") / 100) * (GETVALUE("S3Q2_r1_c1") * .00000224 * 30));
    }

$foodA = $meat + $dairy + $fruit + $grains + $other;
}

if(GETVALUE("S3Q1_r1_c1") == 2)
{
    if(GETVALUE("S3Q4_r1_c1") == 1)
    {
        $dietType = GETVALUE("S3Q2_r1_c1") * .00719 * 30;
    }
    if(GETVALUE("S3Q4_r1_c1") == 2)
    {
        $dietType = GETVALUE("S3Q2_r1_c1") * .00563 * 30;
    }
    if(GETVALUE("S3Q4_r1_c1") == 3)
    {
        $dietType = GETVALUE("S3Q2_r1_c1") * .00467 * 30;
    }
    if(GETVALUE("S3Q4_r1_c1") == 4)
    {
        $dietType = GETVALUE("S3Q2_r1_c1") * .00391 * 30;
    }
    if(GETVALUE("S3Q4_r1_c1") == 5)
    {
        $dietType = GETVALUE("S3Q2_r1_c1") * .00381 * 30;
    }
    if(GETVALUE("S3Q4_r1_c1") == 6)
    {
        $dietType = GETVALUE("S3Q2_r1_c1") * .00289 * 30;
    }
my $foodB = $dietType;
}


if("$foodA" > 0)
{
    SETVALUE("foodCO2", $foodA);
}
elsif("$foodB" > 0)
{
    SETVALUE("foodCO2", $foodB);
}


End Unverified %]
"$foodB" is initialized twice, once on line 4 and again on line 64.  You should remove the "my" from the second case.

On a tangential note, you can probably remove the quotation marks on lines 68 and 72.  I don't think this is causing any bugs right now, but it's just a good practice.  You want to compare a number to another number on these lines; no need to convert the values into strings.
Also make sure all these variable do exist and are spelt correctly in your code. Perl is case sensitive - this includes variable and function names.
Bah, after all this the culprit was in the grid cell references. I have a couple grids that only contain one row and one column with a drop down. Instead of being S3Q4_r1_c1 it is just S3Q4_c1. Thank you both for the feedback.
Been there and done that before. Well done on getting across the finishing line.
...