/* NOTE: provisional steady state finding! */
SBML_ODESOLVER_API int IntegratorInstance_checkSteadyState(integratorInstance_t *engine)
{
  int i;
  double dy_mean, dy_var, dy_std;
  cvodeData_t *data = engine->data;
  odeModel_t *om = engine->om;
  
  /* calculate the mean and standard deviation of rates of change and
     store in cvodeData_t * */
  dy_mean = 0.0;
  dy_var = 0.0;
  dy_std = 0.0;
  
  for ( i=0; i<om->neq; i++ ) {
    dy_mean += fabs(evaluateAST(om->ode[i],data));
  }
  dy_mean = dy_mean / om->neq;
  for ( i=0; i<om->neq; i++ ) {
    dy_var += MySQR(evaluateAST(om->ode[i],data) - dy_mean);
  }
  dy_var = dy_var / (om->neq -1);
  dy_std = MySQRT(dy_var);

  /* stop integrator if mean + std of rates of change are lower than
     1e-11 */
  if ( (dy_mean + dy_std) < 1e-11 ) {
    data->steadystate = 1;
    SolverError_error(WARNING_ERROR_TYPE,
		      SOLVER_MESSAGE_STEADYSTATE_FOUND,
		      "Steady state found. "
		      "Simulation aborted at %g seconds. "
		      "Mean of rates: %g, std %g",
		      data->currenttime, dy_mean, dy_std);
    return(1) ;
  }
  else {
    data->steadystate = 0;
    return(0);
  }  
}
示例#2
0
double SolverData::evaluate(const ASTNode* node)
{
  double result{0};

  if ( !node ) 
  {
    m_Errors.add(new SimError(SIM_ERROR_EMPTY_AST, "Empy ASTNode"));
    return 0;
  }
  if ( node->isUnknown() ) 
  {
    m_Errors.add(new SimError(SIM_ERROR_UNKNOWN_AST, "Unknown ASTNode"));
    return 0;
  }

  int childnum = node->getNumChildren();
  int isTrue{};
  int i{};

  ASTNodeType_t type = node->getType();
  switch(type)
  {
    case AST_INTEGER:
      result = (double) node->getInteger();      
      break;
    case AST_REAL:
      result = node->getReal();
      break;
    case AST_REAL_E:
      result = node->getReal();
      break;      
    case AST_RATIONAL:
      result = node->getReal() ;
      break;
    case AST_NAME:
      {
        const OdeVariable* variable = (const OdeVariable*) node->getUserData();
        if (variable)
        {

          int index = variable->getIndex();
          switch (m_EvalStatus[index])
          {
            case EVAL_DOING:
              {
                std::ostringstream strstr;
                strstr << "Cyclic AST evaluation at " << node->getName();
                m_Errors.add(new SimError(SIM_ERROR_CYCLIC_AST, strstr.str()));          
                break;
              }
            case EVAL_DONE:
              result = m_Values[index];
              break;
            default:                             // EVAL_WAIT
              m_EvalStatus[index] = EVAL_DOING;
              if (variable->getType() == ODE_ASSIGNMENT_VARIABLE)
              {
                result=evaluate(m_Model->getAssignment(variable->getEqIndex()));

              } else if (variable->getInitEqIndex()>=0)
              {
                result=evaluate(m_Model->getInitAssignment(variable->getInitEqIndex()));
              } else 
              {
                //should never happen
                m_Errors.add(new SimError(SIM_UNKNOWN_ERROR, LEVEL_FATAL));          
              }
              m_Values[index] = result;
              m_EvalStatus[index] = EVAL_DONE;
              break;
          }
        } else 
        {
          const char* name = node->getName();          
          if ( strcmp(name, "t") == 0
              || strcmp(name,"T") == 0 
              || strcmp(name,"time") == 0 
              || strcmp(name, "Time") == 0 
              || strcmp(name, "TIME") == 0 ) 
          { 
            result = (double) m_Time; 
          } else 
          {
            std::ostringstream strstr;
            strstr << node->getName() << " has not beed defined";
            m_Errors.add(new SimError(SIM_ERROR_CYCLIC_AST, strstr.str()));          
            result = 0.0;
          }
        }
        break;
      }
    case AST_FUNCTION_DELAY:
      m_Errors.add(new SimError(SIM_WARNING_DELAY_ODE
          , "Solving ODEs with Delay is not implemented. "
          "Defaults to 0 to avoid program crash", LEVEL_WARNING));
      result = 0.0;
      break;
    case AST_NAME_TIME:
      result = (double) m_Time;
      break;

    case AST_CONSTANT_E:
      /** exp(1) is used to adjust exponentiale to machine precision */
      result = (double)exp(1.0);
      break;
    case AST_CONSTANT_FALSE:
      result = 0.0;
      break;
    case AST_CONSTANT_PI:
      /** pi = 4 * atan 1  is used to adjust Pi to machine precision */
      result = 4.*atan(1.);
      break;
    case AST_CONSTANT_TRUE:
      result = 1.0;
      break;

    case AST_PLUS:
      result = 0.0;
      for(i=0; i<childnum; ++i) 
        result += evaluate(node->getChild(i));   
      break;      
    case AST_MINUS:
      if(childnum<2)
        result = - (evaluate(node->getChild(0)));
      else
        result = evaluate(node->getChild(0)) - evaluate(node->getChild(1));
      break;
    case AST_TIMES:
      result = 1.0;
      for( i=0; i<childnum; ++i) 
        result *= evaluate(node->getChild(i));
      break;
    case AST_DIVIDE:
      result = evaluate(node->getChild(0)) / evaluate(node->getChild(1));
      break;
    case AST_POWER:
      result = pow(evaluate(node->getChild(0)),evaluate(node->getChild(1)));
      break;
    case AST_LAMBDA:
      m_Errors.add(new SimError(SIM_WARNING_LAMBDA_USING,
            "Lambda can only be used in function definitions."
            " Defaults to 0 to avoid program crash", LEVEL_WARNING));
      result = 0.0;
      break;
      /** FUNCTIONS: */
    case AST_FUNCTION:
      {
        std::ostringstream strstr;
        strstr << "The function " << node->getName() << "() has not been defined "
               << "in the SBML input model or as an externally "
               << "supplied function. Defaults to 0 to avoid "
               << "program crash";
      m_Errors.add(new SimError(SIM_WARNING_UNDEFINED_FUNCTION, strstr.str(), LEVEL_WARNING));
      result = 0.0;
      break;
      }
    case AST_FUNCTION_ABS:
      result = (double) fabs(evaluate(node->getChild(0)));
      break;
    case AST_FUNCTION_ARCCOS:
      result = acos(evaluate(node->getChild(0))) ;
      break;
    case AST_FUNCTION_ARCCOSH:
      result = acosh(evaluate(node->getChild(0)));
      break;
    case AST_FUNCTION_ARCCOT:
      /** arccot x =  arctan (1 / x) */
      result = atan(1./ evaluate(node->getChild(0)));
      break;
    case AST_FUNCTION_ARCCOTH:
      /** arccoth x = 1/2 * ln((x+1)/(x-1)) */
      result = ((1./2.)*log((evaluate(node->getChild(0))+1.)/
            (evaluate(node->getChild(0))-1.)) );
      break;
    case AST_FUNCTION_ARCCSC:
      /** arccsc(x) = Arctan(1 / sqrt((x - 1)(x + 1))) */
      result = atan( 1. / sqrt( (evaluate(node->getChild(0))-1.)*
            (evaluate(node->getChild(0))+1.) ) );
      break;
    case AST_FUNCTION_ARCCSCH:
      /** arccsch(x) = ln((1 + sqrt(1 + x^2)) / x) */
      result = log((1.+sqrt((1+MySQR(evaluate(node->getChild(0)))))) /
          evaluate(node->getChild(0)));
      break;
    case AST_FUNCTION_ARCSEC:
      /** arcsec(x) = arctan(sqrt((x - 1)(x + 1))) */   
      result = atan( sqrt( (evaluate(node->getChild(0))-1.)*
            (evaluate(node->getChild(0))+1.) ) );
      break;
    case AST_FUNCTION_ARCSECH:
      /** arcsech(x) = ln((1 + sqrt(1 - x^2)) / x) */
      result = log((1.+sqrt((1-MySQR(evaluate(node->getChild(0))))))/
          evaluate(node->getChild(0)));      
      break;
    case AST_FUNCTION_ARCSIN:
      result = asin(evaluate(node->getChild(0)));
      break;
    case AST_FUNCTION_ARCSINH:
      result = asinh(evaluate(node->getChild(0)));
      break;
    case AST_FUNCTION_ARCTAN:
      result = atan(evaluate(node->getChild(0)));
      break;
    case AST_FUNCTION_ARCTANH:
      result = atanh(evaluate(node->getChild(0)));
      break;
    case AST_FUNCTION_CEILING:
      result = ceil(evaluate(node->getChild(0)));
      break;
    case AST_FUNCTION_COS:
      result = cos(evaluate(node->getChild(0)));
      break;
    case AST_FUNCTION_COSH:
      result = cosh(evaluate(node->getChild(0)));
      break;
    case AST_FUNCTION_COT:
      /** cot x = 1 / tan x */
      result = (1./tan(evaluate(node->getChild(0))));
      break;
    case AST_FUNCTION_COTH:
      /** coth x = cosh x / sinh x */
      result = cosh(evaluate(node->getChild(0))) /
        sinh(evaluate(node->getChild(0)));
      break;  
    case AST_FUNCTION_CSC:
      /** csc x = 1 / sin x */
      result = (1./sin(evaluate(node->getChild(0))));
      break;
    case AST_FUNCTION_CSCH:
      /** csch x = 1 / sinh x  */
      result = (1./sinh(evaluate(node->getChild(0))));
      break;
    case AST_FUNCTION_EXP:
      result = exp(evaluate(node->getChild(0)));
      break;
    case AST_FUNCTION_FACTORIAL:
      {
        double floam_Timek = evaluate(node->getChild(0));
        int k = (int) floor(floam_Timek);
        if ( floam_Timek != k ) 
        {
          m_Errors.add(new SimError(SIM_WARNING_FACTORIAL_USING
              , "The factorial is only implemented "
              "for integer values. The floor value of the "
              "passed float is used for calculation!", LEVEL_WARNING));
        }

        for(result=1; k>1; --k)
          result *= k;
      }
      break;
    case AST_FUNCTION_FLOOR:
      result = floor(evaluate(node->getChild(0)));
      break;
    case AST_FUNCTION_LN:
      result = log(evaluate(node->getChild(0)));
      break;
    case AST_FUNCTION_LOG:
      /** log(x,y) = log10(y)/log10(x) (where x is the base)  */
      result = log10(evaluate(node->getChild(1))) /
        log10(evaluate(node->getChild(0)));
      break;
    case AST_FUNCTION_PIECEWISE:
      if ( evaluate(node->getChild(0)) ) {
        result = evaluate(node->getChild(1));
      }
      else {
        result = evaluate(node->getChild(2));
      }
      break;
    case AST_FUNCTION_POWER:
      result = pow(evaluate(node->getChild(0)),evaluate(node->getChild(1)));
      break;
    case AST_FUNCTION_ROOT:
      result = pow(evaluate(node->getChild(1)),
          (1./evaluate(node->getChild(0))));
      break;
    case AST_FUNCTION_SEC:
      /** sec x = 1 / cos x */
      result = 1./cos(evaluate(node->getChild(0)));
      break;
    case AST_FUNCTION_SECH:
      /** sech x = 1 / cosh x */
      result = 1./cosh(evaluate(node->getChild(0)));
      break;
    case AST_FUNCTION_SIN:
      result = sin(evaluate(node->getChild(0)));
      break;
    case AST_FUNCTION_SINH:
      result = sinh(evaluate(node->getChild(0)));
      break;
    case AST_FUNCTION_TAN:
      result = tan(evaluate(node->getChild(0)));
      break;
    case AST_FUNCTION_TANH:
      result = tanh(evaluate(node->getChild(0)));
      break;

    case AST_LOGICAL_AND:
      isTrue = 0;
      for ( i=0; i<childnum; ++i ) 
      {
        isTrue += (int)evaluate(node->getChild(i));
      }
      if ( isTrue == childnum ) 
      {
        result = 1.0;
      } else 
      {
        result = 0.0;
      }
      break;
    case AST_LOGICAL_NOT:
      result = (double) (!(evaluate(node->getChild(0))));
      break;
    case AST_LOGICAL_OR:
      isTrue = 0;
      for (i=0; i<childnum; ++i ) 
      {
        isTrue += (int)evaluate(node->getChild(i));
      }

      if ( isTrue > 0 ) 
      {
        result = 1.0;
      }
      else 
      {
        result = 0.0;
      }
      break;
    case AST_LOGICAL_XOR:
      /* n-ary: true if an odd number of children is true */
      isTrue = 0;
      for ( i=0; i<childnum; ++i ) 
      {
        isTrue += (int)evaluate(node->getChild(i));
      }
      if ( isTrue % 2 != 0 ) 
      {
        result = 1.0;
      } else 
      {
        result = 0.0;
      }
      break;
      /* !!! check n-ary definitions for relational operators !!! */
    case AST_RELATIONAL_EQ:
      /* n-ary: all children must be equal */
      result = 1.0;
      for ( i=1; i<childnum; ++i ) 
      {
        if ( (evaluate(node->getChild(0))) !=
            (evaluate(node->getChild(i))) ) 
        {
          result = 0.0;
        }
      }
      break;
    case AST_RELATIONAL_GEQ:
      /* n-ary: each child must be greater than or equal to the following */
      result = 1.0;
      for ( i=0; i < childnum-1; ++i ) 
      {
        if ( (evaluate(node->getChild(i))) <
            (evaluate(node->getChild(i+1))) ) 
        {
          result = 0.0;
        }
      }
      break;
    case AST_RELATIONAL_GT:
      /* n-ary: each child must be greater than the following */
      result = 1.0;
      for ( i=0; i<childnum-1; ++i ) 
      {
        if ( (evaluate(node->getChild(i))) <=
            (evaluate(node->getChild(i+1))) ) 
        {
          result = 0.0;
        }
      }
      break;
    case AST_RELATIONAL_LEQ:
      /* n-ary: each child must be lower than or equal to the following */
      result = 1.0;
      for ( i=0; i<childnum-1; ++i ) 
      {
        if ( (evaluate(node->getChild(i))) >
            (evaluate(node->getChild(i+1))) ) 
        {
          result = 0.0;
        }
      }
      break;
    case AST_RELATIONAL_LT :
      /* n-ary: each child must be lower the following */
      result = 1.0;
      for ( i=0; i<childnum-1; ++i ) 
      {
        if ( (evaluate(node->getChild(i))) >=
            (evaluate(node->getChild(i+1))) ) 
        {
          result = 0.0;
        }
      }
      break;
    default:
      result = 0;
      break;
  }
  return result;
}