Logo Search packages:      
Sourcecode: felt version File versions  Download package

problem.c

/*
    This file is part of the FElt finite element analysis package.
    Copyright (C) 1993-2000 Jason I. Gobat and Darren C. Atkinson

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program 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 General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

/************************************************************************
 * File:    problem.c                                 *
 *                                                    *
 * Description:   This file contains the public and private function    *
 *          definitions for the creation of a problem instance.   *
 ************************************************************************/

# include <stdio.h>
# include <string.h>
# include <unistd.h>
# include "error.h"
# include "problem.h"
# include "allocate.h"
# include "definition.h"

# ifdef NEED_STRDUP
extern char *strdup ( );
# endif

# define streq(a,b)     !strcmp(a,b)
# define strneq(a,b)    strcmp(a,b)

# ifndef LIBDIR
# define LIBDIR "/usr/local/lib/felt"
# endif

# ifndef CPP
# define CPP "/lib/cpp"
# endif


Problem    problem;
Analysis   analysis;
Appearance appearance;

static struct material default_material = {NULL, "default_material"};
static struct constraint default_constraint = {NULL, "default_constraint"};

static char *cpp;
static char  cpp_command [2048];


/************************************************************************
 * Function:      defnlookup                                *
 *                                                    *
 * Description:   Looks up an element definition by name.               *
 ************************************************************************/

Definition defnlookup (name)
    char *name;
{
    char      *ptr;
    Definition definition;


    ptr = name;
    while (*ptr != ' ' && *ptr != 0) {
      ptr ++;
    }

    *ptr = 0;
    if (!(definition = LookupDefinition (name)))
      error ("%s elements have no definition", name);

    return definition;
}


/************************************************************************
 * Function:      node_cmp                                  *
 *                                                    *
 * Description:   Compares two nodes by number.                   *
 ************************************************************************/

static int node_cmp (n1, n2)
    Item n1;
    Item n2;
{
    return ((Node) n1) -> number - ((Node) n2) -> number;
}


/************************************************************************
 * Function:      element_cmp                               *
 *                                                    *
 * Description:   Compares two elements by number.                *
 ************************************************************************/

static int element_cmp (e1, e2)
    Item e1;
    Item e2;
{
    return ((Element) e1) -> number - ((Element) e2) -> number;
}


/************************************************************************
 * Function:      material_cmp                                    *
 *                                                    *
 * Description:   Compares two materials by name.                       *
 ************************************************************************/

static int material_cmp (m1, m2)
    Item m1;
    Item m2;
{
    return strcmp (((Material) m1) -> name, ((Material) m2) -> name);
}


/************************************************************************
 * Function:      distributed_cmp                                 *
 *                                                    *
 * Description:   Compares two distributed loads by name.               *
 ************************************************************************/

static int distributed_cmp (d1, d2)
    Item d1;
    Item d2;
{
    return strcmp (((Distributed) d1) -> name, ((Distributed) d2) -> name);
}


/************************************************************************
 * Function:      force_cmp                                 *
 *                                                    *
 * Description:   Compares two forces by name.                    *
 ************************************************************************/

static int force_cmp (f1, f2)
    Item f1;
    Item f2;
{
    return strcmp (((Force) f1) -> name, ((Force) f2) -> name);
}


/************************************************************************
 * Function:      constraint_cmp                                  *
 *                                                    *
 * Description:   Compares two constraints by name.               *
 ************************************************************************/

static int constraint_cmp (c1, c2)
    Item c1;
    Item c2;
{
    return strcmp (((Constraint) c1) -> name, ((Constraint) c2) -> name);
}


/************************************************************************
 * Function:      loadcase_cmp                                    *
 *                                                    *
 * Description:   Compares two load cases by name.                *
 ************************************************************************/

static int loadcase_cmp (lc1, lc2)
    Item lc1;
    Item lc2;
{
    return strcmp (((LoadCase) lc1) -> name, ((LoadCase) lc2) -> name);
}


/************************************************************************
 * Function:      resolve_node                                    *
 *                                                    *
 * Description:   Resolve the names of objects for a node.        *
 ************************************************************************/

static int resolve_node (item)
    Item item;
{
    struct force      f;
    struct constraint c;
    unsigned            number;
    Tree          tree;
    Node          node;



    /* Store the node in the array. */

    node = (Node) item;
    number = node -> number;
    problem.nodes [number] = node;


    /* Resolve the constraint. */

    tree = problem.constraint_tree;
    c.name = (char *) node -> constraint;

    if (c.name) {
      node -> constraint = (Constraint) TreeSearch (tree, &c);

      if (!node -> constraint)
          error ("node %u used undefined constraint %s", number, c.name);

      Deallocate (c.name);
    } else
      node -> constraint = &default_constraint;


    /* Resolve the force. */

    tree = problem.force_tree;
    f.name = (char *) node -> force;

    if (f.name) {
      node -> force = (Force) TreeSearch (tree, &f);

      if (!node -> force)
          error ("node %u uses undefined force %s", number, f.name);

      Deallocate (f.name);
    }

    return 0;
}


/************************************************************************
 * Function:      resolve_element                                 *
 *                                                    *
 * Descriptin:    Resolve the names of objects for an element.          *
 ************************************************************************/

static int resolve_element (item)
    Item item;
{
    struct distributed d;
    struct material    m;
    unsigned             i;
    unsigned             number;
    Tree           tree;
    Element        element;


    /* Store the element in the array. */

    element = (Element) item;
    number = element -> number;
    problem.elements [number] = element;



    /* Resolve the material. */

    tree = problem.material_tree;
    m.name = (char *) element -> material;

    if (m.name) {
      element -> material = (Material) TreeSearch (tree, &m);

      if (!element -> material)
          error ("element %u uses undefined material %s", number, m.name);

      Deallocate (m.name);
    } else
      element -> material = &default_material;


    /* Resolve the loads. */

    tree = problem.distributed_tree;

    for (i = 1; i <= element -> numdistributed; i ++) {
      d.name = (char *) element -> distributed [i];
      element -> distributed [i] = (Distributed) TreeSearch (tree, &d);

      if (!element -> distributed)
          error ("element %u used undefined load %s", number, d.name);

      Deallocate (d.name);
    }


    /* Set the pointers to the nodes. */

    if (element -> definition)
      for (i = 1; i <= element -> definition -> numnodes; i ++)
          if (element -> node [i])
            element -> node [i] = problem.nodes [(int) element -> node [i]];

    return 0;
}

static int case_count;

/************************************************************************
 * Function:      resolve_loadcase                          *     
 *                                                    *
 * Description:   Resolve the names of objects for a loadcase.          *
 ************************************************************************/

static int resolve_loadcase (item)
    Item item;
{
    struct force       f;
    struct node          n;
    struct distributed l;
    struct element     e;
    LoadCase             loadcase;
    unsigned             i;


    /* Store the loadcase in the array. */

    loadcase = (LoadCase) item;
    problem.loadcases [case_count] = loadcase;

    for (i = 1 ; i <= loadcase -> numforces ; i++) {
       f.name = (char *) loadcase -> forces [i];
       n.number = (unsigned) loadcase -> nodes [i];

       loadcase -> nodes [i] = (Node) TreeSearch (problem.node_tree, &n);
       if (!loadcase -> nodes [i])
           error ("load case %s used undefined node %d", loadcase -> name, n.number);

       loadcase -> forces [i] = (Force) TreeSearch (problem.force_tree, &f);
       if (!loadcase -> forces [i])
           error ("load case %s used undefined force %s", loadcase -> name, f.name);

       Deallocate (f.name);
    }

    for (i = 1 ; i <= loadcase -> numloads ; i++) {
       l.name = (char *) loadcase -> loads [i];
       e.number = (unsigned) loadcase -> elements [i];

       loadcase -> elements [i] = (Element) TreeSearch (problem.element_tree, &e);
       if (!loadcase -> elements [i])
           error ("load case %s used undefined element %d", loadcase -> name, e.number);

       loadcase -> loads [i] = (Distributed) TreeSearch (problem.distributed_tree, &f);
       if (!loadcase -> loads [i])
           error ("load case %s used undefined load %s", loadcase -> name, l.name);

       Deallocate (l.name);
    }

    case_count ++;

    return 0;
}

/************************************************************************
 * Function:      resolve_names                                   *
 *                                                    *
 * Description:   Resolves the names and numbers of objects making sure *
 *          all that are specified are actually defined.  We've   *
 *          actually cheated and stored the name or number of the *
 *          object instead of a pointer to the object in the node *
 *          and element structures.  This allows nodes and elements     *
 *          to reference objects before they are defined.  We fix *
 *          those pointers here.                            *
 ************************************************************************/

static void resolve_names ( )
{
    unsigned      i;
    struct node   n;


    if (problem.num_nodes) {
      if (!(problem.nodes = Allocate (Node, problem.num_nodes)))
          Fatal ("unable to allocate memory");

      UnitOffset (problem.nodes);

      for (i = 1; i <= problem.num_nodes; i ++)
          problem.nodes [i] = NULL;

      TreeSetIterator (problem.node_tree, resolve_node);
      TreeIterate (problem.node_tree);

      for (i = 1; i <= problem.num_nodes; i ++)
          if (!problem.nodes [i])
            error ("node %u is not defined", i);
    }

    if (problem.num_elements) {
      if (!(problem.elements = Allocate (Element, problem.num_elements)))
          Fatal ("unable to allocate memory");

      UnitOffset (problem.elements);

      for (i = 1; i <= problem.num_elements; i ++)
          problem.elements [i] = NULL;

      TreeSetIterator (problem.element_tree, resolve_element);
      TreeIterate (problem.element_tree);

      for (i = 1; i <= problem.num_elements; i ++)
          if (!problem.elements [i])
            error ("element %u is not defined", i);
    }

    if ((problem.num_loadcases = TreeSize(problem.loadcase_tree))) {
        if (!(problem.loadcases = Allocate (LoadCase, problem.num_loadcases)))
            Fatal ("unable to allocate memory");

        UnitOffset (problem.loadcases);

        for (i = 1 ; i <= problem.num_loadcases ; i ++)
            problem.loadcases [i] = NULL;

        case_count = 1;
        TreeSetIterator (problem.loadcase_tree, resolve_loadcase);
        TreeIterate (problem.loadcase_tree);
    }

      /*
       * resolve any node references given in the analysis parameters
       */

    if (analysis.numnodes) {
        for (i = 1 ; i <= analysis.numnodes ; i++) {
            n.number = (unsigned) analysis.nodes [i];
            analysis.nodes [i] = (Node) TreeSearch (problem.node_tree, &n);
            if (analysis.nodes [i] == NULL)
                error ("analysis node %d not defined", n.number);
        }
    }

    if (analysis.input_node) {
        n.number = (unsigned) analysis.input_node;
        analysis.input_node = (Node) TreeSearch (problem.node_tree, &n);
        if (analysis.input_node == NULL)
            error ("analysis input node %d not defined", n.number);
    }
}


/************************************************************************
 * Function:      ReadFeltFile                                    *
 *                                                    *
 * Description:   Reads a felt file using the preprocessor if desired.  A     *
 *          filename of "-" indicates standard input (can only be *
 *          used initially) and a NULL filename indicates no file *
 *          (an empty problem is created).                        *
 ************************************************************************/

int ReadFeltFile (filename)
    char *filename;
{
    unsigned i;
    char     buffer [2048];
    char    *plural;
    FILE    *input;


    /* Open the file and send it through the preprocessor. */

    if (filename) {
# ifndef DOS
      if (cpp != NULL) {
          if (streq (filename, "-"))
            sprintf (buffer, "%s", cpp_command);
          else {
            if (access (filename, R_OK)) {
                error ("Unable to open %s", filename);
                return 1;
            }
            sprintf (buffer, "%s %s", cpp_command, filename);
          }

          if (!(input = popen (buffer, "r"))) {
            error ("Unable to execute %s", cpp);
            return 1;
          }

      } else
# endif
      {
          if (streq (filename, "-"))
            input = stdin;
          else if (!(input = fopen (filename, "r"))) {
            error ("Unable to open %s", filename);
            return 1;
          }
      }
    } else
      input = NULL;


    /* Initialize the problem instance. */

    problem.mode       = Static;
    problem.title      = strdup ("");
    problem.num_dofs         = 0;
    problem.num_nodes        = 0;
    problem.num_elements     = 0;
    problem.num_loadcases    = 0;
    problem.num_errors       = 0;
    problem.line       = 1;
    problem.nodes      = NULL;
    problem.elements         = NULL;
    problem.node_tree        = TreeCreate (node_cmp);
    problem.element_tree     = TreeCreate (element_cmp);
    problem.material_tree    = TreeCreate (material_cmp);
    problem.distributed_tree = TreeCreate (distributed_cmp);
    problem.force_tree       = TreeCreate (force_cmp);
    problem.constraint_tree  = TreeCreate (constraint_cmp);
    problem.loadcase_tree    = TreeCreate (loadcase_cmp);

    if (filename)
      problem.filename = strdup (streq (filename, "-") ? "stdin" : filename);
    else
      problem.filename = strdup ("");


    /* Initialize the analysis structure. */

    analysis.start     = 0.0;
    analysis.step      = 0.0;
    analysis.stop      = 0.0;
    analysis.gamma     = 0.0;
    analysis.beta      = 0.0;
    analysis.alpha     = 0.0;
    analysis.Rk          = 0.0;
    analysis.Rm        = 0.0;
    analysis.iterations = 0;
    analysis.load_steps = 0;
    analysis.tolerance = 0.0;
    analysis.relaxation = 0.0;
    analysis.mass_mode = 0;
    analysis.nodes     = NULL;
    analysis.numnodes  = 0;
    analysis.numdofs   = 0;
    analysis.input_node = NULL;
    analysis.input_dof = 0;

    for (i = 1 ; i <= 3 ; i++)
       analysis.gravity [i] = 0.0;


    /* Initialize the appearance structure. */

    InitAppearance ( );


    /* Parse the input and resolve the names. */

    if (filename) {
      init_lexer (input);
      yyparse ( );
      problem.line = 0;

# ifdef DOS
        fclose (input);
# else
      if (cpp)
          pclose (input);
      else if (input != stdin)
          fclose (input);
# endif

      if (!problem.num_errors)
          resolve_names ( );


      /* Report any errors. */

      if (problem.num_errors) {
          plural = problem.num_errors != 1 ? "errors" : "error";
          error ("%u %s found in input", problem.num_errors, plural);
          return problem.num_errors;
      }
    }

    return 0;
}


/************************************************************************
 * Function:      SetAnalysisMode                                 *
 *                                                    *
 * Description:   Returns the current analysis mode for given problem   *
 *          instance.  Applications cannot simply use             *
 *          problem.mode blindly because we may want to modify    *
 *          the mode to reflect factors other than those that     *
 *          the user can specify with analysis= (i.e., we want    *
 *          to allow for sub-modes)                         *
 ************************************************************************/

AnalysisType SetAnalysisMode ( )
{
    if (problem.mode == Static && problem.num_loadcases > 0)
        return StaticLoadCases;
    else if (problem.mode == Static && 
             (analysis.input_node || analysis.input_dof))
        return StaticLoadRange;
    else if (problem.mode == StaticSubstitution && 
             (analysis.input_node || analysis.input_dof)) 
       return StaticSubstitutionLoadRange;
    else if (problem.mode == StaticIncremental && 
             (analysis.input_node || analysis.input_dof)) 
       return StaticSubstitutionLoadRange;

    return problem.mode;        
}


/************************************************************************
 * Function:      ParseCppOptions                                 *
 *                                                    *
 * Description:   Parses and removes the preprocesor options from the   *
 *          command line arguments.                         *
 ************************************************************************/

int ParseCppOptions (argc, argv)
    int  *argc;
    char *argv [ ];
{
    int   i;
    int   j;
    char *arg;
    char  cpp_args [2048];


    j = 1;
    cpp = CPP;
    cpp_args [0] = 0;

    for (i = 1; i < *argc; i ++)
      if ((arg = argv [i]) [0] != '-') {
          argv [j ++] = arg;
      } else if (streq (arg, "-nocpp")) {
          cpp = NULL;
      } else if (streq (arg, "-cpp")) {
          if (++ i == *argc)
            return 1;
          cpp = argv [i];
      } else if (arg [1] == 'D' || arg [1] == 'U' || arg [1] == 'I') {
          strcat (cpp_args, " '");
          strcat (cpp_args, arg);
          strcat (cpp_args, "'");
      } else
          argv [j ++] = arg;

    if (cpp)
      sprintf (cpp_command, "%s -I%s %s", cpp, LIBDIR, cpp_args);

    argv [*argc = j] = NULL;
    return 0;
}


/************************************************************************
 * Function:      CompileCode                               *
 *                                                    *
 * Description:   Compiles a string to a piece of code.                 *
 ************************************************************************/

int CompileCode (text)
    char *text;
{
    char input [2048];


    sprintf (input, "x = %s end", text);

    init_lexer (NULL);
    problem.input = input;
    return yyparse ( );
}


/************************************************************************
 * Function:      exptod                                          *
 *                                                    *
 * Description:   Converts a string representing an expression to a     *
 *          double (works just like strtod ( )).                  *
 ************************************************************************/

double exptod (expr, ptr)
    char  *expr;
    char **ptr;
{
    Code code;


    code = CompileCode (expr) ? NULL : InCore;

    if (ptr)
      *ptr = problem.input;

    return EvalCode (code, 0.0);
}


/************************************************************************
 * Function:      InitAppearance                                  *
 *                                                    *
 * Description:   Initializes the appearance structure, first freeing   *
 *          any existing information.                       *
 ************************************************************************/

void InitAppearance ( )
{
    unsigned i;


    appearance.node_numbers    = UnspecifiedValue;
    appearance.element_numbers = UnspecifiedValue;
    appearance.snap            = UnspecifiedValue;
    appearance.grid            = UnspecifiedValue;
    appearance.snap_size       = UnspecifiedValue;
    appearance.grid_size       = UnspecifiedValue;
    appearance.x_min           = UnspecifiedValue;
    appearance.x_max           = UnspecifiedValue;
    appearance.y_min           = UnspecifiedValue;
    appearance.y_max           = UnspecifiedValue;
    appearance.x_pos           = UnspecifiedValue;
    appearance.y_pos           = UnspecifiedValue;
    appearance.scale           = UnspecifiedValue;
    appearance.width           = UnspecifiedValue;
    appearance.height          = UnspecifiedValue;
    appearance.num_figures     = 0;

    for (i = 0; i < appearance.num_figures; i ++) {
      Deallocate (appearance.figures [i].color);
      Deallocate (appearance.figures [i].text);
      Deallocate (appearance.figures [i].font);
      Deallocate (appearance.figures [i].points);
    }

    Deallocate (appearance.figures);
    Deallocate (appearance.label_font);
    Deallocate (appearance.node_color);
    Deallocate (appearance.element_color);

    appearance.figures       = NULL;
    appearance.label_font    = NULL;
    appearance.node_color    = NULL;
    appearance.element_color = NULL;
    appearance.tool_color    = NULL;
    appearance.tool_font     = NULL;
}

Generated by  Doxygen 1.6.0   Back to index