How to Integrate External Data Files with Your COMSOL® App
Temesgen Kindo August 30, 2016
Have you ever wanted to integrate your COMSOL® software apps with external data files? These files can contain material properties, geometric dimensions, or other model inputs, and such data can derive from internal company standards or be provided by a vendor. Built-in methods in the Application Builder simplify reading from these files and displaying options read. To show this procedure, we will build an app that populates a combo box with material properties from a comma-separated values (CSV) file.
A Brief Introduction to Using External Files in Apps
To begin, let’s consider the needs of an app that uses external files:
- A user interface (UI) object for users to browse to file locations
- A UI object to let users choose between options read from the files
- Code to change relevant model object settings according to users’ selections
For the first and second items, the File Import object and a Combo Box in the Application Builder are good options. Meanwhile, there are a number of tools available that make the third task quite simple. One such tool is the Record Code feature, which generates equivalent Java® code for the tasks we perform using the user interface in the COMSOL Multiphysics® software.
When building apps, we often need more code than the methods that set the model inputs. Such auxiliary methods can convert data, manipulate arrays, or interact with the operating system, among other tasks. Again, the Application Builder includes built-in methods for such tasks, allowing you to add features to your apps with minimal coding.
Here, we will demonstrate these ideas by extending the functionality of a tuning fork app. First, we will add a combo box to select between tuning forks made of aluminum, brass, or steel. Then, we will add a File Import object to read materials from a data file.
Extending the Functionality of a Tuning Fork App
Tuning forks are used to calibrate musical instruments to a standard pitch. Tuning fork-like structures, however, are also used in industrial applications such as MEMS gyroscopes.
In an earlier blog post, we presented a tuning fork app that calculates the natural frequency of a steel tuning fork given its length. The app does the reverse as well, determining the length to achieve a target frequency. In our original demonstration, we fixed the prong radius to one commercially available size. As such, users could only adjust the prong length.
The original tuning fork application. The prong length can be changed, while other inputs are fixed.
Say that you now want users to change the material or prong radius. One way to do so is to insert Input Field or Slider objects. These UI objects allow users to specify any values. On the other hand, the tuning fork market has only certain materials and prong radii. When you want an app to offer choices between discrete options, a Combo Box is one suitable object.
These options could be hardcoded if all of the available choices are known when the app is created. But what if new choices become available on the market after the app is distributed? Hardcoding the new options and redistributing the app is not ideal. A better plan is to design an app that allows users to point to a data file and make the app populate combo boxes and other UI objects. Whenever the available choices change, users can simply provide a new data file containing the updated options. This way you make the app enforce market or company standards, without presumptively setting the standards in stone.
Combo Boxes and Recording Code
A Combo Box helps users select from a predefined list and sets the value of a variable according to their choice. The available choices are specified in a Choice List, which features a Value and Display name. The Display name is a description that users see in the UI, while the Value is what the variable will contain. Such variables associated with input objects in the UI are called the input object’s source. An app programmer can, for example, use a variable in a conditional statement to execute a set of actions based on the selected entry.
The series of screenshots below show how to add a combo box for a material selection in the tuning fork app. Aluminum, Brass, and Steel are the predefined choices. Notice that we write full names for Display name but use shorter versions for Value. The source, the string mat, takes either alm, brs, or stl when the user clicks on Aluminum, Brass, or Steel.
If we run the application now, clicking the combo box sets the string mat to either alm, brs, or stl; and that is all. The material properties in the model do not change yet. To achieve this, we have to write a Java® method and associate the method with the combo box.
Let’s name this new method change_material. In the method, we need to include Java® code for updating the density, Young’s modulus, and Poisson’s ratio. To this end, we perform the following steps:
- Click Record Code
- Switch to the Model Builder and change the material properties to some numerical values
- Click Stop Recording
The software will give us the Java® code corresponding to the set of actions we performed in the Model Builder. This is more efficient and less prone to error than looking for object names and methods in the COMSOL Programming Reference Manual.
The Java® code above, obtained using the Record Code feature, fixes the material properties to one set of values. Next, we add a conditional block to choose material properties based on the string mat. Don’t want to have to remember the Java® code syntax for an if-else statement? Use the Language Elements feature! Finally, we associate the method with the On data change event of the combo box, as shown below.
Note that even when you are only interested in scripting, with no plan to make an app, you can utilize the Record Code feature to quickly and easily generate code. To learn more, read our blog post “Apps: How to Use the Editor Tools and Record Code Features“.
Reading from a File and Dynamically Changing a Choice List
To incorporate external files, the app has to enable users to browse to such files. The Application Builder has a File Import object for this purpose. As when adding any input object, we take the following two steps:
- Associate the File Import object with an item in the model or a declaration
- Code a method that runs when the data in the input object changes
The first task is mandatory. In the current example, we will associate the File Import object with a File declaration. A File Import object stores a file path and generates an alias to the path.
The second task, which has a method run right after an input object’s data change, is optional. For instance, the value might only be used later when computing the solution. But the app we are creating has to execute the following actions when the file name in the File Import object changes:
- Read the file and store its content in a string matrix
- Store the labels for all of the rows in a string array
- Update the values and display names of the combo box based on the contents of the data file just read
To this end, we will create a new method, read_materials_file, and link it with the File Import object’s On data change event, as illustrated in the following screenshot.
Let’s now write the code for this method. In the Application Builder, methods are written using the Java® programming language. We could write such codes from scratch but the Application Builder’s Method Library contains several built-in methods for file input/output and other actions, making the process more efficient.
Reading a File
For reading comma-separated values (CSV file), we can use the readCSVFile method. The argument to this method is a string for the file path and the output is a string matrix.
String readCSVFile(String name)
For the purpose of this demonstration, we assume that the first column of the data file contains material labels, such as Aluminum and Steel from supplier 1. We want to extract this column and display it in the combo box. To extract a column from an array, we can use the built-in getColumn method. The arguments are a string matrix and the column number. The column index starts from zero, as is the case with Java® code array indices.
String getColumn(String matrix, int column)
Dynamically Changing Choice List Values and Display Names
To change values in a Choice List, we can use the built-in setList method. This method changes the values and display names of a Choice List to the strings in the argument.
setList(String value, String displayNames)
Using the above built-in methods, we obtain the following short code for reading a CSV file, storing the contents, and updating the combo box’s Choice List.
Let’s clarify the string upload:///file_matCSV and the integer array matindex in the above method. The string upload:///file_matCSV represents the file path. Go to the Access using section in the File declaration settings window to find this alias. The integer array matindex makes up values for the combo box’s Choice List.
In the method, we assume the first column in the CSV file to be material labels. These labels, extracted using the built-in method getColumn, are displayed in the combo box. The values, on the other hand, are internal tags for programming. As such, we should not expect an app user to supply them. Since we can not foresee the number of rows in the data file, we can not hardcode the value string either.
What we can do instead is get the number of rows in the file and store as many integers in an integer array. This entails changing the source data of the combo box from a string to an integer (see the integer imat in the screenshot below). Finally, make the built-in toString method convert the integer array to a string array for the setList method. That way, when a user clicks on the combo box, the integer changes to the index number of the selected row. The app can then use this number to go to the relevant row in the string matrix holding the file’s content.
The above modifications result in the following method.
Notice the old code for hardcoded material options is still around. Our goal is to let users incorporate their own material data file, if they have one. Otherwise, they need alternate options. To that end, we make a new method out of the commented section and have it called when users prefer the built-in choices to external data files. This preference can be expressed, for example, by checking on/off within a check box. The resulting implementation is highlighted below.
A method local to the check box object is used to enable the file browser or disable the browser and populate the combo box with default options, based on the value of the check box. The Record Code feature is again used to get the Java® code for enabling and disabling the file browser.
Now let’s utilize our app with the following sample CSV file.
Apps can be linked to a user-specified data file.
Here’s a look at the final version of the app in action.
Possible Further Refinement of the Tuning Fork App
The main purpose of today’s blog post is to demonstrate how to link apps to external data files. Note that some auxiliary refinements have been left out.
We assumed that the data file contains labels, densities, Young’s moduli, and Poisson ratios in columns in that order. It is possible that the data file is not in that order or contains some columns that are unnecessary for the app’s purpose. Rather than asking users to restructure their file to conform to our assumptions, we can add input fields or dialog boxes in the app to ask the user which column contains what information.
Consider the case where a user has more than one data file, say from different suppliers and possibly with different formats. Instead of reading just one file at a time, we may want to make the app append the Choice List every time a new file is read. The Application Builder has built-in methods for appending arrays, finding unique values when there are duplicates, writing the appended data to an output file for future use, and more.
In this app, the mechanical properties and length of the tuning fork can be edited while the radius is fixed. If the radius needs to be read from a data file as well, we just need to use the Record Code feature to get the Java® code for changing the radius and add it to the methods above. This is true for any model input.
We have taken for granted that the data will be in the right units. If this is not certain, we can use the Application Builder’s built-in methods for string manipulation and data validation to take care of that.
Concluding Thoughts on Using an External Data File with an App
We have shown you how to use an external data file with an app. This feature helps you design apps that cater to evolving company or market standards, without the need for modifying the code when such changes happen. The same techniques for file reading and manipulation may come in handy if your app needs a lengthy list of inputs. App users can easily store their frequently used sets of values in a data file.
To effectively and efficiently create apps, we encourage you to utilize the Application Builder’s Method Library. It contains several methods that can enhance the functionality and usability of apps. For more details, you can refer to the Introduction to Application Builder manual, particularly the Built-in Method Library appendix.
For further information on the basics of building COMSOL apps, be sure to check out our Intro to Application Builder Videos series as well as this blog post on automating model preprocessing with the Application Builder.
If you have any questions about this blog post or building simulation apps, please do not hesitate to contact us.
Oracle and Java are registered trademarks of Oracle and/or its affiliates.