Using Ch with Autolev to Solve Dynamics Equations

Introduction

When using Autolev to solve dynamics problems, you can use it to produce C code that will run the numerical analysis in order to solve the ODE's. The typical process is to compile the resulting C code in whatever compiler you have handy and then run the compiled version. By using Ch you can not only skip the compile step, but you can also get output in the form of plots as you run the code instead of having to postprocess some output files with Excel or some other plotting utility.

Running a C program created by Autolev in Ch is the same as running any other program. You simply start Ch and type the file name, given that you're in the same directory. Therefore the majority of this web page will describe the steps necessary to use the plotting capabilities of Ch to get immediate output instead of going throught the post processing procedures. It is assumed that, if you're looking to use the code shown on this page, you have a basic working knowledge of both C and Ch. Any questions on specific code that was used can be directed to me via email.

The example code that's used here is some that I wrote while taking Multibody Dynamics, MAE 223. Therefore a lot of the specific variable names that I used can be changed depending on what you would like them to be. Also, several of the variable need to be placed in certain spots in the C file. I will try to point out where and show some of the Autolev created code to help with this, but it would probably be helpful to have your c file open to compare with pieces of code I'll show.

Overview

Here is a list of the necessary steps to create output plots directly in the Autolev C file.

  1. Add the necessary header files
  2. Define macros used for plotting
  3. Create new variables for:
    • Data (numerical array)
    • Plots (object of plot class)
  4. Close the output files
  5. Set up plots for:
    • Screen output
    • File output if desired
  6. Save data to new variables

Suggestions

Here are several suggestions that can make life easier before you begin modifying your code. These are not necessay, but I found them useful.

First is to make a separate file that has your additional code so that it can be pasted into the program instead of typed in as you go. This is handy in case you discover a small error in your Autolev program and need to create a new C file. If the changes you've made aren't saved some where, you will have to rewrite them because Autolev will overwrite the old program if you didn't move it. This also makes it easier to modify subsequent programs.

Second is to put all of your addtional code together in blocks labeled with comments before and after. If you have errors when running program or if you need to make small changes to your code, this makes it much easier to wade through the large Autolev program and isolate your code from the Autolev created portion.

Third, save plots to external files. When running the program it would be fairly common to run it several times with different initial conditions or time frames. If the plots are saved externally, then it becomes very easy to move all of the output to a separate folder and rerun the program thereby saving both sets of data.

Header files

To add plotting and numerical arrays to your program you only need to add the chplot and array header files


   #include <ctype.h> 
   #include <math.h>
   #include <stdarg.h>
   #include <stdio.h> 
   #include <stdlib.h>
   #include <string.h>

   /* Header Files Added */
   #include <array.h>
   #include <chplot.h>
   /* Header Files Added */

      

Macros

For creating the array used in plotting, you have to define the array size. This can be done directly in the declartion statement for the array, but if you want to run the program over a different time span or change the time step, the array sizes will have to change. By using a macro to define the array size, you'll only have to change the size in one place. Add a #define statements to set the number of points in the arrays.


   #define  _NAN      9.99999999999999E+305

   /* Constant Definitions Added */
   #define POINTS  51  // Number of data points
   /* Constant Definitions Added */

      

Added Variables

There are two types of variables needed to do the plotting, objects of the plot class and computational arrays. The exact number of each one will depend on how many plots you'd like to create. Obviously you'll need one plot object for each plot. Don't forget that you can put more than one data set on a plot and even create subplots if you like. As for the arrays, you need one for time and one additional one for each data set. In this code, there are four plots being created, one each for θ, ω, α, and torque. Notice that for each plot there are actually four sets of data. Each variable is a [4] × [something] array. This makes it extremely simple to plot all four set on one graph as I'll show in the plotting seciton. Also note the count variable. This will become necessary when entering data into your arrays in the output section as a way of indexing through the elements of the arrays. You can see here how the number of data points for each one was set with the maro POINTS.


   double   Pi,DEGtoRAD,RADtoDEG,z[189],...

   /* variables added */
   class CPlot plot1;
   class CPlot plot2;
   class CPlot plot3;
   class CPlot plot4;
   int count = 0;
   double time[POINTS];
   double angles[4][POINTS];
   double angvel[4][POINTS];
   double alpha[4][POINTS];
   double torques[4][POINTS];
   /* variables added */

      

Closing Output Files

In order to create the plots with Ch, the output files that Autolev writes to need to be closed. It is important to do this in the correct place of you will mess up the program. Whereas all the previous code was added before any function definitions, this code is added to the main function. The last thing the program does is write several messages to the screen to telling you about the various files. Then there's the return 0; statement. Close the files after the program writes these messages to the screen. This is done with the fclose statement as show below. Autolev uses the array Fptr[] to point to all the output files. The number of files you have will depend on the number of output statements in your Autolev code. You can also look for the comment /* Open input and output files */. The for loop just after this will show how many files are being opened. Just add the necessary number of close statements.


   /* Inform user of input and output filename(s) */
   puts( "\n Input is in the file punt.in" );
   puts( "\n Output is in the file(s) punt.i  (i=1, ..., 9)" );
   puts( "\n The output quantities and associated 
         "files are listed in file punt.dir\n" );

   /* Added to Close file and plot results */
   fclose(Fptr[1]);
   fclose(Fptr[2]);
   etc...
   /* Added to Close file and plot results */

   return 0;
   }

      

Where the etc... just means to add the number you need. Note that I didn't close the Fptr[0] file. This is the input file and I found closing it to be unecessary, but at this point the program doesn't need the file any more so closing it shouldn't hurt.

Setting Up the Plots

After you close the output files you can create the plots. I set up the program to save the plots as files and to output them directly to the screen for immediate feedback. Below are the commands used for one plot. They can be repeated as many times as necessary.


   /* Inform user of input and output filename(s) */
   puts( "\n Input is in the file punt.in" );
   puts( "\n Output is in the file(s) punt.i  (i=1, ..., 9)" );
   puts( "\n The output quantities and associated files 
         "are listed in file punt.dir\n" );

   /* Added to Close file and plot results */
   fclose(Fptr[1]);
   fclose(Fptr[2]);
   etc...

   plotxy(time, angles, "Angles", "t", "angle");

   plotxy(time, angles, "Angles", "t (s)", "Angle (deg)", &plot1);

   plot1.legend("tang ", 0);
   plot1.legend("lang1", 1);
   plot1.legend("fang ", 2);
   plot1.legend("lang2", 3);
   plot1.legendLocation(0.2,240);

   plot1.outputType(PLOT_OUTPUTTYPE_FILE, "png color", "plot_1.png");

   plot1.plotting();
   /* Added to Close file and plot results */

   return 0;
   }

      
angle plot

The first plotxy will give you the quick sceen output without using the CPlot object. The rest of the commands are for creating the plot with the CPlot object and then saving to the file. The nice part about using the plotting object is it allows you to do more with the layout. In this program, the plots are saved as .png files. I've found that the plots look nicer if saved as .eps files, but you will need a program that reads them.


Saving Data to Arrays

To get the data into the arrays you need to go to the output function in program. This is where the program writes to its output files. At the end of the fuction, there is at least one writef statement. After this, assign the output to the arrays that you defined. This is where the count variable gets used. Having initialized count to 0 previously, count will be the index for the array element that the data is saved to. Autolev uses the T variable for time. The rest of the variables are the ones that you defined in Autolev. Don't forget at the end of the assignment statements to increment the count variable to continue throught the arrays.

 

   /* Write output to screen and to output file(s) */
   writef(stdout, " %- 14.6E", T,...
   writef(Fptr[1]," %- 14.6E", T,...

   /* Added arrays for plotting */
   time[count] = T;
   angles[0][count] = (TANG*RADtoDEG);
   angles[1][count] = (LANG1*RADtoDEG);
   angles[2][count] = (FANG*RADtoDEG);
   angles[3][count] = (LANG2*RADtoDEG);

   angvel[0][count] = U1;
   angvel[1][count] = U2;
   angvel[2][count] = U3;
   angvel[3][count] = U4;

   alpha[0][count] = U1p;
   alpha[1][count] = U2p;
   alpha[2][count] = U3p;
   alpha[3][count] = U4p;

   torques[0][count] = TA;
   torques[1][count] = TH;
   torques[2][count] = TK1;
   torques[3][count] = TK2;

   count++;
   /* Added arrays for plotting */

      

Here I've data being saved to all the arrays that I set up in the variables section. With this you should be able to get plots for all your significant data from within your Autolev created C program.

Quickly Plotting with External Files

If your just trying out your program for the first time and are not sure if you need to make corrections, you might want to look at the output plots without having to define new variables inside the program. Here is a quick way to use the plotting capabilities of Ch without making as many changes. You can modify the output files that the program writes so that Ch will read them and use a separate Ch program to plot the data from the files. The main disadvantage to this method is that Ch won't plot more than one curve this way. If your output file has multiple columns of data Ch will use the first for the X values, the second for the Y, and ignore the rest. Still, it can be useful for simpler models.

First in main, locate section commented /* Write heading(s) to output file(s) */. The fprintf statements must be modifies so that Ch will see these headings as comments. This can be done by placing a pound sign "#" where the beginning of each line will be in the resulting output file. Then these files can be plotted with another program such as the one below. Notice the inputs to the plots are the modified data files. Here, I had run the program twice with different initial conditions and renamed the output file after each run. That allowed me to plot two curves simultaneously, but each file has only two columns.

The modified code from the Autolev C program.


   /* Write heading(s) to output file(s) */
   fprintf(stdout,  " FILE: p-13-10.1\n\n *** %s\n\n", string);
   fprintf(stdout,  "        T             Q2\n"
                    "     (UNITS)         (DEG)\n\n" );
   fprintf(Fptr[1], "# FILE: p-13-10.1\n#\n# *** %s#\n#\n", string);
   fprintf(Fptr[1], "#        T             Q2\n"
                    "#     (UNITS)         (DEG)\n#\n" ); 
   /* # at each line of heading */

      

The program used to plot the files.


   /* p-13-10-plotab.ch */
   /* Plotting the output of p-13-10.ch for Dynamics */
   /* Initial values: q1(0) = 45 & q2(0) = 1, 0.5 */

   #include <stdio.h>
   #include <chplot.h>

   int main()
   {
      class CPlot plot;
      char *title = "q2 vs. t w/ q1(0) = 45";
      char *xlabel = "time (s)";
      char *ylabel = "q2 (deg)"; 

      plot.dataFile("p-13-10.1(a)"); /* input file */
      plot.dataFile("p-13-10.1(b)"); /* input file */
      plot.legend("q2(0) = 1.0", 0);
      plot.legend("q2(0) = 0.5", 1);
      plot.legendLocation(9,1.5);
      plot.title(title);
      plot.label(PLOT_AXIS_X, xlabel);
      plot.label(PLOT_AXIS_Y, ylabel);
      plot.plotting();
      plot.outputType(PLOT_OUTPUTTYPE_FILE, "png color", "plot.png");
      plot.plotting();
      return 0;
   }

      

Code Examples

If you'd like to down load the code fragments that I included on the page, but can not get them directly from the page, here is a text file with all the code included.

Get the Code fragments in this text file

Example Problem and Program

On this page, there's an example problem that with the code from Autolev, the original Autolev C program, the modified C program, and all the associated output. It is a fairly simple problem that you should be able to work through easily

Example Problem and Code


Hopefully this information has been helpful. If you have any questions or comments they can be directed to Matt Campbell whose email can be found on the
MAE Grauduate Student Directory

Autolev™ is the property of OnLine Dynamics, Inc.

Powered by Ch Valid XHTML 1.0! Valid CSS!