Reading values from Excel component into Flownex Scripts!

Today we’re going to explore how we can directly reference specific cells in Excel workbooks via script. By building the direct reference in the script we can avoid having to assign specific cells as outputs and we can also avoid having to use data transfer links which can clutter our work canvas.

Code Snippets

Depending on when we want the script to execute we should choose the appropriate function to make this part of. Since I want this to be called every cycle I will make this part of the “Execute” function.

//script main execution function - called every cycle
public override void Execute(double Time)
{
//new code to go here	
}

The first bit of code we’re going to use will link our script to the excel file “Workbook (2).xlsx” in the Flownex project directory.

SpreadsheetGear.IWorkbookSet workbookSet = SpreadsheetGear.Factory.GetWorkbookSet(); 

// Path to where Flownex Project is located
System.IO.DirectoryInfo projectpath = new System.IO.DirectoryInfo(Project.ProjectRootPath);	        
		
// Create Workbook object linked to .xlsx file or .csv
SpreadsheetGear.IWorkbook workbook = workbookSet.Workbooks.Open(projectpath + "\\Tasks\\ExcelWorkBooks\\Workbook (2).xlsx"); 

Now that we’ve created our workbook object connected to the Excel file we can read in values from cells in a couple of different ways.

To read from an explicit cell (A1),

// Read from Cell A1 in Sheet 1
double excel_value_1 = Convert.ToDouble(workbook.Worksheets["Sheet1"].Cells["A1"].Value); 

to read from a set row and column,

// Read from Row 4, Column 1 in Sheet 2 (Note: row and column indices start at 0)
double excel_value_2 = Convert.ToDouble(workbook.Worksheets["Sheet2"].Cells[3,0].Value); 

If the value in the Excel cell is a string we can use the following,

// Read text from Cell B1 in Sheet 1
string excel_value_3 = workbook.Worksheets["Sheet1"].Cells["B1"].Value as string; 

There we have it! These are now internal variables to the script. To assign them as output variables we can use the following syntax (this is all still within the Execute function).

//Save Value to Output Script Variable
Output1.Value = excel_value_1;
Output2.Value = excel_value_2;
Output3.Value = excel_value_3;

Then, as per the usual, we’ll need a bit of code to initialize these output variables and make them visible/usable outside of the script.

//constructer initializes parameters
	public Script()
	{
		_Output1 = new IPS.Properties.Double();
		_Output2 = new IPS.Properties.Double();
		_Output3 = new IPS.Properties.Text();
	}

	//property declarations to make
	//parameters visible to outside world
	[PropertyUsage(UseProperty.DYNAMIC)]
	public IPS.Properties.Double Output1
	{
		get
		{
			return _Output1;
		}
	}
	
	[PropertyUsage(UseProperty.DYNAMIC)]
	public IPS.Properties.Double Output2
	{
		get
		{
			return _Output2;
		}
	}
	
	[PropertyUsage(UseProperty.DYNAMIC)]
	public IPS.Properties.Text Output3
	{
		get
		{
			return _Output3;
		}
	}
}

Happy Friday and Happy Scripting!

Avoid Spiderwebs with Direct References in Scripts

Flownex Friday Tech Tips!

It’s officially Spooky Season! In between episodes of Squid Game and re-watching Hubie Halloween I thought I could make things a little less scary by demonstrating how to get rid of the spiderwebs in our projects (AKA Data Transfer Links). We use these often with scripts, which can be very powerful, but as our networks get more complex we may want to avoid the clutter/attracting spiders.

Quick Script vs Full Script

If we’re not scared of a little C# we may decide to start with a full script. I, personally, like to use a quick script so that I can use the table inputs to define my script inputs and results.

Calling a Specific Component

We will identify the component we want to read/write to by the unique Identifier. This can be found in the input properties for the component. In this example we’ll use a pipe component. By default this would typically be “Pipe – 0” or “Pipe” followed by some other integer. This field is editable so you can change it, but it must remain unique to that specific component.

We can either specify the identifier as a string explicitly in the script:

//Referencing component "Pipe - 0"
IPS.Core.Component Pipe = Project.GetComponent("Pipe - 0");

Or we can have this as an text-type input to the script so that we can change the reference more easily. In this example we have a text variable “ComponentIdentifier”:

//Referencing component which is defined by input "ComponentIdentifier"
IPS.Core.Component Pipe = Project.GetComponent(ComponentIdentifier.ToString());

Note that we are using the ToString function to convert our text variable to a string.

Reading from Component

Now that we have our Pipe component referenced in the script we can read any of the results into our script via their display identifier using the following syntax:

//Reading from flow component
IPS.Properties.Double T_1 = Pipe.GetPropertyFromFullDisplayName("{Flow Element Results,Generic}Total temperature
") as IPS.Properties.Double;
Pipe_Temp.Value = T_1;

Note that we must use a internal variable. in this case “T_1”, to read the temperature before we assign that to the value of our script result “Pipe_Temp”.

A quick trick to determine the display name is to right-click on the result you’re interested in and select “Copy display identifiers to clipboard”.

Writing to Component

The process of modifying a component input with values from the script is very similar. We can use the above trick on our Inputs for the component to find the display identifier for the pipe diameter in this example.

//Write to component
IPS.Properties.Double diameter = Pipe.GetPropertyFromFullDisplayName("{Geometry,Inlet}Diameter") as IPS.Properties.Double;
diameter.Value = Pipe_Diameter;

Summary

Here is how we’ve set up the quick script, as you can see it is really not that scary:

And the snippet of code from the quick script:

//Identify Component
IPS.Core.Component Pipe = Project.GetComponent(ComponentIdentifier.ToString()); 

//Read from component
IPS.Properties.Double T_1 = Pipe.GetPropertyFromFullDisplayName("{Flow Element Results,Generic}Total temperature") as IPS.Properties.Double;
Pipe_Temp.Value = T_1;

//Write to component
IPS.Properties.Double diameter = Pipe.GetPropertyFromFullDisplayName("{Geometry,Inlet}Diameter") as IPS.Properties.Double;
diameter.Value = Pipe_Diameter;

Happy Friday and Happy Coding!