\documentclass[12pt]{beamer}
\input{BEAMERoptions.tex}

% ----- Packages and libraries ----- %
\usepackage[T1]{fontenc}                                % cut/paste and search with "_"
\usepackage[english]{babel}
\usepackage{graphics}
\usepackage{verbatim}
\usepackage{times}
\usepackage{graphicx}
\usepackage{epsfig}
\usepackage{subfigure}
\usepackage{amssymb}
\usepackage{amsmath, amsfonts}
\usepackage{amsthm}
\usepackage{color}
\usepackage{alltt}
\usepackage{anyfontsize}
\usepackage{fancyvrb}
\usepackage{tikz}
   \usetikzlibrary{shapes, arrows, shadows}

\newcommand{\Frametitle}[1]{\frametitle{\includegraphics[width=0.25in]{esp_logo.png}
      \hspace{0.05in} #1}}

\newcommand{\FrameTitle}[1]{\frametitle{\includegraphics[width=0.3in]{caps_logo.png}
      \hspace{0.05in} #1}}

\setbeamertemplate{navigation symbols}{}
\setbeamertemplate{caption}[numbered]

%============================
% command to repeate a ~ n-times
%============================
\newcount\myloopcounter

\newcommand{\spaces}[1][10]{%
  \myloopcounter0% initialize the loop counter
  \loop\ifnum\myloopcounter < #1 % Test if the loop counter is < #1
  ~%
  \advance\myloopcounter by 1 %
  \repeat % start again
}
%============================

% ----- Presentation information ----- %
\title[UDP/UDF Programming -- Full-featured UDP]{
\includegraphics[width=1.0in]{esp_logo.png}\\
Engineering Sketch Pad\\
UDP/UDF Programming -- Full-featured UDP\\[0.02in]
For {\tt ESP} Rev 1.28}

\author[Dannenhoffer]{
John F. Dannenhoffer, III \\
  {\footnotesize \textcolor{blue}{john@geocentrictech.com} \\[-0.03in]
    Geocentric Technologies LLC}
}

\date[July 2025]{}

% ----- Document follows ----- %

\begin{document}

\begin{frame}
  \titlepage
\end{frame}

\begin{frame}
  \Frametitle{Overview}

  \begin{itemize}
  \item Use the process from the previous session to create {\tt
    udpTrain1} from {\tt udpTemplate}
  \item Modify {\tt train1.c} to:
    \begin{itemize}
    \item add more arguments
    \item revisit top-down build process
    \item introduce bottom-up build process
    \item add output arguments (OUTPMTRs)
    \item compute sensitivities analytically
    \item add private data
    \end{itemize}
  \item Exercise2
  \end{itemize}
\end{frame}

\begin{frame}[fragile]
  \Frametitle{Listing of {\tt train1.hlp} (1)}

  \begin{minipage}{0.95\textwidth}
\begin{Verbatim}[frame=single,numbers=left,fontsize=\tiny,firstnumber=auto,xleftmargin=5mm]
UDPRIM train1 -
       purpose:
           serve as a template for UDP developer training
           it creates either:
               a straight WireBody aligned with a coordinate axis
               a rectangular SheetBody parallel to a coordinate plane
               a brick SolidBody
       input Bodys:
           -none-
       input arguments (specified as name/value pairs):
           lenx        length in x direction                   [default 0]
           leny        length in y direction                   [default 0]
           lenz        length in z direction                   [default 0]
           center      location of the center (3 values)       [default 0]
       output arguments:
           @@area      surface area (for SheetBody and SolidBody)
                                                               [default 0]
           @@volume    volume (for SolidBody)                  [default 0]
\end{Verbatim}
  \end{minipage}
\end{frame}

\begin{frame}[fragile]
  \Frametitle{Listing of {\tt train1.hlp} (2)}

  \begin{minipage}{0.95\textwidth}
\begin{Verbatim}[frame=single,numbers=left,fontsize=\tiny,firstnumber=last,xleftmargin=5mm]
       usage notes:
           lenx, leny, and lenz must be non-negative scalars

           if lenx=leny=lenz=0
               an error is raised
           elseif lenx=leny=0
               a WireBody parallel to the Z-axis is generated
           elseif leny=lenz=0
               a WireBody parallel to the X-axis is generated
           elseif lenz=lenx=0
               a WireBody parallel to the Y-axis is generated
           elseif lenx=0
               a SheetBody parallel to the YZ-plane is generated
           elseif leny=0
               a SheetBody parallel to the ZX-plane is generated
           elseif lenz=0
               a SheetBody parallel to the XY-plane is generated
           else
               a SolidBody is generated

           if center has three values
               the Body is centered at the specified location
           else
               the Body is centered at the origin

           analytic sensitivities are computed
       contributed by:
           John Dannenhoffer john@geocentrictech.com
\end{Verbatim}
  \end{minipage}
\end{frame}

\begin{frame}[fragile]
  \Frametitle{Listing of {\tt train\_1.csm} (1)}

  \begin{minipage}{0.95\textwidth}
\begin{Verbatim}[frame=single,numbers=left,fontsize=\tiny,firstnumber=auto,xleftmargin=5mm]
# train1_1
# written by John Dannenhoffer

DESPMTR   DX   4.0
DESPMTR   DY   2.0
DESPMTR   DZ   5.0

# verify that outputs and their sensitivities are correct
OUTPMTR   boxArea
OUTPMTR   boxVolume
OUTPMTR   xyArea
OUTPMTR   xyVolume
OUTPMTR   yzArea
OUTPMTR   yzVolume
OUTPMTR   zxArea
OUTPMTR   zxVolume

# box
UDPRIM    train1    lenx DX   leny DY   lenz DZ
SET       boxArea   @@area
SET       boxVolume @@volume

# plate parallel to XY plane
UDPRIM    train1    lenx DX   leny DY             center 0;0;DZ
ATTRIBUTE _color    $red
ATTRIBUTE _bcolor   $lred
SET        xyArea   @@area
SET        xyVolume @@volume
\end{Verbatim}
  \end{minipage}
\end{frame}

\begin{frame}[fragile]
  \Frametitle{Listing of {\tt train\_1.csm} (2)}

  \begin{minipage}{0.95\textwidth}
\begin{Verbatim}[frame=single,numbers=left,fontsize=\tiny,firstnumber=last,xleftmargin=5mm]
# plate parallel to YZ plane
UDPRIM    train1              leny DY   lenz DZ   center DX;0;0
ATTRIBUTE _color    $green
ATTRIBUTE _bcolor   $lgreen
SET        yzArea   @@area
SET        yzVolume @@volume

# plate parallel to ZX plane
UDPRIM    train1    lenx DX             lenz DZ   center 0;DY;0
ATTRIBUTE _color    $blue
ATTRIBUTE _bcolor   $lblue
SET        zxArea   @@area
SET        zxVolume @@volume

# wire in X direction
UDPRIM    train1    lenx DX                       center 0;DY;DZ

# wire in Y direction
UDPRIM    train1              leny DY             center DX;0;DZ

# wire in Z direction
UDPRIM    train1                        lenz DZ   center DX;DY;0

END
\end{Verbatim}
  \end{minipage}
\end{frame}

\begin{frame}
  \Frametitle{Process for Bottom-up Build of a WireBody}

  \begin{itemize}
  \item Create the Nodes (with {\tt EG\_makeTopology})
    \begin{itemize}
    \item {\tt egads.pdf} page 89
    \end{itemize}
  \item Create the Curves (with {\tt EG\_makeGeometry})
    \begin{itemize}
    \item {\tt egads.pdf} pages 18 and 73
    \end{itemize}
  \item Find the {\tt t} values on the Curves associated with the
    Nodes (with {\tt EG\_invEvaluate})
    \begin{itemize}
    \item {\tt egads.pdf} page 83
    \end{itemize}
  \item Create the Edges (with {\tt EG\_makeTopology})
  \item Create a Loop (with {\tt EG\_makeTopology})
  \item Create the WireBody (with {\tt EG\_makeTopology})
  \end{itemize}
\end{frame}

\begin{frame}[fragile]
  \Frametitle{Bottom-up WireBody Build Example (1)}

  \begin{minipage}{0.95\textwidth}
\begin{Verbatim}[frame=single,numbers=left,fontsize=\tiny,firstnumber=auto,xleftmargin=5mm]
    int    senses[2];
    double xyz[10], trange[2], xyzout[3];
    ego    enodes[3], ecurves[2], eedges[3], eloop, ebody;

    /* make Nodes */
    xyz[0] = 0;   xyz[1] = 0;   xyz[2] = 0;
    status = EG_makeTopology(context, NULL, NODE, 0, xyz, 0, NULL,
                                NULL, &(enodes[0]));
    CHECK_STATUS(EG_makeTopology);

    xyz[0] = 1;   xyz[1] = 0;   xyz[2] = 0;
    status = EG_makeTopology(context, NULL, NODE, 0, xyz, 0, NULL,
                                NULL, &(enodes[1]));
    CHECK_STATUS(EG_makeTopology);

    xyz[0] = 2;   xyz[1] = 1;   xyz[2] = 0;
    status = EG_makeTopology(context, NULL, NODE, 0, xyz, 0, NULL,
                                NULL, &(enodes[2]));
    CHECK_STATUS(EG_makeTopology);
\end{Verbatim}
  \end{minipage}
\end{frame}

\begin{frame}[fragile]
  \Frametitle{Bottom-up WireBody Build Example (2)}

  \begin{minipage}{0.95\textwidth}
\begin{Verbatim}[frame=single,numbers=left,fontsize=\tiny,firstnumber=auto,xleftmargin=5mm]
    /* make Curves */
    xyz[0] = 0;   xyz[1] = 0;   xyz[2] = 0;   /* starting point */
    xyz[3] = 1;   xyz[4] = 0;   xyz[5] = 0;   /* direction */
    status = EG_makeGeometry(context, CURVE, LINE, NULL,
                             NULL, xyz, &(ecurves[0]));
    CHECK_STATUS(EG_makeGeometry);

    xyz[0] = 1;   xyz[1] = 1;   xyz[2] = 0;   /* center */
    xyz[3] = 1;   xyz[4] = 0;   xyz[5] = 0;   /* direction 1 */
    xyz[6] = 0;   xyz[7] = 1;   xyz[8] = 0;   /* direction 2 */
    xyz[9] = 1;                               /* radius */
    status = EG_makeGeometry(context, CURVE, CIRCLE, NULL,
                             NULL, xyz, &(ecurves[1]));
    CHECK_STATUS(EG_makeGeometry);
\end{Verbatim}
  \end{minipage}
\end{frame}

\begin{frame}[fragile]
  \Frametitle{Bottom-up WireBody Build Example (3)}

  \begin{minipage}{0.95\textwidth}
\begin{Verbatim}[frame=single,numbers=left,fontsize=\tiny,firstnumber=auto,xleftmargin=5mm]
    /* find t-range and make Edges */
    xyz[0] = 0;   xyz[1] = 0;   xyz[2] = 0;
    status = EG_invEvaluate(ecurve[0], xyz, &(trange[0]), xyzout);
    CHECK_STATUS(EG_invEvaluate);

    xyz[0] = 1;   xyz[1] = 0;   xyz[2] = 0;
    status = EG_invEvaluate(ecurve[0], xyz, &(trange[1]), xyzout);
    CHECK_STATUS(EG_invEvaluate);

    status = EG_makeTopology(context, ecurve[0], EDGE, TWONODE, trange,
                             2, &(enodes[0]), NULL, &(eedges[0]));
    CHECK_STATUS(EG_makeTopology);

    xyz[0] = 1;   xyz[1] = 0;   xyz[2] = 0;
    status = EG_invEvaluate(ecurve[1], xyz, &(trange[0]), xyzout);
    CHECK_STATUS(EG_invEvaluate);

    xyz[0] = 1;   xyz[1] = 1;   xyz[2] = 0;
    status = EG_invEvaluate(ecurve[1], xyz, &(trange[1]), xyzout);
    CHECK_STATUS(EG_invEvaluate);

    status = EG_makeTopology(context, ecurve[1], EDGE, TWONODE, trange,
                             2, &(enodes[1]), NULL, &(eedges[1]));
    CHECK_STATUS(EG_makeTopology);
\end{Verbatim}
  \end{minipage}
\end{frame}

\begin{frame}[fragile]
  \Frametitle{Bottom-up WireBody Build Example (4)}

  \begin{minipage}{0.95\textwidth}
\begin{Verbatim}[frame=single,numbers=left,fontsize=\tiny,firstnumber=auto,xleftmargin=5mm]
    /* make the Loop */
    senses[0] = SFORWARD;   senses[1] = SFORWARD;
    status = EG_makeTopology(context, NULL, LOOP, OPEN, NULL,
                             2, eedges, senses, &eloop);
    CHECK_STATUS(EG_makeTopology);

    /* make the WireBody */
    statys = EG_makeTopology(context, NULL, BODY, WIREBODY, NULL,
                             1, &eloop, NULL, &ebody);
    CHECK_STATUS(EG_makeTopology);
\end{Verbatim}
  \end{minipage}
\end{frame}

\begin{frame}
  \Frametitle{Process for Bottom-up Build of a SheetBody}
  \framesubtitle{Planar SheetBody}

  \begin{itemize}
  \item Create the Nodes (with {\tt EG\_makeTopology})
  \item Create the Curves (with {\tt EG\_makeGeometry})
  \item Find the {\tt t} values on the Curves associated with the
    Nodes (with {\tt EG\_invEvaluate})
  \item Create the Edges (with {\tt EG\_makeTopology})
  \item Create a Loop (with {\tt EG\_makeLoop})
    \begin{itemize}
    \item {\tt egads.pdf} page 93
    \end{itemize}
  \item Create a Face (with {\tt EG\_makeFace})
    \begin{itemize}
    \item {\tt egads.pdf} page 92
    \end{itemize}
  \item Create a Shell (with {\tt EG\_makeTopology})
  \item Create the SheetBody (with {\tt EG\_makeTopology})
  \end{itemize}
\end{frame}

\begin{frame}
  \Frametitle{Process for Bottom-up Build of a SheetBody}
  \framesubtitle{Non-planar SheetBody}

  \begin{itemize}
  \item Create the Nodes (with {\tt EG\_makeTopology})
  \item Create the Curves (with {\tt EG\_makeGeometry})
  \item Find the {\tt t} values on the Curves associated with the
    Nodes (with {\tt EG\_invEvaluate})
  \item Create the Edges (with {\tt EG\_makeTopology})
  \item Create the Surface (with {\tt EG\_makeGeometry})
  \item Create the Pcurves (with {\tt EG\_otherCurve})
  \item Create a Loop (with {\tt EG\_makeTopology})
  \item Create a Face (with {\tt EG\_makeTopology})
  \item Create a Shell (with {\tt EG\_makeTopology})
  \item Create the SheetBody (with {\tt EG\_makeTopology})
  \end{itemize}
\end{frame}

\begin{frame}
  \Frametitle{Process for Bottom-up Build of a SolidBody}
  \framesubtitle{Planar Faces}

  \begin{itemize}
  \item Create the Nodes (with {\tt EG\_makeTopology})
  \item Create the Curves (with {\tt EG\_makeGeometry})
  \item Find the {\tt t} values on the Curves associated with the
    Nodes (with {\tt EG\_invEvaluate})
  \item Create the Edges (with {\tt EG\_makeTopology})
  \item Create the Loops (with {\tt EG\_makeLoop})
  \item Create the Faces (with {\tt EG\_makeFace})
  \item Create a Shell (with {\tt EG\_makeTopology})
  \item Create the SolidBody (with {\tt EG\_makeTopology})
  \end{itemize}
\end{frame}

\begin{frame}[fragile]
  \Frametitle{Listing of {\tt train1.c} (1)}

  \begin{minipage}{0.95\textwidth}
\begin{Verbatim}[frame=single,numbers=left,fontsize=\tiny,firstnumber=auto,xleftmargin=5mm]
/*
 ************************************************************************
 *                                                                      *
 * udpTrain1 -- training UDP                                            *
 *                                                                      *
 *             this makes a box, plate, or wire (centered at origin)    *
 *             and returns its area and volume (for training purposes)  *
 *             sensitivities are computed analytically                  *
 *                                                                      *
 *             Written by John Dannenhoffer @ Geocentric Technologies   *
 *                                                                      *
 ************************************************************************
 */

/*
 * Copyright (C) 2025  John F. Dannenhoffer, III (Geocentric Technologies))
 *
 * This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License as published by the Free Software Foundation; either
 *    version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 *     MA  02110-1301  USA
 */
\end{Verbatim}
  \end{minipage}
\end{frame}

\begin{frame}
  \Frametitle{Explanation of {\tt train1.c} (1)}

  \begin{itemize}
  \item General notes:
    \begin{itemize}
    \item the descriptions given focus on the difference between {\tt
      template.c} (from session 1) and {\tt train1.c}
    \item at times there will be no explanation slide since the code
      shown is basically a copy-paste-edit of preceeding code
    \end{itemize}
  \item Lines 4--8: identifying comment (which is different from {\tt
    template.c})
  \end{itemize}
\end{frame}

\begin{frame}[fragile]
  \Frametitle{Listing of {\tt train1.c} (2)}

  \begin{minipage}{0.95\textwidth}
\begin{Verbatim}[frame=single,numbers=left,fontsize=\tiny,firstnumber=last,xleftmargin=5mm]
/* uncomment the following to get DEBUG printouts */
//#define DEBUG 1

/* the number of "input" Bodys

   this only needs to be specified if this is a UDF (user-defined
   function) that consumes Bodys from OpenCSM's stack.  (the default
   value is 0).

   if NUMUDPINPUTBODYS>0  then exactly NUMUDPINPUTBODYS are in emodel
   if NUMUDPINPUTBODYS<0  then up to  -NUMUDPINPUTBODYS are in emodel
*/
#define NUMUDPINPUTBODYS 0

/*  the name of the routine to clean up private data

    this only needs to be specified if the UDP hangs private
    data onto udps[iudp].data (which is a void*), and that data
    could not be freed by a simple call to EG_free().  cases where
    this happens is when udps[iudp].data points to a structure that
    contains components that had be allocated via separate calls
    to EG_alloc (or malloc) or which used an allocator other
    than EG_alloc
*/
#define FREEUDPDATA(A) freePrivateData(A)
static int freePrivateData(void *data);

#define COPYUDPDATA(SRC,TGT) copyPrivateData(SRC,TGT)
static int copyPrivateData(/*@null@*/void *src, void **tgt);
\end{Verbatim}
  \end{minipage}
\end{frame}

\begin{frame}
  \Frametitle{Explanation of {\tt train1.c} (2)}

  \begin{itemize}
  \item Lines 57--61: definitions needed when the UDP/UDF has data
    that it needs to store for future sensitivity calculations.
  \end{itemize}
\end{frame}

\begin{frame}[fragile]
  \Frametitle{Listing of {\tt train1.c} (3)}

  \begin{minipage}{0.95\textwidth}
\begin{Verbatim}[frame=single,numbers=left,fontsize=\tiny,firstnumber=last,xleftmargin=5mm]
/* the number of arguments (specified below) */
#define NUMUDPARGS 6

/* set up the necessary structures (uses NUMUDPARGS) */
#include "udpUtilities.h"

/* shorthand macros for accessing argument values and velocities */
#define LENX(      IUDP  )  ((double *) (udps[IUDP].arg[0].val))[0]
#define LENX_DOT(  IUDP  )  ((double *) (udps[IUDP].arg[0].dot))[0]
#define LENX_SIZ(  IUDP  )               udps[IUDP].arg[0].size

#define LENY(      IUDP  )  ((double *) (udps[IUDP].arg[1].val))[0]
#define LENY_DOT(  IUDP  )  ((double *) (udps[IUDP].arg[1].dot))[0]
#define LENY_SIZ(  IUDP  )               udps[IUDP].arg[1].size

#define LENZ(      IUDP  )  ((double *) (udps[IUDP].arg[2].val))[0]
#define LENZ_DOT(  IUDP  )  ((double *) (udps[IUDP].arg[2].dot))[0]
#define LENZ_SIZ(  IUDP  )               udps[IUDP].arg[2].size

#define CENTER(    IUDP,I)  ((double *) (udps[IUDP].arg[3].val))[I]
#define CENTER_DOT(IUDP,I)  ((double *) (udps[IUDP].arg[3].dot))[I]
#define CENTER_SIZ(IUDP  )               udps[IUDP].arg[3].size

#define AREA(      IUDP  )  ((double *) (udps[IUDP].arg[4].val))[0]
#define AREA_DOT(  IUDP  )  ((double *) (udps[IUDP].arg[4].dot))[0]

#define VOLUME(    IUDP  )  ((double *) (udps[IUDP].arg[5].val))[0]
#define VOLUME_DOT(IUDP  )  ((double *) (udps[IUDP].arg[5].dot))[0]
\end{Verbatim}
  \end{minipage}
\end{frame}

\begin{frame}
  \Frametitle{Explanation of {\tt train1.c} (3)}

  \begin{itemize}
  \item Line 63: there are 4 input and 2 output arguments (for a
    total of 6)
  \item Line 70: this defines the velocity (dot) that is need to
    compute the sensitivities
  \item Lines 73--89: the macros for the remaining arguments. Note the
    indicies of the {\tt arg} variable
  \end{itemize}
\end{frame}

\begin{frame}[fragile]
  \Frametitle{Listing of {\tt train1.c} (4)}

  \begin{minipage}{0.95\textwidth}
\begin{Verbatim}[frame=single,numbers=left,fontsize=\tiny,firstnumber=last,xleftmargin=5mm]
/* data about possible arguments
      argNames: argument name (must be all lower case)
      argTypes: argument type: +ATTRINT      integer input
                               -ATTRINT      integer output
                               +ATTRREAL     double input  (no sensitivities)
                               -ATTRREAL     double output (no sensitivities)
                               +ATTRREALSEN  double input  (with sensitivities)
                               -ATTRREALSEN  double output (with sensitivities)
                               +ATTRSTRING   string input
                               -ATTRSTRING   *** cannot be used ***
                               +ATTRFILE     input file
                               -ATTRFILE     *** cannot be used ***
                               +ATTRREBUILD  forces rebuild if any variable in
                                             semi-colon-separated list has been changed
                               -ATTRREBUILD  *** cannot be used ***
                               +ATTRRECYCLE  forces rebuild (always) by blocking recycling
                               -ATTRRECYCLE  *** cannot be used ***
      argIdefs: default value for ATTRINT
      argDdefs: default value for ATTRREAL or ATTRREALSEN */
static char  *argNames[NUMUDPARGS] = {"lenx",      "leny",       "lenz",
                                      "center",    "area",       "volume",    };
static int    argTypes[NUMUDPARGS] = {ATTRREALSEN,  ATTRREALSEN, ATTRREALSEN,
                                      ATTRREALSEN, -ATTRREALSEN, -ATTRREALSEN,};
static int    argIdefs[NUMUDPARGS] = {0,           0,            0,
                                      0,           0,            0,           };
static double argDdefs[NUMUDPARGS] = {0.,          0.,           0.,
                                      0.,          0.,           0.,          };
\end{Verbatim}
  \end{minipage}
\end{frame}

\begin{frame}
  \Frametitle{Explanation of {\tt train1.c} (4)}

  \begin{itemize}
  \item Lines 109--110: lists the names of the 6 arguments
  \item Lines 111--112: {\tt argTypes} set to {\tt ATTRREALSEN}
    indicate that analytic sensitivities are computed in this
    UDP/UDF for these input arguments
  \item Line 112: the {\tt argTypes} for the output arguments are
    given as {\tt -ATTRREALSEN}, indicating that sensitivities are
    provided for these outputs by this UDP/UDF
  \end{itemize}
\end{frame}

\begin{frame}[fragile]
  \Frametitle{Listing of {\tt train1.c} (5)}

  \begin{minipage}{0.95\textwidth}
\begin{Verbatim}[frame=single,numbers=left,fontsize=\tiny,firstnumber=last,xleftmargin=5mm]
/* get utility routines: udpErrorStr, udpInitialize, udpReset, udpSet,
                         udpGet, udpVel, udpClean, udpMesh */
#include "udpUtilities.c"

/*
 ************************************************************************
 *                                                                      *
 *   udpExecute - execute the primitive                                 *
 *                                                                      *
 ************************************************************************
 */

int
udpExecute(ego  context,                /* (in)  EGADS context */
           ego  *ebody,                 /* (out) Body (or model) pointer */
           int  *nMesh,                 /* (out) number of associated meshes */
           char *string[])              /* (out) error message */
{
    int     status = EGADS_SUCCESS;
    int     type=0, sense[4];
    double  node1[3], node2[3], node3[3], node4[3];
    double  data[18], trange[2];
    char    *message=NULL;
    ego     enodes[4], tempNodes[2], ecurve, eedges[8], eloop, eface;
    udp_T   *udps = *Udps;

    ROUTINE(udpExecute);

    /* --------------------------------------------------------------- */
\end{Verbatim}
  \end{minipage}
\end{frame}

\begin{frame}
  \Frametitle{Explanation of {\tt train1.c} (5)}

  \begin{itemize}
  \item Lines 136--138: needed local variables
  \end{itemize}
\end{frame}

\begin{frame}[fragile]
  \Frametitle{Listing of {\tt train1.c} (6)}

  \begin{minipage}{0.95\textwidth}
\begin{Verbatim}[frame=single,numbers=left,fontsize=\tiny,firstnumber=last,xleftmargin=5mm]
#ifdef DEBUG
    /* debug printing of the input arguments */
    printf("udpExecute(context=%llx)\n", (long long)context);
    printf("lenx(0)       = %f\n", LENX(    0));
    printf("lenx_dot(0)   = %f\n", LENX_DOT(0));
    printf("leny(0)       = %f\n", LENY(    0));
    printf("leny_dot(0)   = %f\n", LENY_DOT(0));
    printf("lenz(0)       = %f\n", LENZ(    0));
    printf("lenz_dot(0)   = %f\n", LENZ_DOT(0));
    if (CENTER_SIZ(0) == 3) {
        printf("center(0)     = %f %f %f\n", CENTER(    0,0), CENTER(    0,1), CENTER(    0,2));
        printf("center_dot(0) = %f %f %f\n", CENTER_DOT(0,0), CENTER_DOT(0,1), CENTER_DOT(0,2));
    }
#endif

    /* default return values */
    *ebody  = NULL;
    *nMesh  = 0;
    *string = NULL;

    /* the place where messages to the user are placed */
    MALLOC(message, char, 100);
    message[0] = '\0';

    /* check arguments */
    if (LENX_SIZ(0) > 1) {
        snprintf(message, 100, "\"lenx\" should be a scalar");
        status  = EGADS_RANGERR;
        goto cleanup;
\end{Verbatim}
  \end{minipage}
\end{frame}

\begin{frame}
  \Frametitle{Explanation of {\tt train1.c} (6)}

  \begin{itemize}
  \item Lines 171--174: the size of the argument is checked to ensure
    that a scalar (not vector) was provided by {\tt ESP} during the call
  \end{itemize}
\end{frame}

\begin{frame}[fragile]
  \Frametitle{Listing of {\tt train1.c} (7)}

  \begin{minipage}{0.95\textwidth}
\begin{Verbatim}[frame=single,numbers=left,fontsize=\tiny,firstnumber=last,xleftmargin=5mm]
    } else if (LENX(0) < 0) {
        snprintf(message, 100, "\"lenx\" (=%f) should be non-negative", LENX(0));
        status  = EGADS_RANGERR;
        goto cleanup;

    } else if (LENY_SIZ(0) > 1) {
        snprintf(message, 100, "\"leny\" should be a scalar");
        status  = EGADS_RANGERR;
        goto cleanup;

    } else if (LENY(0) < 0) {
        snprintf(message, 100, "\"leny\" (-%f) should be non-negative", LENY(0));
        status  = EGADS_RANGERR;
        goto cleanup;

    } else if (LENZ_SIZ(0) > 1) {
        snprintf(message, 100, "\"lenz\" should be a scalar");
        status  = EGADS_RANGERR;
        goto cleanup;

    } else if (LENZ(0) < 0) {
        snprintf(message, 100, "\"lenz\" (=%f) should be non-negative", LENZ(0));
        status  = EGADS_RANGERR;
        goto cleanup;

    } else if (LENX(0) <= 0 && LENY(0) <= 0 && LENZ(0) <= 0) {
        snprintf(message, 100, "cannot have \"lenx\"=\"leny\"=\"lenz\"=0");
        status  = EGADS_GEOMERR;
        goto cleanup;

\end{Verbatim}
  \end{minipage}
\end{frame}

\begin{frame}[fragile]
  \Frametitle{Listing of {\tt train1.c} (8)}

  \begin{minipage}{0.95\textwidth}
\begin{Verbatim}[frame=single,numbers=left,fontsize=\tiny,firstnumber=last,xleftmargin=5mm]
    } else if (CENTER_SIZ(0) == 1) {
        // CENTER is not used

    } else if (CENTER_SIZ(0) != 3) {
        snprintf(message, 100, "\"center\" should contain 3 entries");
        status  = EGADS_GEOMERR;
        goto cleanup;
    }

    /* make private data (not needed here, but included to
       show how one would do this */
    if (numUdp == 0) {
        MALLOC(udps[0].data, char, 30);
    }

    /* if not after a ocsmCopy (which happens when making finite difference
       senstivities), create the string in  the private data */
    if (udps[0].data != NULL) {
        strcpy((char*)(udps[0].data), "this is test private data");
    }

    /* cache copy of arguments for future use */
    status = cacheUdp(NULL);
    CHECK_STATUS(cacheUdp);
\end{Verbatim}
  \end{minipage}
\end{frame}

\begin{frame}
  \Frametitle{Explanation of {\tt train1.c} (8)}

  \begin{itemize}
  \item Lines 216--218: if this is the first UDP/UDF of this type
    (that is {\tt numUdp} is zero), then space is allocated for the
    private data
  \item Lines 222--224: during the computation of sensitivities, the
    entire process is ``rebuilt'' in order to propagate the
    velocities.  This is done by making a copy of the Modl, so in this
    case the provate data should not be copied
  \end{itemize}
\end{frame}

\begin{frame}[fragile]
  \Frametitle{Listing of {\tt train1.c} (9)}

  \begin{minipage}{0.95\textwidth}
\begin{Verbatim}[frame=single,numbers=left,fontsize=\tiny,firstnumber=last,xleftmargin=5mm]
#ifdef DEBUG
    /* debug printing of cached input arguments */
    printf("lenx[%d]       = %f\n", numUdp, LENX(    numUdp));
    printf("lenx_dot[%d]   = %f\n", numUdp, LENX_DOT(numUdp));
    printf("leny[%d]       = %f\n", numUdp, LENY(    numUdp));
    printf("leny_dot[%d]   = %f\n", numUdp, LENY_DOT(numUdp));
    printf("lenz[%d]       = %f\n", numUdp, LENZ(    numUdp));
    printf("lenz_dot[%d]   = %f\n", numUdp, LENZ_DOT(numUdp));
    if (CENTER_SIZ(numUdp) == 3) {
        printf("center[%d]     = %f %f %f\n", numUdp, CENTER(    numUdp,0), CENTER(    numUdp,1), CENTER(    numUdp,2));
        printf("center_dot[%d] = %f %f %f\n", numUdp, CENTER_DOT(numUdp,0), CENTER_DOT(numUdp,1), CENTER_DOT(numUdp,2));
    }
#endif
\end{Verbatim}
  \end{minipage}
\end{frame}

\begin{frame}[fragile]
  \Frametitle{Listing of {\tt train1.c} (10)}

  \begin{minipage}{0.95\textwidth}
\begin{Verbatim}[frame=single,numbers=left,fontsize=\tiny,firstnumber=last,xleftmargin=5mm]
    /* check for 3D SolidBody (and make if requested) */
    if (LENX(0) > 0 && LENY(0) > 0 && LENZ(0) > 0)  {

        /*
                ^ Y
                |
                4----11----8
               /:         /|
              3 :        7 |
             /  4       /  8
            3----12----7   |
            |   2-----9|---6  --> X
            |  '       |  /
            2 1        6 5
            |'         |/
            1----10----5
           /
          Z

        */

        data[0] = -LENX(0)/2;
        data[1] = -LENY(0)/2;
        data[2] = -LENZ(0)/2;
        data[3] =  LENX(0);
        data[4] =  LENY(0);
        data[5] =  LENZ(0);
\end{Verbatim}
  \end{minipage}
\end{frame}

\begin{frame}
  \Frametitle{Explanation of {\tt train1.c} (10)}

  \begin{itemize}
  \item Lines 263--268: set up the data needed by {\tt
    EG\_makeSolidBody} for a box.  See {\tt egads.pdf} for a
    description of the data that is needed for each type of primitive
    (box, sphere, cylinder, cone, or torus)
  \end{itemize}
\end{frame}

\begin{frame}[fragile]
  \Frametitle{Listing of {\tt train1.c} (11)}

  \begin{minipage}{0.95\textwidth}
\begin{Verbatim}[frame=single,numbers=left,fontsize=\tiny,firstnumber=last,xleftmargin=5mm]
        /* move the Body if CENTER has 3 values */
        if (CENTER_SIZ(0) == 3) {
            data[0] += CENTER(0,0);
            data[1] += CENTER(0,1);
            data[2] += CENTER(0,2);
        }

        /* make SolidBody */
        status = EG_makeSolidBody(context, BOX, data, ebody);
        CHECK_STATUS(EG_makeSolidBody);

        SPLINT_CHECK_FOR_NULL(*ebody);

        /* set the output value(s) */
        status = EG_getMassProperties(*ebody, data);
        CHECK_STATUS(EG_getMassProperties);

        AREA(  numUdp) = data[1];
        VOLUME(numUdp) = data[0];

        /* remember this model (Body) */
        udps[numUdp].ebody = *ebody;

        goto cleanup;
\end{Verbatim}
  \end{minipage}
\end{frame}

\begin{frame}[fragile]
  \Frametitle{Explanation of {\tt train1.c} (11)}

  \begin{itemize}
  \item Lines 270--274: if the UDP/UDF is executed without an argument
    being set, the argument value will be set to a scalar with the
    default value.  So if the {\tt .csm} script does not specify {\tt
      center}, then {\tt CENTER\_SIZ(0)} will be 1.  If {\tt center}
    was set to a 3-vector, the values for the starting-point of the
    box will need to be modified
  \item Lines 283--284: the mass properties (including volume and
    surface area) are computed.
  \item Lines 286--287: the values of the output arguments ({\tt area}
    and {\tt volume}) are set to return them to {\tt ESP} as
    \verb+@@area+ and \verb+@@volume+
  \end{itemize}
\end{frame}

\begin{frame}[fragile]
  \Frametitle{Listing of {\tt train1.c} (12)}

  \begin{minipage}{0.95\textwidth}
\begin{Verbatim}[frame=single,numbers=left,fontsize=\tiny,firstnumber=last,xleftmargin=5mm]
    /* WireBody parallel to X axis */
    } else if (LENY(0) == 0 && LENZ(0) == 0) {
        type = OCSM_WIRE_BODY;
        node1[0] = -LENX(0)/2;   node1[1] = 0;            node1[2] = 0;
        node2[0] = +LENX(0)/2;   node2[1] = 0;            node2[2] = 0;

    /* WireBody parallel to Y axis */
    } else if (LENZ(0) == 0 && LENX(0) == 0) {
        type = OCSM_WIRE_BODY;
        node1[0] = 0;            node1[1] = -LENY(0)/2;   node1[2] = 0;
        node2[0] = 0;            node2[1] = +LENY(0)/2;   node2[2] = 0;

    /* WireBody parallel to Z axis */
    } else if (LENX(0) == 0 && LENY(0) == 0) {
        type = OCSM_WIRE_BODY;
        node1[0] = 0;            node1[1] = 0;            node1[2] = -LENZ(0)/2;
        node2[0] = 0;            node2[1] = 0;            node2[2] = +LENZ(0)/2;
\end{Verbatim}
  \end{minipage}
\end{frame}

\begin{frame}
  \Frametitle{Explanation of {\tt train1.c} (12)}

  \begin{itemize}
  \item Line 295: sets the local variable {\tt type} to indicate that
    a WireBody is to be built
  \item Lines 296--297: sets the the coordinates of the endpoints of
    the WireBody
  \end{itemize}
\end{frame}

\begin{frame}[fragile]
  \Frametitle{Listing of {\tt train1.c} (13)}

  \begin{minipage}{0.95\textwidth}
\begin{Verbatim}[frame=single,numbers=left,fontsize=\tiny,firstnumber=last,xleftmargin=5mm]
    /* SheetBody parallel to XY plane */
    } else if (LENZ(0) == 0) {
        type = OCSM_SHEET_BODY;
        node1[0] = -LENX(0)/2;   node1[1] = -LENY(0)/2;   node1[2] = 0;
        node2[0] = +LENX(0)/2;   node2[1] = -LENY(0)/2;   node2[2] = 0;
        node3[0] = +LENX(0)/2;   node3[1] = +LENY(0)/2;   node3[2] = 0;
        node4[0] = -LENX(0)/2;   node4[1] = +LENY(0)/2;   node4[2] = 0;

    /* SheetBody parallel to YZ plane */
    } else if (LENX(0) == 0) {
        type = OCSM_SHEET_BODY;
        node1[0] = 0;            node1[1] = -LENY(0)/2;   node1[2] = -LENZ(0)/2;
        node2[0] = 0;            node2[1] = +LENY(0)/2;   node2[2] = -LENZ(0)/2;
        node3[0] = 0;            node3[1] = +LENY(0)/2;   node3[2] = +LENZ(0)/2;
        node4[0] = 0;            node4[1] = -LENY(0)/2;   node4[2] = +LENZ(0)/2;

    /* SheetBody parallel to ZX plane */
    } else if (LENY(0) == 0) {
        type = OCSM_SHEET_BODY;
        node1[0] = -LENX(0)/2;   node1[1] = 0;            node1[2] = -LENZ(0)/2;
        node2[0] = -LENX(0)/2;   node2[1] = 0;            node2[2] = +LENZ(0)/2;
        node3[0] = +LENX(0)/2;   node3[1] = 0;            node3[2] = +LENZ(0)/2;
        node4[0] = +LENX(0)/2;   node4[1] = 0;            node4[2] = -LENZ(0)/2;
    }
\end{Verbatim}
  \end{minipage}
\end{frame}

\begin{frame}
  \Frametitle{Explanation of {\tt train1.c} (13)}

  \begin{itemize}
  \item Line 312: sets the local variable {\tt type} to indicate that
    a SheetBody is to be built
  \item Lines 313--316: sets the the coordinates of the corners of the
    SheetBody (which are also the endpoints for the Edges)
  \end{itemize}
\end{frame}

\begin{frame}[fragile]
  \Frametitle{Listing of {\tt train1.c} (14)}

  \begin{minipage}{0.95\textwidth}
\begin{Verbatim}[frame=single,numbers=left,fontsize=\tiny,firstnumber=last,xleftmargin=5mm]
    /* make the WireBody if required */
    if (type == OCSM_WIRE_BODY) {

        /* move the Nodes if CENTER has 3 values */
        if (CENTER_SIZ(0) == 3) {
            node1[0] += CENTER(0,0);   node1[1] += CENTER(0,1);   node1[2] += CENTER(0,2);
            node2[0] += CENTER(0,0);   node2[1] += CENTER(0,1);   node2[2] += CENTER(0,2);
        }

        /* make Nodes */
        status = EG_makeTopology(context, NULL, NODE, 0, node1, 0, NULL, NULL, &(enodes[0]));
        CHECK_STATUS(EG_makeTopology);

        status = EG_makeTopology(context, NULL, NODE, 0, node2, 0, NULL, NULL, &(enodes[1]));
        CHECK_STATUS(EG_makeTopology);

        /* make the Line */
        data[0] = node1[0];
        data[1] = node1[1];
        data[2] = node1[2];
        data[3] = node2[0] - node1[0];
        data[4] = node2[1] - node1[1];
        data[5] = node2[2] - node1[2];
        status = EG_makeGeometry(context, CURVE, LINE, NULL, NULL, data, &ecurve);
        CHECK_STATUS(EG_makeGeometry);

        /* get the parameter range */
        status = EG_invEvaluate(ecurve, node1, &(trange[0]), data);
        CHECK_STATUS(EG_invEvaluate);
\end{Verbatim}
  \end{minipage}
\end{frame}

\begin{frame}
  \Frametitle{Explanation of {\tt train1.c} (14)}

  \begin{itemize}
  \item Lines 338--341: adjusts the WireBody endpoints by the values
    in {\tt center} (if it was set in the {\tt .csm} file)
  \item Lines 344--348: the Nodes are made given their coordinates
  \item Lines 351--358: the line Curve is created (see {\tt egads.pdf}
    for descrption of the arguments)
  \item Lines 361--362: the parametric coordinate ({\tt t}) at the
    Node at the beginning of the Edge that we are going to make is
    found by inverse evaluation.  Note the inverse evaluation is
    generally slow and somewhat fragile (especially for Surfaces) and
    should be avoided if possible.
  \end{itemize}
\end{frame}

\begin{frame}[fragile]
  \Frametitle{Listing of {\tt train1.c} (15)}

  \begin{minipage}{0.95\textwidth}
\begin{Verbatim}[frame=single,numbers=left,fontsize=\tiny,firstnumber=last,xleftmargin=5mm]
        status = EG_invEvaluate(ecurve, node2, &(trange[1]), data);
        CHECK_STATUS(EG_invEvaluate);

        /* make Edge */
        status = EG_makeTopology(context, ecurve, EDGE, TWONODE, trange,
                                 2, enodes, NULL, &(eedges[0]));
        CHECK_STATUS(EG_makeTopology);

        /* make Loop from this Edge */
        sense[0] = SFORWARD;
        status = EG_makeTopology(context, NULL, LOOP, OPEN, NULL, 1, eedges, sense, &eloop);
        CHECK_STATUS(EG_makeTopology);

        /* create the WireBody (which will be returned) */
        status = EG_makeTopology(context, NULL, BODY, WIREBODY, NULL, 1, &eloop, NULL, ebody);
        CHECK_STATUS(EG_makeTopology);
        if (*ebody == NULL) goto cleanup;    // needed for splint

        /* set the output value(s) */
        AREA(  numUdp) = 0;
        VOLUME(numUdp) = 0;

        /* remember this model (Body) */
        udps[numUdp].ebody = *ebody;
\end{Verbatim}
  \end{minipage}
\end{frame}

\begin{frame}
  \Frametitle{Explanation of {\tt train1.c} (15)}

  \begin{itemize}
  \item Lines 367--369: makes the Edge with the Curve that we made
    above.  In general, Curves have infinite extent (that is there
    {\tt t} value is unbounded.  In contrast, Edges use only a portion
    of the Curve in the specified {\tt trange}.  Also note that the
    Edge uses a 2-element array of Node {\tt ego}s.
  \item Lines 372--374:  a Loop is made from the Edge.  Because {\tt
    sense[0]=SFORWARD}, the direction of the Edge and Loop are the
    same.
  \item Lines 377--379: the WireBody is made from the Loop.  Arguments
    that are not needed in any specific call to {\tt EG\_makeTopology}
    are specified as {\tt NULL}.
  \end{itemize}
\end{frame}

\begin{frame}[fragile]
  \Frametitle{Listing of {\tt train1.c} (16)}

  \begin{minipage}{0.95\textwidth}
\begin{Verbatim}[frame=single,numbers=left,fontsize=\tiny,firstnumber=last,xleftmargin=5mm]
    /* make the SheetBody if required */
    } else if (type == OCSM_SHEET_BODY) {

        /*
                  y,z,x
                    ^
                    :
              4----<3----3
              |     :    |
              4v    +- - 2^ - -> x,y,z
              |          |
              1----1>----2
        */

        /* move the Nodes if CENTER has 3 values */
        if (CENTER_SIZ(0) == 3) {
            node1[0] += CENTER(0,0);   node1[1] += CENTER(0,1);   node1[2] += CENTER(0,2);
            node2[0] += CENTER(0,0);   node2[1] += CENTER(0,1);   node2[2] += CENTER(0,2);
            node3[0] += CENTER(0,0);   node3[1] += CENTER(0,1);   node3[2] += CENTER(0,2);
            node4[0] += CENTER(0,0);   node4[1] += CENTER(0,1);   node4[2] += CENTER(0,2);
        }
\end{Verbatim}
  \end{minipage}
\end{frame}

\begin{frame}[fragile]
  \Frametitle{Listing of {\tt train1.c} (17)}

  \begin{minipage}{0.95\textwidth}
\begin{Verbatim}[frame=single,numbers=left,fontsize=\tiny,firstnumber=last,xleftmargin=5mm]
       /* make Nodes */
        status = EG_makeTopology(context, NULL, NODE, 0, node1, 0, NULL, NULL, &(enodes[0]));
        CHECK_STATUS(EG_makeTopology);

        status = EG_makeTopology(context, NULL, NODE, 0, node2, 0, NULL, NULL, &(enodes[1]));
        CHECK_STATUS(EG_makeTopology);

        status = EG_makeTopology(context, NULL, NODE, 0, node3, 0, NULL, NULL, &(enodes[2]));
        CHECK_STATUS(EG_makeTopology);

        status = EG_makeTopology(context, NULL, NODE, 0, node4, 0, NULL, NULL, &(enodes[3]));
        CHECK_STATUS(EG_makeTopology);
\end{Verbatim}
  \end{minipage}
\end{frame}

\begin{frame}[fragile]
  \Frametitle{Listing of {\tt train1.c} (18)}

  \begin{minipage}{0.95\textwidth}
\begin{Verbatim}[frame=single,numbers=left,fontsize=\tiny,firstnumber=last,xleftmargin=5mm]
        /* make the Line 1 */
        data[0] = node1[0];
        data[1] = node1[1];
        data[2] = node1[2];
        data[3] = node2[0] - node1[0];
        data[4] = node2[1] - node1[1];
        data[5] = node2[2] - node1[2];
        status = EG_makeGeometry(context, CURVE, LINE, NULL, NULL, data, &ecurve);
        CHECK_STATUS(EG_makeGeometry);

        /* get the parameter range */
        status = EG_invEvaluate(ecurve, node1, &(trange[0]), data);
        CHECK_STATUS(EG_invEvaluate);

        status = EG_invEvaluate(ecurve, node2, &(trange[1]), data);
        CHECK_STATUS(EG_invEvaluate);

        /* make Edge */
        tempNodes[0] = enodes[0];
        tempNodes[1] = enodes[1];

        status = EG_makeTopology(context, ecurve, EDGE, TWONODE, trange,
                                 2, tempNodes, NULL, &(eedges[0]));
        CHECK_STATUS(EG_makeTopology);
\end{Verbatim}
  \end{minipage}
\end{frame}

\begin{frame}[fragile]
  \Frametitle{Listing of {\tt train1.c} (19)}

  \begin{minipage}{0.95\textwidth}
\begin{Verbatim}[frame=single,numbers=left,fontsize=\tiny,firstnumber=last,xleftmargin=5mm]
        /* make the Line 2 */
        data[0] = node2[0];
        data[1] = node2[1];
        data[2] = node2[2];
        data[3] = node3[0] - node2[0];
        data[4] = node3[1] - node2[1];
        data[5] = node3[2] - node2[2];
        status = EG_makeGeometry(context, CURVE, LINE, NULL, NULL, data, &ecurve);
        CHECK_STATUS(EG_makeGeometry);

        /* get the parameter range */
        status = EG_invEvaluate(ecurve, node2, &(trange[0]), data);
        CHECK_STATUS(EG_invEvaluate);

        status = EG_invEvaluate(ecurve, node3, &(trange[1]), data);
        CHECK_STATUS(EG_invEvaluate);

        /* make Edge */
        tempNodes[0] = enodes[1];
        tempNodes[1] = enodes[2];

        status = EG_makeTopology(context, ecurve, EDGE, TWONODE, trange,
                                 2, tempNodes, NULL, &(eedges[1]));
        CHECK_STATUS(EG_makeTopology);
\end{Verbatim}
  \end{minipage}
\end{frame}

\begin{frame}[fragile]
  \Frametitle{Listing of {\tt train1.c} (20)}

  \begin{minipage}{0.95\textwidth}
\begin{Verbatim}[frame=single,numbers=left,fontsize=\tiny,firstnumber=last,xleftmargin=5mm]
        /* make the Line 3 */
        data[0] = node3[0];
        data[1] = node3[1];
        data[2] = node3[2];
        data[3] = node4[0] - node3[0];
        data[4] = node4[1] - node3[1];
        data[5] = node4[2] - node3[2];
        status = EG_makeGeometry(context, CURVE, LINE, NULL, NULL, data, &ecurve);
        CHECK_STATUS(EG_makeGeometry);

        /* get the parameter range */
        status = EG_invEvaluate(ecurve, node3, &(trange[0]), data);
        CHECK_STATUS(EG_invEvaluate);

        status = EG_invEvaluate(ecurve, node4, &(trange[1]), data);
        CHECK_STATUS(EG_invEvaluate);

        /* make Edge */
        tempNodes[0] = enodes[2];
        tempNodes[1] = enodes[3];

        status = EG_makeTopology(context, ecurve, EDGE, TWONODE, trange,
                                 2, tempNodes, NULL, &(eedges[2]));
        CHECK_STATUS(EG_makeTopology);
\end{Verbatim}
  \end{minipage}
\end{frame}

\begin{frame}[fragile]
  \Frametitle{Listing of {\tt train1.c} (21)}

  \begin{minipage}{0.95\textwidth}
\begin{Verbatim}[frame=single,numbers=left,fontsize=\tiny,firstnumber=last,xleftmargin=5mm]
        /* make the Line 4 */
        data[0] = node4[0];
        data[1] = node4[1];
        data[2] = node4[2];
        data[3] = node1[0] - node4[0];
        data[4] = node1[1] - node4[1];
        data[5] = node1[2] - node4[2];
        status = EG_makeGeometry(context, CURVE, LINE, NULL, NULL, data, &ecurve);
        CHECK_STATUS(EG_makeGeometry);

        /* get the parameter range */
        status = EG_invEvaluate(ecurve, node4, &(trange[0]), data);
        CHECK_STATUS(EG_invEvaluate);

        status = EG_invEvaluate(ecurve, node1, &(trange[1]), data);
        CHECK_STATUS(EG_invEvaluate);

        /* make Edge */
        tempNodes[0] = enodes[3];
        tempNodes[1] = enodes[0];

        status = EG_makeTopology(context, ecurve, EDGE, TWONODE, trange,
                                 2, tempNodes, NULL, &(eedges[3]));
        CHECK_STATUS(EG_makeTopology);
\end{Verbatim}
  \end{minipage}
\end{frame}

\begin{frame}[fragile]
  \Frametitle{Listing of {\tt train1.c} (22)}

  \begin{minipage}{0.95\textwidth}
\begin{Verbatim}[frame=single,numbers=left,fontsize=\tiny,firstnumber=last,xleftmargin=5mm]
        /* make Loop from this Edge */
        sense[0] = SFORWARD;   sense[1] = SFORWARD;
        sense[2] = SFORWARD;   sense[3] = SFORWARD;

        status = EG_makeTopology(context, NULL, LOOP, CLOSED, NULL, 4, eedges, sense, &eloop);
        CHECK_STATUS(EG_makeTopology);

        /* make Face from the loop */
        status = EG_makeFace(eloop, SREVERSE, NULL, &eface);
        CHECK_STATUS(EG_makeFace);

        /* create the FaceBody (which will be returned) */
        status = EG_makeTopology(context, NULL, BODY, FACEBODY, NULL, 1, &eface, NULL, ebody);
        CHECK_STATUS(EG_makeTopology);
        if (*ebody == NULL) goto cleanup;    // needed for splint

        /* set the output value(s) */
        status = EG_getMassProperties(*ebody, data);
        CHECK_STATUS(EG_getMassProperties);

        AREA(  numUdp) = data[1];
        VOLUME(numUdp) = 0;

        /* remember this model (Body) */
        udps[numUdp].ebody = *ebody;
\end{Verbatim}
  \end{minipage}
\end{frame}

\begin{frame}
  \Frametitle{Explanation of {\tt train1.c} (22)}

  \begin{itemize}
  \item Lines 517--521: the Loop is made from the array of Edges
    created above.  Because all the Edges were created with a
    counter-clockwise sense, they can all have a {\tt sense} of {\tt
      SFORWARD}
  \item Lines 524--525: make a Face given a Loop.  The function {\tt
    EG\_makeFace} only applies when the Face is planar.  When it is
    not, one must make a Surface (with {\tt EG\_makeGeometry}), make
    the PCurves (with {\tt EG\_otherCurve}), then make the Loop (with
    {\tt EG\_makeTopology}) and then finally the Face (with {\tt
      EG\_makeTopology})
  \item Lines 528--530: a FaceBody is made from the Face.
  \end{itemize}
\end{frame}

\begin{frame}[fragile]
  \Frametitle{Listing of {\tt train1.c} (23)}

  \begin{minipage}{0.95\textwidth}
\begin{Verbatim}[frame=single,numbers=left,fontsize=\tiny,firstnumber=last,xleftmargin=5mm]
    }

cleanup:
#ifdef DEBUG
    printf("udpExecute -> numUdp=%d, *ebody=%llx\n", numUdp, (long long)(*ebody));
#endif

    if (strlen(message) > 0) {
        *string = message;
        printf("%s\n", message);
    } else if (status != EGADS_SUCCESS) {
        FREE(message);
        *string = udpErrorStr(status);
    } else {
        FREE(message);
    }

    return status;
}
\end{Verbatim}
  \end{minipage}
\end{frame}

\begin{frame}[fragile]
  \Frametitle{Listing of {\tt train1.c} (24)}

  \begin{minipage}{0.95\textwidth}
\begin{Verbatim}[frame=single,numbers=left,fontsize=\tiny,firstnumber=last,xleftmargin=5mm]
/*
 ************************************************************************
 *                                                                      *
 *   udpSensitivity - return sensitivity derivatives for the "real" argument *
 *                                                                      *
 ************************************************************************
 */

int
udpSensitivity(ego    ebody,            /* (in)  Body pointer */
               int    npnt,             /* (in)  number of points */
               int    entType,          /* (in)  OCSM entity type */
               int    entIndex,         /* (in)  OCSM entity index (bias-1) */
   /*@unused@*/double uvs[],            /* (in)  parametric coordinates for evaluation */
               double vels[])           /* (out) velocities */
{
    int    status = EGADS_SUCCESS;

    int    iudp, judp, i, inode, iedge, iface;
    double lenx_dot, leny_dot, lenz_dot, xcent_dot, ycent_dot, zcent_dot;
    double area_dot=0, volume_dot=0;

    ROUTINE(udpSensitivity);

    /* --------------------------------------------------------------- */
\end{Verbatim}
  \end{minipage}
\end{frame}

\begin{frame}
  \Frametitle{Explanation of {\tt train1.c} (24)}

  \begin{itemize}
  \item Lines 568--574: this defines the function that is called when
    {\tt ESP} want sensitivities.  It is passed the {\tt ego} of the
    Body that was created by {\tt udpExecute} and well as a
    description of the type of sensitivity that is requested.
  \end{itemize}
\end{frame}

\begin{frame}[fragile]
  \Frametitle{Listing of {\tt train1.c} (25)}

  \begin{minipage}{0.95\textwidth}
\begin{Verbatim}[frame=single,numbers=left,fontsize=\tiny,firstnumber=last,xleftmargin=5mm]
#ifdef DEBUG
    if (uvs != NULL) {
        printf("udpSensitivity(ebody=%llx, npnt=%d, entType=%d, entIndex=%d, uvs=%f %f)\n",
               (long long)ebody, npnt, entType, entIndex, uvs[0], uvs[1]);
    } else {
        printf("udpSensitivity(ebody=%llx, npnt=%d, entType=%d, entIndex=%d, uvs=NULL)\n",
               (long long)ebody, npnt, entType, entIndex);
    }
#endif

    /* the following line should be included if sensitivities
       are not computed analytically */
//$$$    return EGADS_NOLOAD;

    /* check that ebody matches one of the ebodys */
    iudp = 0;
    for (judp = 1; judp <= numUdp; judp++) {
        if (ebody == udps[judp].ebody) {
            iudp = judp;
            break;
        }
    }
    if (iudp <= 0) {
        status = EGADS_NOTMODEL;
        goto cleanup;
    }
\end{Verbatim}
  \end{minipage}
\end{frame}

\begin{frame}
  \Frametitle{Explanation of {\tt train1.c} (25)}

  \begin{itemize}
  \item Lines 600--606: find the instance of this UDP.  Recall that a
    UDP can be called several times with (possibly) different
    arguments.  This is the reason we cache the arguments and store
    the Body {\tt ego} with the statement {\tt
      udps[numUdp].ebody=*ebody} at the end of {\tt udpExecute}.
  \item Lines 607--610: return an error if a match is not found.
    (Such an error would indicate that something went wrong in {\tt
    ESP} and should be reported to the {\tt ESP} team.)
  \end{itemize}
\end{frame}

\begin{frame}[fragile]
  \Frametitle{Listing of {\tt train1.c} (26)}

  \begin{minipage}{0.95\textwidth}
\begin{Verbatim}[frame=single,numbers=left,fontsize=\tiny,firstnumber=last,xleftmargin=5mm]
    /* remember the velocity of center */
    if (CENTER_SIZ(iudp) == 3) {
        xcent_dot = CENTER_DOT(iudp,0);
        ycent_dot = CENTER_DOT(iudp,1);
        zcent_dot = CENTER_DOT(iudp,2);
    } else {
        xcent_dot = 0;
        ycent_dot = 0;
        zcent_dot = 0;
    }
\end{Verbatim}
  \end{minipage}
\end{frame}

\begin{frame}
  \Frametitle{Explanation of {\tt train1.c} (26)}

  \begin{itemize}
  \item Lines 612--620: find the sensitivity of the center point with
    respect the sensitivity of the arguments (in this case {\tt
      CENTER}). Notice that we use {\tt CENTER\_DOT(iudp,0)} because we
    are finding the sensitivity for the ${\tt iudp}^{th}$ instance of
    this UDP.
  \end{itemize}
\end{frame}

\begin{frame}[fragile]
  \Frametitle{Listing of {\tt train1.c} (27)}

  \begin{minipage}{0.95\textwidth}
\begin{Verbatim}[frame=single,numbers=left,fontsize=\tiny,firstnumber=last,xleftmargin=5mm]
    /* WireBody in X direction */
    if        (LENY(iudp) <= 0 && LENZ(iudp) <= 0) {
        if (entType == OCSM_NODE) {
            inode = entIndex;

            if        (inode == 1) {
                lenx_dot = -LENX_DOT(iudp)/2;   leny_dot = 0;   lenz_dot = 0;
            } else if (inode == 2) {
                lenx_dot = +LENX_DOT(iudp)/2;   leny_dot = 0;   lenz_dot = 0;
            } else {
                status = OCSM_NODE_NOT_FOUND;
                goto cleanup;
            }
        } else if (entType == OCSM_EDGE) {
            iedge = entIndex;

            if (iedge == 1) {
                lenx_dot = 0;   leny_dot = 0;   lenz_dot = 0;
            } else {
                status = OCSM_EDGE_NOT_FOUND;
                goto cleanup;
            }
        } else {
            status = OCSM_ILLEGAL_VALUE;
            goto cleanup;
        }
\end{Verbatim}
  \end{minipage}
\end{frame}

\begin{frame}
  \Frametitle{Explanation of {\tt train1.c} (27)}

  \begin{itemize}
  \item Lines 623--633: this call to {\tt udpSensitivity} is asking to
    compute the sensitivity of a Node location.  The equations in
    line 627 and 629 are simply derivatives of the location that was
    specified in {\tt udpExecute}.
  \item Lines 634--642: because this UDP creates WireBodys that are
    parallel to a coordinate axis, the sensitivity of any point along
    the Edge (normal to the tangent direction) is the same.  So we can
    just compute a single sensitivity value.
  \end{itemize}
\end{frame}

\begin{frame}[fragile]
  \Frametitle{Listing of {\tt train1.c} (28)}

  \begin{minipage}{0.95\textwidth}
\begin{Verbatim}[frame=single,numbers=left,fontsize=\tiny,firstnumber=last,xleftmargin=5mm]
        /* return (constant) velocities, accounting for the movement
           of the CENTER if it set */
        for (i = 0; i < npnt; i++) {
            vels[3*i  ] = lenx_dot + xcent_dot;
            vels[3*i+1] = leny_dot + ycent_dot;
            vels[3*i+2] = lenz_dot + zcent_dot;
        }
\end{Verbatim}
  \end{minipage}
\end{frame}

\begin{frame}
  \Frametitle{Explanation of {\tt train1.c} (28)}

  \begin{itemize}
  \item Lines 649--653: add the sensitivity of the center point to the
    sensitivity.  This corresponds to lines 338--341.
  \end{itemize}
\end{frame}

\begin{frame}[fragile]
  \Frametitle{Listing of {\tt train1.c} (29)}

  \begin{minipage}{0.95\textwidth}
\begin{Verbatim}[frame=single,numbers=left,fontsize=\tiny,firstnumber=last,xleftmargin=5mm]
    /* WireBody in Y direction */
    } else if (LENZ(iudp) <= 0 && LENX(iudp) <= 0) {
        if (entType == OCSM_NODE) {
            inode = entIndex;

            if        (inode == 1) {
                lenx_dot = 0;   leny_dot = -LENY_DOT(iudp)/2;   lenz_dot = 0;
            } else if (inode == 2) {
                lenx_dot = 0;   leny_dot = +LENY_DOT(iudp)/2;   lenz_dot = 0;
            } else {
                status = OCSM_NODE_NOT_FOUND;
                goto cleanup;
            }
        } else if (entType == OCSM_EDGE) {
            iedge = entIndex;

            if (iedge == 1) {
                lenx_dot = 0;   leny_dot = 0;   lenz_dot = 0;
            } else {
                status = OCSM_EDGE_NOT_FOUND;
                goto cleanup;
            }
        } else {
            status = OCSM_ILLEGAL_VALUE;
            goto cleanup;
        }
\end{Verbatim}
  \end{minipage}
\end{frame}

\begin{frame}[fragile]
  \Frametitle{Listing of {\tt train1.c} (30)}

  \begin{minipage}{0.95\textwidth}
\begin{Verbatim}[frame=single,numbers=left,fontsize=\tiny,firstnumber=last,xleftmargin=5mm]
        /* return (constant) velocities, accounting for the movement
           of the CENTER if it set */
        for (i = 0; i < npnt; i++) {
            vels[3*i  ] = lenx_dot + xcent_dot;
            vels[3*i+1] = leny_dot + ycent_dot;
            vels[3*i+2] = lenz_dot + zcent_dot;
        }
\end{Verbatim}
  \end{minipage}
\end{frame}

\begin{frame}[fragile]
  \Frametitle{Listing of {\tt train1.c} (31)}

  \begin{minipage}{0.95\textwidth}
\begin{Verbatim}[frame=single,numbers=left,fontsize=\tiny,firstnumber=last,xleftmargin=5mm]
    /* WireBody in Z direction */
    } else if (LENX(iudp) <= 0 && LENY(iudp) <= 0) {
        if (entType == OCSM_NODE) {
            inode = entIndex;

            if        (inode == 1) {
                lenx_dot = 0;   leny_dot = 0;   lenz_dot = -LENZ_DOT(iudp)/2;
            } else if (inode == 2) {
                lenx_dot = 0;   leny_dot = 0;   lenz_dot = +LENZ_DOT(iudp)/2;
            } else {
                status = OCSM_NODE_NOT_FOUND;
                goto cleanup;
            }
        } else if (entType == OCSM_EDGE) {
            iedge = entIndex;

            if (iedge == 1) {
                lenx_dot = 0;   leny_dot = 0;   lenz_dot = 0;
            } else {
                status = OCSM_EDGE_NOT_FOUND;
                goto cleanup;
            }
        } else {
            status = OCSM_ILLEGAL_VALUE;
            goto cleanup;
        }
\end{Verbatim}
  \end{minipage}
\end{frame}

\begin{frame}[fragile]
  \Frametitle{Listing of {\tt train1.c} (32)}

  \begin{minipage}{0.95\textwidth}
\begin{Verbatim}[frame=single,numbers=left,fontsize=\tiny,firstnumber=last,xleftmargin=5mm]
        /* return (constant) velocities, accounting for the movement
           of the CENTER if it set */
        for (i = 0; i < npnt; i++) {
            vels[3*i  ] = lenx_dot + xcent_dot;
            vels[3*i+1] = leny_dot + ycent_dot;
            vels[3*i+2] = lenz_dot + zcent_dot;
        }
\end{Verbatim}
  \end{minipage}
\end{frame}

\begin{frame}[fragile]
  \Frametitle{Listing of {\tt train1.c} (33)}

  \begin{minipage}{0.95\textwidth}
\begin{Verbatim}[frame=single,numbers=left,fontsize=\tiny,firstnumber=last,xleftmargin=5mm]
    /* SheetBody in XY plane (since the velocity on each Node and Edge is
                              a constant, we need to just compute one value) */
    } else if (LENZ(iudp) <= 0) {
        if        (entType == OCSM_NODE) {
            inode = entIndex;

            if        (inode == 1) {
                lenx_dot = -LENX_DOT(iudp)/2;   leny_dot = -LENY_DOT(iudp)/2;   lenz_dot = 0;
            } else if (inode == 2) {
                lenx_dot = +LENX_DOT(iudp)/2;   leny_dot = -LENY_DOT(iudp)/2;   lenz_dot = 0;
            } else if (inode == 3) {
                lenx_dot = +LENX_DOT(iudp)/2;   leny_dot = +LENY_DOT(iudp)/2;   lenz_dot = 0;
            } else if (inode == 4) {
                lenx_dot = -LENX_DOT(iudp)/2;   leny_dot = +LENY_DOT(iudp)/2;   lenz_dot = 0;
            } else {
                status = OCSM_NODE_NOT_FOUND;
                goto cleanup;
            }
        } else if (entType == OCSM_EDGE) {
            iedge = entIndex;

            if        (iedge == 1) {
                lenx_dot = 0;   leny_dot = -LENY_DOT(iudp)/2;   lenz_dot = 0;
            } else if (iedge == 2) {
                lenx_dot = +LENX_DOT(iudp)/2;   leny_dot = 0;   lenz_dot = 0;
            } else if (iedge == 3) {
                lenx_dot = 0;   leny_dot = +LENY_DOT(iudp)/2;   lenz_dot = 0;
\end{Verbatim}
  \end{minipage}
\end{frame}

\begin{frame}[fragile]
  \Frametitle{Listing of {\tt train1.c} (34)}

  \begin{minipage}{0.95\textwidth}
\begin{Verbatim}[frame=single,numbers=left,fontsize=\tiny,firstnumber=last,xleftmargin=5mm]
            } else if (iedge == 4) {
                lenx_dot = -LENX_DOT(iudp)/2;   leny_dot = 0;   lenz_dot = 0;
            } else {
                status = OCSM_EDGE_NOT_FOUND;
                goto cleanup;
            }
        } else if (entType == OCSM_FACE) {
            iface = entIndex;

            if (iface == 1) {
                lenx_dot = 0;   leny_dot = 0;   lenz_dot = 0;
            } else {
                status = OCSM_FACE_NOT_FOUND;
                goto cleanup;
            }
        } else {
            status = OCSM_ILLEGAL_VALUE;
            goto cleanup;
        }

        /* return (constant) velocities, accounting for the movement
           of the CENTER if it set */
        for (i = 0; i < npnt; i++) {
            vels[3*i  ] = lenx_dot + xcent_dot;
            vels[3*i+1] = leny_dot + ycent_dot;
            vels[3*i+2] = lenz_dot + zcent_dot;
        }

        /* compute the sensitivities of the area */
        area_dot = LENX_DOT(iudp) * LENY(iudp) + LENY_DOT(iudp) * LENX(iudp);
\end{Verbatim}
  \end{minipage}
\end{frame}

\begin{frame}
  \Frametitle{Explanation of {\tt train1.c} (34)}

  \begin{itemize}
  \item Line 776: The area of the SheetBody is given by {\tt
    area=lenx*leny}.  Here we analytically differente this (using the
    product rule) to give us {\tt
      area\_dot=lenx\_dot*leny+leny\_dot*lenx}.  Notice that we use the
    values and dots for the ${\tt iudp}^{th}$ instance of this UDP.
  \end{itemize}
\end{frame}

\begin{frame}[fragile]
  \Frametitle{Listing of {\tt train1.c} (35)}

  \begin{minipage}{0.95\textwidth}
\begin{Verbatim}[frame=single,numbers=left,fontsize=\tiny,firstnumber=last,xleftmargin=5mm]
    /* SheetBody in YZ plane (since the velocity on each Node and Edge is
                              a constant, we need to just compute one value) */
    } else if (LENX(iudp) <= 0) {
        if        (entType == OCSM_NODE) {
            inode = entIndex;

            if        (inode == 1) {
                lenx_dot = 0;   leny_dot = -LENY_DOT(iudp)/2;   lenz_dot = -LENZ_DOT(iudp)/2;
            } else if (inode == 2) {
                lenx_dot = 0;   leny_dot = +LENY_DOT(iudp)/2;   lenz_dot = -LENZ_DOT(iudp)/2;
            } else if (inode == 3) {
                lenx_dot = 0;   leny_dot = +LENY_DOT(iudp)/2;   lenz_dot = +LENZ_DOT(iudp)/2;
            } else if (inode == 4) {
                lenx_dot = 0;   leny_dot = -LENY_DOT(iudp)/2;   lenz_dot = +LENZ_DOT(iudp)/2;
            } else {
                status = OCSM_NODE_NOT_FOUND;
                goto cleanup;
            }
        } else if (entType == OCSM_EDGE) {
            iedge = entIndex;

            if        (iedge == 1) {
                lenx_dot = 0;   leny_dot = 0;   lenz_dot = -LENZ_DOT(iudp)/2;
            } else if (iedge == 2) {
                lenx_dot = 0;   leny_dot = +LENY_DOT(iudp)/2;   lenz_dot = 0;
            } else if (iedge == 3) {
                lenx_dot = 0;   leny_dot = 0;   lenz_dot = +LENZ_DOT(iudp)/2;
\end{Verbatim}
  \end{minipage}
\end{frame}

\begin{frame}[fragile]
  \Frametitle{Listing of {\tt train1.c} (36)}

  \begin{minipage}{0.95\textwidth}
\begin{Verbatim}[frame=single,numbers=left,fontsize=\tiny,firstnumber=last,xleftmargin=5mm]
            } else if (iedge == 4) {
                lenx_dot = 0;   leny_dot = -LENY_DOT(iudp)/2;   lenz_dot = 0;
            } else {
                status = OCSM_EDGE_NOT_FOUND;
                goto cleanup;
            }
        } else if (entType == OCSM_FACE) {
            iface = entIndex;

            if (iface == 1) {
                lenx_dot = 0;   leny_dot = 0;   lenz_dot = 0;
            } else {
                status = OCSM_FACE_NOT_FOUND;
                goto cleanup;
            }
        } else {
            status = OCSM_ILLEGAL_VALUE;
            goto cleanup;
        }

        /* return (constant) velocities, accounting for the movement
           of the CENTER if it set */
        for (i = 0; i < npnt; i++) {
            vels[3*i  ] = lenx_dot + xcent_dot;
            vels[3*i+1] = leny_dot + ycent_dot;
            vels[3*i+2] = lenz_dot + zcent_dot;
        }

        /* compute the sensitivities of the area */
        area_dot = LENY_DOT(iudp) * LENZ(iudp) + LENZ_DOT(iudp) * LENY(iudp);
\end{Verbatim}
  \end{minipage}
\end{frame}

\begin{frame}[fragile]
  \Frametitle{Listing of {\tt train1.c} (37)}

  \begin{minipage}{0.95\textwidth}
\begin{Verbatim}[frame=single,numbers=left,fontsize=\tiny,firstnumber=last,xleftmargin=5mm]
    /* SheetBody in ZX plane (since the velocity on each Node and Edge is
                              a constant, we need to just compute one value) */
    } else if (LENY(iudp) <= 0) {
        if        (entType == OCSM_NODE) {
            inode = entIndex;

            if        (inode == 1) {
                lenx_dot = -LENX_DOT(iudp)/2;   leny_dot = 0;   lenz_dot = -LENZ_DOT(iudp)/2;
            } else if (inode == 2) {
                lenx_dot = -LENX_DOT(iudp)/2;   leny_dot = 0;   lenz_dot = +LENZ_DOT(iudp)/2;
            } else if (inode == 3) {
                lenx_dot = +LENX_DOT(iudp)/2;   leny_dot = 0;   lenz_dot = +LENZ_DOT(iudp)/2;
            } else if (inode == 4) {
                lenx_dot = +LENX_DOT(iudp)/2;   leny_dot = 0;   lenz_dot = -LENZ_DOT(iudp)/2;
            } else {
                status = OCSM_NODE_NOT_FOUND;
                goto cleanup;
            }
        } else if (entType == OCSM_EDGE) {
            iedge = entIndex;

            if        (iedge == 1) {
                lenx_dot = -LENX_DOT(iudp)/2;   leny_dot = 0;   lenz_dot = 0;
            } else if (iedge == 2) {
                lenx_dot = 0;   leny_dot = 0;   lenz_dot = +LENZ_DOT(iudp)/2;
            } else if (iedge == 3) {
                lenx_dot = +LENX_DOT(iudp)/2;   leny_dot = 0;   lenz_dot = 0;
\end{Verbatim}
  \end{minipage}
\end{frame}

\begin{frame}[fragile]
  \Frametitle{Listing of {\tt train1.c} (38)}

  \begin{minipage}{0.95\textwidth}
\begin{Verbatim}[frame=single,numbers=left,fontsize=\tiny,firstnumber=last,xleftmargin=5mm]
            } else if (iedge == 4) {
                lenx_dot = 0;   leny_dot = 0;   lenz_dot = -LENZ_DOT(iudp)/2;
            } else {
                status = OCSM_EDGE_NOT_FOUND;
                goto cleanup;
            }
        } else if (entType == OCSM_FACE) {
            iface = entIndex;

            if (iface == 1) {
                lenx_dot = 0;   leny_dot = 0;   lenz_dot = 0;
            } else {
                status = OCSM_FACE_NOT_FOUND;
                goto cleanup;
            }

        } else {
            status = OCSM_ILLEGAL_VALUE;
            goto cleanup;
        }

        /* return (constant) velocities, accounting for the movement
           of the CENTER if it set */
        for (i = 0; i < npnt; i++) {
            vels[3*i  ] = lenx_dot + xcent_dot;
            vels[3*i+1] = leny_dot + ycent_dot;
            vels[3*i+2] = lenz_dot + zcent_dot;
        }

        /* compute the sensitivities of the area */
        area_dot = LENZ_DOT(iudp) * LENX(iudp) + LENX_DOT(iudp) * LENZ(iudp);
\end{Verbatim}
  \end{minipage}
\end{frame}

\begin{frame}[fragile]
  \Frametitle{Listing of {\tt train1.c} (39)}

  \begin{minipage}{0.95\textwidth}
\begin{Verbatim}[frame=single,numbers=left,fontsize=\tiny,firstnumber=last,xleftmargin=5mm]
    /* SolidBody (since the velocity on each Node, Edge, and Face is a
                  constant, we need just to compute one vaue) */
    } else {
        if        (entType == OCSM_NODE) {
            inode = entIndex;

            if        (inode == 1) {
                lenx_dot = -LENX_DOT(iudp)/2;   leny_dot = -LENY_DOT(iudp)/2;   lenz_dot = +LENZ_DOT(iudp)/2;
            } else if (inode == 2) {
                lenx_dot = -LENX_DOT(iudp)/2;   leny_dot = -LENY_DOT(iudp)/2;   lenz_dot = -LENZ_DOT(iudp)/2;
            } else if (inode == 3) {
                lenx_dot = -LENX_DOT(iudp)/2;   leny_dot = +LENY_DOT(iudp)/2;   lenz_dot = +LENZ_DOT(iudp)/2;
            } else if (inode == 4) {
                lenx_dot = -LENX_DOT(iudp)/2;   leny_dot = +LENY_DOT(iudp)/2;   lenz_dot = -LENZ_DOT(iudp)/2;
            } else if (inode == 5) {
                lenx_dot = +LENX_DOT(iudp)/2;   leny_dot = -LENY_DOT(iudp)/2;   lenz_dot = +LENZ_DOT(iudp)/2;
            } else if (inode == 6) {
                lenx_dot = +LENX_DOT(iudp)/2;   leny_dot = -LENY_DOT(iudp)/2;   lenz_dot = -LENZ_DOT(iudp)/2;
            } else if (inode == 7) {
                lenx_dot = +LENX_DOT(iudp)/2;   leny_dot = +LENY_DOT(iudp)/2;   lenz_dot = +LENZ_DOT(iudp)/2;
            } else if (inode == 8) {
                lenx_dot = +LENX_DOT(iudp)/2;   leny_dot = +LENY_DOT(iudp)/2;   lenz_dot = -LENZ_DOT(iudp)/2;
\end{Verbatim}
  \end{minipage}
\end{frame}

\begin{frame}[fragile]
  \Frametitle{Listing of {\tt train1.c} (40)}

  \begin{minipage}{0.95\textwidth}
\begin{Verbatim}[frame=single,numbers=left,fontsize=\tiny,firstnumber=last,xleftmargin=5mm]
            } else {
                status = OCSM_NODE_NOT_FOUND;
                goto cleanup;
            }
        } else if (entType == OCSM_EDGE) {
            iedge = entIndex;

            if        (iedge == 1) {
                lenx_dot = -LENX_DOT(iudp)/2;   leny_dot = -LENY_DOT(iudp)/2;   lenz_dot =  0;
            } else if (iedge == 2) {
                lenx_dot = -LENX_DOT(iudp)/2;   leny_dot =  0;   lenz_dot = +LENZ_DOT(iudp)/2;
            } else if (iedge == 3) {
                lenx_dot = -LENX_DOT(iudp)/2;   leny_dot = +LENY_DOT(iudp)/2;   lenz_dot =  0;
            } else if (iedge == 4) {
                lenx_dot = -LENX_DOT(iudp)/2;   leny_dot =  0;   lenz_dot = -LENZ_DOT(iudp)/2;
            } else if (iedge == 5) {
                lenx_dot = +LENX_DOT(iudp)/2;   leny_dot = -LENY_DOT(iudp)/2;   lenz_dot =  0;
            } else if (iedge == 6) {
                lenx_dot = +LENX_DOT(iudp)/2;   leny_dot =  0;   lenz_dot = +LENZ_DOT(iudp)/2;
            } else if (iedge == 7) {
                lenx_dot = +LENX_DOT(iudp)/2;   leny_dot = +LENY_DOT(iudp)/2;   lenz_dot =  0;
            } else if (iedge == 8) {
                lenx_dot = +LENX_DOT(iudp)/2;   leny_dot =  0;   lenz_dot = -LENZ_DOT(iudp)/2;
            } else if (iedge == 9) {
                lenx_dot =  0;   leny_dot = -LENY_DOT(iudp)/2;   lenz_dot = -LENZ_DOT(iudp)/2;
            } else if (iedge == 10) {
                lenx_dot =  0;   leny_dot = -LENY_DOT(iudp)/2;   lenz_dot = +LENZ_DOT(iudp)/2;
            } else if (iedge == 11) {
                lenx_dot =  0;   leny_dot = +LENY_DOT(iudp)/2;   lenz_dot = -LENZ_DOT(iudp)/2;
\end{Verbatim}
  \end{minipage}
\end{frame}

\begin{frame}[fragile]
  \Frametitle{Listing of {\tt train1.c} (41)}

  \begin{minipage}{0.95\textwidth}
\begin{Verbatim}[frame=single,numbers=left,fontsize=\tiny,firstnumber=last,xleftmargin=5mm]
            } else if (iedge == 12) {
                lenx_dot =  0;   leny_dot = +LENY_DOT(iudp)/2;   lenz_dot = +LENZ_DOT(iudp)/2;
            } else {
                status = OCSM_EDGE_NOT_FOUND;
                goto cleanup;
            }
        } else if (entType == OCSM_FACE) {
            iface = entIndex;

            if        (iface == 1) {
                lenx_dot = -LENX_DOT(iudp)/2;   leny_dot = 0;   lenz_dot = 0;
            } else if (iface == 2) {
                lenx_dot = +LENX_DOT(iudp)/2;   leny_dot = 0;   lenz_dot = 0;
            } else if (iface == 3) {
                lenx_dot = 0;   leny_dot = -LENY_DOT(iudp)/2;   lenz_dot = 0;
            } else if (iface == 4) {
                lenx_dot = 0;   leny_dot = +LENY_DOT(iudp)/2;   lenz_dot = 0;
            } else if (iface == 5) {
                lenx_dot = 0;   leny_dot = 0;   lenz_dot = -LENZ_DOT(iudp)/2;
            } else if (iface == 6) {
                lenx_dot = 0;   leny_dot = 0;   lenz_dot = +LENZ_DOT(iudp)/2;
            } else {
                status = OCSM_FACE_NOT_FOUND;
                goto cleanup;
            }

        } else {
            status = OCSM_ILLEGAL_VALUE;
            goto cleanup;
        }
\end{Verbatim}
  \end{minipage}
\end{frame}

\begin{frame}[fragile]
  \Frametitle{Listing of {\tt train1.c} (42)}

  \begin{minipage}{0.95\textwidth}
\begin{Verbatim}[frame=single,numbers=left,fontsize=\tiny,firstnumber=last,xleftmargin=5mm]
        /* return (constant) velocities, accounting for the movement
           of the CENTER if it set */
        for (i = 0; i < npnt; i++) {
            vels[3*i  ] = lenx_dot + xcent_dot;
            vels[3*i+1] = leny_dot + ycent_dot;
            vels[3*i+2] = lenz_dot + zcent_dot;
        }

        /* compute the sensitivities of the area and volume */
        area_dot = 2 * (LENX_DOT(iudp) * (LENY(iudp) + LENZ(iudp))
                     +  LENY_DOT(iudp) * (LENZ(iudp) + LENX(iudp))
                     +  LENZ_DOT(iudp) * (LENX(iudp) + LENY(iudp)));
        volume_dot = LENX_DOT(iudp) * LENY(iudp) * LENZ(iudp)
                   + LENY_DOT(iudp) * LENZ(iudp) * LENX(iudp)
                   + LENZ_DOT(iudp) * LENX(iudp) * LENY(iudp);
    }

    AREA_DOT(  iudp) = area_dot;
    VOLUME_DOT(iudp) = volume_dot;

    status = EGADS_SUCCESS;

cleanup:
#ifdef DEBUG
    printf("udpSensitivity -> vels=%f %f %f\n", vels[0], vels[1], vels[2]);
#endif
    return status;
}
\end{Verbatim}
  \end{minipage}
\end{frame}

\begin{frame}[fragile]
  \Frametitle{Listing of {\tt train1.c} (43)}

  \begin{minipage}{0.95\textwidth}
\begin{Verbatim}[frame=single,numbers=left,fontsize=\tiny,firstnumber=last,xleftmargin=5mm]
/*
 ************************************************************************
 *                                                                      *
 *   freePrivateData - free private data (just an example)              *
 *                                                                      *
 ************************************************************************
 */

static int
freePrivateData(void  *data)            /* (in)  pointer to private data */
{
    int    status = EGADS_SUCCESS;

#ifdef DEBUG
    printf("freePrivateData(%s)\n", (char*)(data));
#endif

    /* note: this function would not be necessary if we are only calling
             EG_free (and then FREEUDPDATA would not be defined above).
             It is simply included here to show how one would write
             such a function if the allocation was more complicated
             than a simple EG_alloc() */

    EG_free(data);

//cleanup:
    return status;
}
\end{Verbatim}
  \end{minipage}
\end{frame}

\begin{frame}
  \Frametitle{Explanation of {\tt train1.c} (43)}

  \begin{itemize}
  \item Lines 1009--1028: this routine (and the one that follows) are
    only needed in the case where the UDP needs to store data.  See
    the comments on lines 1018--1022 for more details.
  \end{itemize}
\end{frame}

\begin{frame}[fragile]
  \Frametitle{Listing of {\tt train1.c} (44)}

  \begin{minipage}{0.95\textwidth}
\begin{Verbatim}[frame=single,numbers=left,fontsize=\tiny,firstnumber=last,xleftmargin=5mm]
/*
 ************************************************************************
 *                                                                      *
 *   copyPrivateData - copy private data (just an example)              *
 *                                                                      *
 ************************************************************************
 */

static int
copyPrivateData(
      /*@null@*/void  *src,             /* (in)  pointer to source private data */
                void  **tgt)            /* (in)  pointer to target private data */
{
    int    status = EGADS_SUCCESS;

    *tgt = NULL;

    if (src == NULL) goto cleanup;

    /* note: this function would not be necessary if we are only calling
             EG_free (and then COPYUDPDATA would not be defined above).
             It is simply included here to show how one would write
             such a function if the allocation was more complicated
             than a simple EG_alloc() */

    *tgt = (void *) malloc(sizeof(char)*(strlen((char*)src)+1));
    if (*tgt == NULL) {
        status = EGADS_MALLOC;
        goto cleanup;
    }
\end{Verbatim}
  \end{minipage}
\end{frame}

\begin{frame}[fragile]
  \Frametitle{Listing of {\tt train1.c} (45)}

  \begin{minipage}{0.95\textwidth}
\begin{Verbatim}[frame=single,numbers=left,fontsize=\tiny,firstnumber=last,xleftmargin=5mm]
#ifdef DEBUG
    printf("copyPrivateData(src=%llx, tgt=%llx)\n", (long long)(src), (long long)(*tgt));
#endif

    strcpy(*tgt, src);

cleanup:
    return status;
}
\end{Verbatim}
  \end{minipage}
\end{frame}


\begin{frame}
  \Frametitle{Exercise2 (1)}

  \begin{itemize}
  \item Make a new UDP ({\tt exercise2}) in the directory (folder) {\tt
    udpExercise2}
    \begin{itemize}
    \item the purpose is: create a pyramid whose base is on the $XY$
      plane and which is centered on the $Z$-axis.  The apex is also on
      the $Z$-axis.
    \item the input parameters are:
      \begin{itemize}
      \item {\tt length} - the length of the base in the $X$-direction
      \item {\tt width} - the width of the base in the $Y$-direction
      \item {\tt height} - the $Z$-coordinate of the apex
      \end{itemize}
    \end{itemize}
  \item Make sure that your UDP does appropriate error checking
  \end{itemize}
\end{frame}

\begin{frame}
  \Frametitle{Exercise2 (2)}

  \begin{itemize}
  \item First write the UDP so that it uses finite-difference
    sensitivities
    \begin{itemize}
    \item draw a picture, numbering the Nodes and Edges
    \item make the Nodes ({\tt EG\_makeTopology})
    \item foreach Edge
      \begin{itemize}
      \item make a curve ({\tt EG\_makeGeometry})
      \item find $t$ at endpoints ({\tt EG\_invEvaluate})
      \item make the Edge ({\tt EG\_makeTopology})
      \end{itemize}
    \item foreach Face
      \begin{itemize}
      \item make a Loop ({\tt EG\_makeLoop})
      \item make the Face ({\tt EG\_makeFace})
      \end{itemize}
    \item make a Shell ({\tt EG\_makeTopology})
    \item make the SolidBody ({\tt EG\_makeTopology})
    \end{itemize}
  \end{itemize}
\end{frame}

\begin{frame}
  \Frametitle{Exercise2 (3)}

  \begin{itemize}
  \item Notes:
    \begin{itemize}
    \item If you use {\tt EG\_makeToplology} to make the Loop instead
      of {\tt EG\_makeLoop}, you need to properly order the Edges and
      assign the correct sense to each Edge
    \item If your Face is not planar, instead of {\tt EG\_makeFace}
      you need to first create a Surface ({\tt EG\_makeGeometry}),
      create the PCurves ({\tt EG\_otherCurve}), and then the Face
      ({\tt EG\_makeTopology})
  \item To aid in debugging, you can use {\tt ocsmPrintEgo(X)} where
    {\tt X} is an {\tt ego} of any type
    \end{itemize}
  \end{itemize}
\end{frame}

\begin{frame}
  \Frametitle{Exercise2 (4)}

  \begin{itemize}
  \item Modify the UDP to compute analytic sensitivities
    \begin{itemize}
    \item For this case
      \begin{eqnarray*}
        x & = & {\tt LENGTH} * f(u,v,w) \\
        \dot{x} & = & {\tt LENGTH\_DOT} * f(u,v,w)
      \end{eqnarray*}
      where $f(u,v,w)$ tells a specific location in the pyramid
    \item So
      \begin{displaymath}
        \dot{x} = x*\frac{\tt LENGTH\_DOT}{\tt LENGTH}
      \end{displaymath}
    \item The same idea applies in the other coordinate directions
    \end{itemize}
  \end{itemize}
\end{frame}

\begin{frame}[fragile]
  \Frametitle{Hints: Pyramid Equations}

\begin{block}{Area \& Volume}
%\footnotesize
$lh = \sqrt{(l^2/4 +h^2)}$\\[0.03in]
$wh = \sqrt{(w^2/4 +h^2)}$\\[0.06in]
$area = l*w + l*wh + w*lh$\\[0.03in]
$volume = l*w*h / 3$
\end{block}

\begin{block}{Dots}
%\footnotesize
$\dot{lh} = (\dot{l}*l/4 + \dot{h}*h)/lh$\\[0.03in]
$\dot{wh}= (\dot{w}*w/4 + \dot{h}*h)/wh$\\[0.06in]
$\dot{area} = \dot{l}*w + \dot{w}*l + \dot{w}*lh + w*\dot{lh} + \dot{l}*wh + l*\dot{wh}$\\[0.03in]
$\dot{volume} = (\dot{l}*w*h + \dot{w}*h*l + \dot{h}*l*w) / 3$  
\end{block}

\end{frame}

\end{document}
