\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 UDF]{
\includegraphics[width=1.0in]{esp_logo.png}\\
Engineering Sketch Pad\\
UDP/UDF Programming -- Full-featured UDF\\[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
    udpTrain2} from {\tt udpTemplate}
  \item Modify {\tt train2.c} to:
    \begin{itemize}
      \item get a Body from the stack (that is, write a UDF instead of
        a UDP)
    \item get inputs from a file
    \item manipulate attributes
    \end{itemize}
  \item Exercise3
  \end{itemize}
\end{frame}

\begin{frame}[fragile]
  \Frametitle{Listing of {\tt train2.hlp}}

  \begin{minipage}{0.95\textwidth}
\begin{Verbatim}[frame=single,numbers=left,fontsize=\tiny,firstnumber=auto,xleftmargin=5mm]
UDPRIM train2 Body
       purpose:
           serve as a template for creation of new UDFs
           as an example, modifies attributes on the input Body
       input Bodys:
           one SolidBody, SheetBody, or WireBody
       input arguments (specified as name/value pairs):
           filename    name of file with directives
       output arguments:
           nskip       number of skipped directives
       usage notes:
           the directives are in the form:
               FACE attrName            (deletes    attrName on Faces)
               FACE attrName attrValue  (overwrites attrName on Faces)
               EDGE attrName            (deletes    attrName on Edges)
               EDGE attrName attrValue  (overwrites attrName on Edges)
               NODE attrName            (deletes    attrName on Nodes)
               NODE attrName attrValue  (overwrites attrName on Nodes)

               # signifies a comment (can be used anywhere)
               @ inserts Face, Edge, or Node number into attrValue
               the directive can either be in UPPERACE or lowercase
               error messages are printed, but otherwise ignored
               
           analytic sensitivities are not supported
       contributed by:
           John Dannenhoffer john@geocentrictech.com
\end{Verbatim}
  \end{minipage}
\end{frame}

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

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

# make a box
BOX       0  0  0  4  3  2

# add attributes 
UDPRIM    train2    filename <<
#  this   is a comment
   Face   myFace   @            # error - ignored
   face   myFace   @            # real attribute

   EDGE   myEdge   edge_@       # string attribute
   edge   myEdge2  deleteMe     # string attribute

   node   myNode   @            # real attribute
   node   myNode   @_node       # overwrites with string
   NODE                         # error - no attrName

   edge   myEdge2               # deletes attribute
>>

# verify that there were 2 skipped directives (ie, errors)
ASSERT    @@nskip  2
\end{Verbatim}
  \end{minipage}
\end{frame}

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

  \begin{minipage}{0.95\textwidth}
\begin{Verbatim}[frame=single,numbers=left,fontsize=\tiny,firstnumber=last,xleftmargin=5mm]
# verify that attributes have been added to the box
PATBEG    iface  @nface
   SELECT    FACE  $myFace   iface
   ASSERT    @sellist[1]     iface
PATEND

PATBEG    iedge  @nedge
   SELECT    EDGE  $myEdge   $edge_+iedge
   ASSERT    @sellist[1]     iedge
PATEND

SELECT    EDGE  $myEdge2  $deleteMe
ASSERT    0  1                  # should not execute
CATBEG    $edge_not_found
CATEND

PATBEG    inode  @nnode
   SELECT    NODE  $myNode   val2str(inode,0)+$_node
   ASSERT    @sellist[1]     inode
PATEND

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

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

  \begin{itemize}
  \item Attributes can be associated with any {\tt EGADS} object ({\tt
    ego})
    \begin{itemize}
    \item Curve, PCurve, Surface
    \item Node, Edge, Loop, Face, Shell, Body
    \end{itemize}
  \item Attributes are specified as a name/value pair
  \item Attribute names are arbitrary strings of letters, digits, or
    underscores
  \item Attribute values can be:
    \begin{itemize}
    \item {\tt ATTRINT} -- one or more integers
    \item {\tt ATTRREAL} -- one or more doubles
    \item {\tt ATTRSTRING} -- a character string
    \item {\tt ATTRCSYS} -- doubles that are transformed with {\tt
      EG\_copyObject}
    \end{itemize}
  \end{itemize}
\end{frame}
         
\begin{frame}
  \Frametitle{Attributes (2)}

  \begin{itemize}
  \item Operations that apply to attributes include:
    \begin{itemize}
    \item {\tt EG\_attributeNum} -- return the number of attributes
      associated with an {\tt ego}
    \item {\tt EG\_attributeAdd} -- add an attribute and its value to
      an {\tt ego}
    \item {\tt EG\_attributeDel} -- delete the named attribute from an
      {\tt ego}
    \item {\tt EG\_attributeDup} -- duplicate the attributes from one
      {\tt ego} to another {\tt ego}
    \item {\tt EG\_attributeGet} -- get the attribute name and value
      given its index from an {\tt ego}
    \item {\tt EG\_attributeRet} -- return the attribute value given
      its name from an {\tt ego}
    \end{itemize}
  \end{itemize}
\end{frame}

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

  \begin{minipage}{0.95\textwidth}
\begin{Verbatim}[frame=single,numbers=left,fontsize=\tiny,firstnumber=auto,xleftmargin=5mm]
/*
 ************************************************************************
 *                                                                      *
 * udfTrain2 -- training UDF                                            *
 *                                                                      *
 *             this modified attributes on a Body                       *
 *             sensitivities are not computed                           *
 *                                                                      *
 *             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 train2.c} (1)}

  \begin{itemize}
  \item General notes:
    \begin{itemize}
    \item the descriptions given focus on the difference between
      previous sessions and {\tt train2.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--7: identifying comment (which is different from {\tt
    template.c})
  \end{itemize}
\end{frame}

\begin{frame}[fragile]
  \Frametitle{Listing of {\tt train2.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 1

/* the number of arguments (specified below) */
#define NUMUDPARGS 2

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

/* shorthand macros for accessing argument values and velocities */
#define FILENAME(IUDP)  ((char   *) (udps[IUDP].arg[0].val))
#define NSKIP(   IUDP)  ((int    *) (udps[IUDP].arg[1].val))[0]
\end{Verbatim}
  \end{minipage}
\end{frame}

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

  \begin{itemize}
  \item Line 44: one Body is removed from the stack, put into an {\tt
    EGADS} MODEL, and passed to this UDF
  \end{itemize}
\end{frame}

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

  \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] = {"filename", "nskip",  };
static int    argTypes[NUMUDPARGS] = {ATTRFILE,   -ATTRINT, };
static int    argIdefs[NUMUDPARGS] = {0,          0,        };
static double argDdefs[NUMUDPARGS] = {1.,         0.,       };
\end{Verbatim}
  \end{minipage}
\end{frame}

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

  \begin{itemize}
  \item Line 75: the {\tt filename} argument is of type {\tt
    ATTRFILE}.  Both {\tt ATTRFILE} and {\tt ATTRSTRING} give the
    UDP/UDF character strings, but {\tt ATTRFILE} handles the
    filename consistently with {\tt ESP}
  \end{itemize}
\end{frame}

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

  \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"

static int addAttribute(ego eobj, char attrName[], char attrValue[], int index);
#ifdef DEBUG
static int printAttributes(ego eobj);
#endif
static int convertAtSign(char instring[], int number, char outstring[]);

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

int
udpExecute(ego  emodel,                 /* (in)  Model containing Body */
           ego  *ebody,                 /* (out) Body (or model) pointer */
           int  *nMesh,                 /* (out) number of associated meshes */
           char *string[])              /* (out) error message */
\end{Verbatim}
  \end{minipage}
\end{frame}

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

  \begin{itemize}
  \item Lines 82--88: declare the ``helper'' routines which are
    defined at the end of the file
  \item Line 98: because this is a UDF (nd not a UDP), this first
    argument now has the MODEL that contains the input Bodys (from the
    stack).  This is different from a UDP, where the first argument is
    the {\tt context}.
  \end{itemize}
\end{frame}

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

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

    char    *message=NULL;
    udp_T   *udps = *Udps;

    int     oclass, mtype, nchild, *senses, i, nskip;
    int     eof, inext, nread;
    int     nnode, inode, nedge, iedge, nface, iface;
    double  data[18];
    char    templine[256], command[256], attrName[256], attrValue[256];
    ego     *ebodys, context, eref, modl;
    ego     *enodes=NULL, *eedges=NULL, *efaces=NULL;
    FILE    *fp=NULL;

    ROUTINE(udpExecute);

    /* --------------------------------------------------------------- */

#ifdef DEBUG
    /* debug printing of the input arguments */
    printf("udpExecute(emodel=%llx)\n", (long long)emodel);
    printf("filename(0) = %s\n", FILENAME(0));
    printf("nskip(   0) = %d\n", NSKIP(   0));
#endif
\end{Verbatim}
  \end{minipage}
\end{frame}

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

  \begin{minipage}{0.95\textwidth}
\begin{Verbatim}[frame=single,numbers=left,fontsize=\tiny,firstnumber=last,xleftmargin=5mm]
    /* 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';

    /* number of directives containing an error */
    nskip = 0;

    /* check that Model was input that contains one Body */
    status = EG_getTopology(emodel, &eref, &oclass, &mtype,
                            data, &nchild, &ebodys, &senses);
    CHECK_STATUS(EG_getTopology);

    if (oclass != MODEL) {
        snprintf(message, 100, "expecting a Model, but found oclass=%d", oclass);
        status = EGADS_NOTMODEL;
        goto cleanup;
    } else if (nchild != 1) {
        snprintf(message, 100, "expecting Model to contain one Body (not %d)", nchild);
        status = EGADS_NOTBODY;
        goto cleanup;
    }
\end{Verbatim}
  \end{minipage}
\end{frame}

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

  \begin{itemize}
  \item Lines 140--142: extract from {\tt emodel} its class (which
    should be {\tt MODEL}) and the Bodys that it contains (in {\tt
      ebodys})
  \item Lines 144--147: make sure that {\tt emodel} contains a {\tt
    MODEL}
  \item Lines 148--151: make sure that {\tt emodel} only contains one
    Body
  \end{itemize}
\end{frame}

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

  \begin{minipage}{0.95\textwidth}
\begin{Verbatim}[frame=single,numbers=left,fontsize=\tiny,firstnumber=last,xleftmargin=5mm]
    /* check arguments */
    if (STRLEN(FILENAME(0)) <= 0) {
        snprintf(message, 100, "\"filename\" must be specified");
        status = OCSM_ILLEGAL_VALUE;
        goto cleanup;
    }

    /* cache copy of arguments for future use */
    status = cacheUdp(NULL);
    CHECK_STATUS(cacheUdp);

#ifdef DEBUG
    /* debug printing of cached input arguments */
    printf("filename(%d) = %s\n", numUdp, FILENAME(numUdp));
    printf("nskip(   %d) = %d\n", numUdp, NSKIP(   numUdp));
#endif

    /* make a copy of the Body (so that it does not get removed
     when OpenCSM deletes emodel) */
    status = EG_copyObject(ebodys[0], NULL, ebody);
    CHECK_STATUS(EG_copyObject);

    SPLINT_CHECK_FOR_NULL(*ebody);

    /* get pointer to model */
    status = EG_getContext(emodel, &context);
    CHECK_STATUS(EG_getContext);

    status = EG_getUserPointer(context, (void**)(&(modl)));
    CHECK_STATUS(EG_getUserPointer);
\end{Verbatim}
  \end{minipage}
\end{frame}

\begin{frame}
  \Frametitle{Explanation of {\tt train2.c} (7)}

  \begin{itemize}
  \item Lines 172--173: make a copy of the input Body ({\tt
    ebodys[0]}) to be the output Body ({\tt ebody}).  This is needed
    because {\tt ESP} deletes {\tt emodel} (and its Bodys) when
    it returns from {\tt udpExecute}.  The second argument to {\tt
      EG\_copyObject} is a transformation, which is not needed here.
  \item Lines 178--179: because a UDF gets a {\tt MODEL} instead of
    the {\tt context}, we need to get the {\tt context} by calling
    {\tt EG\_getContext} (which can be called on any {\tt ego})
  \item Lines 181--182: get the {\tt OpenCSM} Modl pointer in case we
    need to access any information from {\tt ESP} (such as Design
    Parameters).  This is actually not needed for this UDF, but is
    here in case we change things in the future.
  \end{itemize}
\end{frame}

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

  \begin{minipage}{0.95\textwidth}
\begin{Verbatim}[frame=single,numbers=left,fontsize=\tiny,firstnumber=last,xleftmargin=5mm]
    /* get arrays of the Nodes, Edges, and Faces in the Body */
    status = EG_getBodyTopos(*ebody, NULL, NODE, &nnode, &enodes);
    CHECK_STATUS(EG_getBodyTopos);

    status = EG_getBodyTopos(*ebody, NULL, EDGE, &nedge, &eedges);
    CHECK_STATUS(EG_getBodyTopos);

    status = EG_getBodyTopos(*ebody, NULL, FACE, &nface, &efaces);
    CHECK_STATUS(EG_getBodyTopos);

    /* debug print of attributes before processing */
#ifdef DEBUG
    printf("Attributes before processing\n");

    for (inode = 0; inode < nnode; inode++) {
        printf("Node %3d\n", inode+1);
        printAttributes(enodes[inode]);
    }

    for (iedge = 0; iedge < nedge; iedge++) {
        printf("Edge %3d\n", iedge+1);
        printAttributes(eedges[iedge]);
    }

    for (iface = 0; iface < nface; iface++) {
        printf("Face %3d\n", iface+1);
        printAttributes(efaces[iface]);
    }
#endif
\end{Verbatim}
  \end{minipage}
\end{frame}

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

  \begin{itemize}
  \item Lines 184--185: get the number of Nodes and a list of the
    Nodes from {\tt ebody}.  Examining the documentation for {\tt
      EG\_getBodyTopos} indicates that the last argument is
    ``freeable'', which means that we need to make sure we call {\tt
      EG\_free} (which is done in  the cleanup section on line 353).
    Also note that this list is bias-0 and we typically number the
    Nodes bias-1.
  \item Lines 197--200: if {\tt DEBUG} is defined, print the
    attributes for all the Nodes.  Note in line 198 the addition of 1
    to {\tt inode} to convert from bias-0 to bias-1.
  \end{itemize}
\end{frame}

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

  \begin{minipage}{0.95\textwidth}
\begin{Verbatim}[frame=single,numbers=left,fontsize=\tiny,firstnumber=last,xleftmargin=5mm]
    /* if FILENAME contains a real filename, open it now and remember
       if we are at the end of file */
    if (strncmp(FILENAME(0), "<<\n", 3) != 0) {
        fp = fopen(FILENAME(0), "rb");
        if (fp == NULL) {
            snprintf(message, 100, "could not open file \"%s\"", FILENAME(0));
            status = EGADS_NOTFOUND;
            goto cleanup;
        }

        ieof = feof(fp);

    /* otherwise we have an inline file, so set up the next character to read */
    } else {
        inext = 3;
        ieof  = 0;
    }
\end{Verbatim}
  \end{minipage}
\end{frame}

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

  \begin{itemize}
  \item Lines 214--222: if the first three characters of {\tt
    FILENAME(0)} are not ``\verb+<<\+'' then this is a real filename that
    should be opened
  \item Lines 225--228: if the first characters of {\tt FILENAME(0)}
    were ``\verb+<<\n+'', then this is actually an inline file, where each
    lines of the inline file follow.  So, we need to start reading at
    the fourth character.  Note that {\tt fp} was initialized to {\tt
      NULL} above so it does not need to be set here.
  \end{itemize}
\end{frame}

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

  \begin{minipage}{0.95\textwidth}
\begin{Verbatim}[frame=single,numbers=left,fontsize=\tiny,firstnumber=last,xleftmargin=5mm]
    /* read until end of file */
    while (ieof == 0) {

        /* read the next line */
        if (fp != NULL) {
            (void) fgets(templine, 255, fp);
            if (feof(fp) > 0) break;

            /* overwite the \n and \r at the end */
            if (STRLEN(templine) > 0 && templine[STRLEN(templine)-1] == '\n') {
                templine[STRLEN(templine)-1] = '\0';
            }
            if (STRLEN(templine) > 0 && templine[STRLEN(templine)-1] == '\r') {
                templine[STRLEN(templine)-1] = '\0';
            }
        } else {
            i = 0;
            for (; inext < STRLEN(FILENAME(0)); inext++) {
                if (FILENAME(0)[inext] == '\n' || FILENAME(0)[inext] == '\r') break;

                templine[i++] = FILENAME(0)[inext];
            }
            templine[i] = '\0';
            inext++;

            if (inext >= STRLEN(FILENAME(0))) {
                ieof = 1;
            }
        }
\end{Verbatim}
  \end{minipage}
\end{frame}

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

  \begin{itemize}
  \item Line 230: read until {\tt ioef} is not 0
  \item Lines 233--243: a real file is being read, so get the next
    line into {\tt templine} and record weather or not we have reached
    the end of file.  Also remove the \verb+\n+ or \verb+\r+ from the
    line (if they exist)
  \item Lines 244--256: an inline file is being read, so copy from
    {\tt FILENAME(0)} into {\tt templine} until we get an end of line.
    Also if we have gotten to the end of the inline file, set {\tt
      ieof} to 1 to get out of the loop in line 230.
  \end{itemize}
\end{frame}

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

  \begin{minipage}{0.95\textwidth}
\begin{Verbatim}[frame=single,numbers=left,fontsize=\tiny,firstnumber=last,xleftmargin=5mm]
        printf("processing: %s\n", templine);

        /* remove inline comments */
        for (i = 0; i < strlen(templine); i++) {
            if (templine[i] == '#') {
                templine[i] =  '\0';
                break;
            }
        }

        /* read the fields out of templine */
        attrValue[0] = '\0';

        nread = sscanf(templine, "%s %s %s", command, attrName, attrValue);

        /* whole-line comment or blank line */
        if (nread < 0) {

        /* line with only command (error) */
        } else if (nread < 2) {
            printf("   error encountered when reading: %s\n", templine);
            nskip++;
\end{Verbatim}
  \end{minipage}
\end{frame}

\begin{frame}
  \Frametitle{Explanation of {\tt train2.c} (11)}

  \begin{itemize}
  \item Lines 261--266: remove comments form {\tt templine}
  \item Lines 269--271: read out of {\tt templine} up to 3
    space-delimited fields.  Note that the third field in initialized
    to a blank string in case only 2 fields were read.
  \item Lines 274--279: take case of blank lines and lines that do not
    contain at least 2 fields
  \end{itemize}
\end{frame}

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

  \begin{minipage}{0.95\textwidth}
\begin{Verbatim}[frame=single,numbers=left,fontsize=\tiny,firstnumber=last,xleftmargin=5mm]
        /* attributes on all Nodes */
        } else if (strcmp(command, "node") == 0 || strcmp(command, "NODE") == 0) {
            for (inode = 0; inode < nnode; inode++) {
                status = addAttribute(enodes[inode], attrName, attrValue, inode+1);
                CHECK_STATUS(addAttribute);
            }

        /* attributes on all Edges */
        } else if (strcmp(command, "edge") == 0 || strcmp(command, "EDGE") == 0) {
            for (iedge = 0; iedge < nedge; iedge++) {
                status = addAttribute(eedges[iedge], attrName, attrValue, iedge+1);
                CHECK_STATUS(addAttribute);
            }

        /* attributes on all Faces */
        } else if (strcmp(command, "face") == 0 || strcmp(command, "FACE") == 0) {
            for (iface = 0; iface < nface; iface++) {
                status = addAttribute(efaces[iface], attrName, attrValue, iface+1);
                CHECK_STATUS(addAttribute);
            }

        /* illegal command */
        } else {
            printf("   illegal command (%s) when reading: %s\n", command, templine);
            nskip++;
        }
    }
\end{Verbatim}
  \end{minipage}
\end{frame}

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

  \begin{itemize}
  \item Lines 281--285: process lines that start with eith {\tt node}
    or {\tt NODE} by calling {\tt addAttribute} (which is defined
    below) on the Node.  Note the switch from bias-0 (in {\tt enodes})
    to bias-1 by adding 1 to {\tt inode}
  \end{itemize}
\end{frame}

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

  \begin{minipage}{0.95\textwidth}
\begin{Verbatim}[frame=single,numbers=left,fontsize=\tiny,firstnumber=last,xleftmargin=5mm]
    /* debug print of attributes after processing */
#ifdef DEBUG
    printf("Attributes after processing\n");

    for (inode = 0; inode < nnode; inode++) {
        printf("Node %3d\n", inode+1);
        printAttributes(enodes[inode]);
    }

    for (iedge = 0; iedge < nedge; iedge++) {
        printf("Edge %3d\n", iedge+1);
        printAttributes(eedges[iedge]);
    }

    for (iface = 0; iface < nface; iface++) {
        printf("Face %3d\n", iface+1);
        printAttributes(efaces[iface]);
    }
#endif

    /* add a special Attribute to the Body to tell OpenCSM that there
       is no topological change and hence it should not adjust the
       Attributes on the Body in finishBody() */
    status = EG_attributeAdd(*ebody, "__noTopoChange__", ATTRSTRING,
                             0, NULL, NULL, "udfTrain2");
    CHECK_STATUS(EG_attributeAdd);
\end{Verbatim}
  \end{minipage}
\end{frame}

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

  \begin{itemize}
  \item Lines 330--332: since the topology of then input body ({\tt
    ebodys[0]}) and output body ({\tt ebody}) are the same, we can set
    a special attribute on the Body to tell {\tt ESP} to simply use
    the attributes already on ({\tt ebody}), which were put there
    during the {\tt EG\_copyObject} back on line 172.
  \end{itemize}
\end{frame}

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

  \begin{minipage}{0.95\textwidth}
\begin{Verbatim}[frame=single,numbers=left,fontsize=\tiny,firstnumber=last,xleftmargin=5mm]
    /* set the output value(s) */
    NSKIP(numUdp) = nskip;

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

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

    if (fp != NULL) fclose(fp);

    if (enodes != NULL) EG_free(enodes);
    if (eedges != NULL) EG_free(eedges);
    if (efaces != NULL) EG_free(efaces);

    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 train2.c} (15)}

  \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) */
               double uvs[],            /* (in)  parametric coordinates for evaluation */
               double vels[])           /* (out) velocities */
{
    int    status = EGADS_SUCCESS;

    int    iudp, judp;

    ROUTINE(udpSensitivity);

    /* --------------------------------------------------------------- */

#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]);
\end{Verbatim}
  \end{minipage}
\end{frame}

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

  \begin{itemize}
  \item Since we are not computing sensitivities, this is exactly the
    same routine as it was in {\tt udpTemplate}
  \end{itemize}
\end{frame}

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

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

    /* 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;
    }

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

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 train2.c} (17)}

  \begin{minipage}{0.95\textwidth}
\begin{Verbatim}[frame=single,numbers=left,fontsize=\tiny,firstnumber=last,xleftmargin=5mm]
/*
 ************************************************************************
 *                                                                      *
 *   addAttribute - add the specified attribute to the ego              *
 *                                                                      *
 ************************************************************************
 */

static int
addAttribute(ego    eobj,               /* (in)  ego to get attribute */
             char   attrName[],         /* (in)  attribute name */
             char   attrValue[],        /* (in)  attribute value (may contain @ */
             int    index)              /* (in)  index (such as bias-1 Node number) */
{
    int     status=EGADS_SUCCESS;       /* (out)  return status */

    int     attrType, attrLen;
    CINT    *tempIlist;
    CDOUBLE *tempRlist;
    char    tempValue[256];
    CCHAR   *tempClist;

    ROUTINE(printAttributes);

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

\begin{frame}
  \Frametitle{Explanation of {\tt train2.c} (17)}

  \begin{itemize}
  \item Lines 428--431: definition of the function to add an attribute
    named {\tt attrName} with the (possibly modified) value {\tt
      attrValue} to the Node, Edge, or Face, whose {\tt ego} is {\tt
      eobj}
    \item Lines 436--439:  the declaration {\tt CINT} is simply a
      macro that expands to {\tt const int}, {\tt CDOUBLE} expands to
      {\tt const double}, and {\tt CCHAR} expands to {\tt const char}.
      These are needed to match the declarations of {\tt
        EG\_attributeRet} and {\tt EG\_attributeGet} in {\tt EGADS}
  \end{itemize}
\end{frame}

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

  \begin{minipage}{0.95\textwidth}
\begin{Verbatim}[frame=single,numbers=left,fontsize=\tiny,firstnumber=last,xleftmargin=5mm]
    /* remove the attribute if it exists */
    status = EG_attributeRet(eobj, attrName, &attrType, &attrLen,
                             &tempIlist, &tempRlist, &tempClist);
    if (status == EGADS_SUCCESS) {
        status = EG_attributeDel(eobj, attrName);
        CHECK_STATUS(EG_attributeDel);
    }

    /* if attrValue was a percent-sign, add an integer attribute */
    if (strcmp(attrValue, "@") == 0) {
        status = EG_attributeAdd(eobj, attrName, ATTRINT, 1,
                                 &index, NULL, NULL);
        CHECK_STATUS(EG_attributeAdd);

    /* otherise add a string attribute */
    } else if (STRLEN(attrValue) > 0) {
        status = convertAtSign(attrValue, index, tempValue);
        CHECK_STATUS(convertAtSign);

        status = EG_attributeAdd(eobj, attrName, ATTRSTRING, 0,
                                 NULL, NULL, tempValue);
        CHECK_STATUS(EG_attributeAdd);
    }

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

\begin{frame}
  \Frametitle{Explanation of {\tt train2.c} (18)}

  \begin{itemize}
  \item Lines 445--450: if the {\tt attrName} attributes exists on {\tt
    eboj}, delete it.  The reason we chack if it exists first is to
    avoid an error being generated by {\tt EG\_attributeDel}.  Notice
    on line 446 the three places that an attribute could be returned,
    depending on its type
  \item Lines 453--456: if the {\tt attrValue} was a single at-sign,
    we are going to store a single integer for this attribute
  \item Lines 460--461: convert {\tt attrValue} to {\tt tempValue} by
    replacing at-signs with the value of {\tt index}.  The routine
    that does this is listed below
  \item Lines 463--465: add a string attribute to {\tt ego}
  \end{itemize}
\end{frame}

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

  \begin{minipage}{0.95\textwidth}
\begin{Verbatim}[frame=single,numbers=left,fontsize=\tiny,firstnumber=last,xleftmargin=5mm]
/*
 ************************************************************************
 *                                                                      *
 *   printAttributes - print attributes associated with an ego          *
 *                                                                      *
 ************************************************************************
 */

#ifdef DEBUG
static int
printAttributes(ego eobj)               /* (in)  ego object */
{
    int     status=EGADS_SUCCESS;       /* (out)  return status */

    int     attrType, attrLen, nattr, iattr, i;
    CINT    *tempIlist;
    CDOUBLE *tempRlist;
    CCHAR   *tempClist, *attrName;

    ROUTINE(printAttributes);

    /* --------------------------------------------------------------- */

    status = EG_attributeNum(eobj, &nattr);
    CHECK_STATUS(EG_attributeNum);
\end{Verbatim}
  \end{minipage}
\end{frame}

\begin{frame}
  \Frametitle{Explanation of {\tt train2.c} (19)}

  \begin{itemize}
  \item Lines 494--495: return the number of attributes on {\tt eobj}
  \end{itemize}
\end{frame}

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

  \begin{minipage}{0.95\textwidth}
\begin{Verbatim}[frame=single,numbers=left,fontsize=\tiny,firstnumber=last,xleftmargin=5mm]
    for (iattr = 1; iattr <= nattr; iattr++) {
        status = EG_attributeGet(eobj, iattr, &attrName, &attrType, &attrLen,
                                 &tempIlist, &tempRlist, &tempClist);
        CHECK_STATUS(EG_attributeGet);

        printf("   %-20s ", attrName);
        if (attrType == ATTRINT) {
            for (i = 0; i < attrLen; i++) {
                printf(" %6d", tempIlist[i]);
            }
            printf("\n");
        } else if (attrType == ATTRREAL) {
            for (i = 0; i < attrLen; i++) {
                printf(" %13.7f", tempRlist[i]);
            }
            printf("\n");
        } else if (attrType == ATTRSTRING) {
            printf(" %s\n", tempClist);
        }
    }

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

\begin{frame}
  \Frametitle{Explanation of {\tt train2.c} (20)}

  \begin{itemize}
  \item Lines 497--499: return the ${\tt iattr}^{th}$ attribute
    (bias-1) from {\tt eobj}.  Notice that we get its type {\tt
    attrType}, how many there are {\tt attrLen}, and either {\tt
    tempIlist} (if integers), {\tt tempRlist} (if doubles) or {\tt
    tempClist} (if a character string)
  \item Lines 501--515: depending on the type (in {\tt attrType}), we
    print the values
  \end{itemize}
\end{frame}

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

  \begin{minipage}{0.95\textwidth}
\begin{Verbatim}[frame=single,numbers=left,fontsize=\tiny,firstnumber=last,xleftmargin=5mm]
/*
 ************************************************************************
 *                                                                      *
 *   convertAtSign - convert at-signs to number                         *
 *                                                                      *
 ************************************************************************
 */

static int
convertAtSign(char instring[],          /* (in)  input string */
              int  number,              /* (in)  number to use instead of at-sign */
              char outstring[])         /* (out) output string */
{
    int     status=EGADS_SUCCESS;       /* (out)  return status */

    int     i, j, natsign=0;
    char    format[512];

    ROUTINE(convertAtSign);

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

\begin{frame}
  \Frametitle{Explanation of {\tt train2.c} (21)}

  \begin{itemize}
  \item Lines 530--532: this function take a string ({\tt instring})
    and generates a string ({\tt outstring}) in which the at-signs in
    {\tt instring} are replaced with the integer {\tt index}
  \end{itemize}
\end{frame}

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

  \begin{minipage}{0.95\textwidth}
\begin{Verbatim}[frame=single,numbers=left,fontsize=\tiny,firstnumber=last,xleftmargin=5mm]
    /* build a format string that replaces @ with %d */
    j = 0;
    for (i = 0; i < STRLEN(instring); i++) {
        if (instring[i] != '@') {
            format[j++] = instring[i];
        } else if(natsign >= 3) {
            format[j++] = instring[i];
        } else {
            natsign++;
            format[j++] = '\%';
            format[j++] = 'd';
        }
    }
    format[j++] = '\0';

    /* if there are no at-signs, we can do a simple copy */
    if (natsign == 0) {
        strncpy(outstring, instring, 256);

    /* otherwise print to the outstring */
    } else {
        snprintf(outstring, 256, format, number, number, number);
    }

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

\begin{frame}
  \Frametitle{Exercise3}

  \begin{itemize}
  \item Make a new UDP ({\tt exercise3}) in the directory (folder) {\tt
    udpExercise2}
    \begin{itemize}
    \item the purpose is: copy an Edge attribute with a given name to
      its Nodes.  If the Node already has the attribute, change its
      value to the string {\tt **conflict**}
    \item the input parameter is:
      \begin{itemize}
      \item {\tt attrname} - name of the attribute to copy
      \end{itemize}
    \end{itemize}
  \item Make sure that your UDF does appropriate error checking
  \end{itemize}
\end{frame}

\end{document}
