Opened 4 years ago

Closed 4 years ago

Last modified 4 years ago

#6125 closed defect (fixed)

Don't throw / assert / abort inside FMUs

Reported by: AnHeuermann Owned by: AnHeuermann
Priority: critical Milestone: 1.16.0
Component: FMI Version: v1.16.0-dev
Keywords: fmi, fmu, assert, throw, abort Cc:

Description

When an error occurs inside an OpenModelica FMU we should return the appropriate FMI error code and don't throw an error / abort.

For example an FMU that has an equation with a square root will call throwStreamPrintWithEquationIndexes if the argument for sqrt is negative.

But for instance this error is recoverable. Such an equation must be called by the FMU simulator multiple times, and if the evaluation failed the simulator can try with a different value. This is needed e.g. for iterative solvers for algebraic loops.

Related issue: OMSimulator Issue#808

Change History (7)

comment:1 Changed 4 years ago by AnHeuermann

There are two different approaches I could think off:

  1. Change the code generation to don't use throwStreamPrintWithEquationIndexes and similar in FMI context. But to report the error we need to change all C functions to return an FMI error code after each call and propagate it upwards. This will need a lot of changes and has a big potential to mess up a lot of code, since we share code generation for C and FMI.
  1. Change function throwStreamPrintWithEquationIndexes and similar to behave different inside the runtime linked to an FMU. It's not longer allowed to throw errors, but will jump / goto to some location to report the correct error code. But we have different runtimes linked in an C FMU. I think those are mainly libSimulationRuntimeC and libOpenModelicaFMIRuntimeC. So I expect to get some trouble with build dependecies and different behavior for static or dynamic linked FMUs.

On both approaches is hard to differentiate what is a recoverable error (dividing by zero, sqrt of a negative number, ...) and what is not (can't allocate memory, dimensions of key components not correct, ...).

At the moment I prefer Option 2.

comment:2 Changed 4 years ago by sjoelund.se

I prefer 3: Fix the FMU functions to set the jumpers to not be NULL, and catch the errors so you can return the correct code in the FMI function call :)

I guess 2 is actually the same, but just the way you implement not making it crash.

comment:3 Changed 4 years ago by lochel

The jumpers are problematic for certain industrial customers: see https://trac.openmodelica.org/OpenModelica/ticket/5965

comment:4 Changed 4 years ago by AnHeuermann

I can add a try-catch block to all fmi2 functions. This would look something like this:

fmi2Status fmi2GetReal([..]) {
  [Variables]

  threadData = comp->threadData;

  [Check for invalid state]

  setThreadData(comp);
#if NUMBER_OF_REALS > 0

  saveJumpState = threadData->currentErrorStage;
  threadData->currentErrorStage = ERROR_INTEGRATOR;
  /* TRY */
#if !defined(OMC_EMCC)
  MMC_TRY_INTERNAL(simulationJumpBuffer)
#endif

  [Stuff that normally happens]

  success = 1;

  /* CATCH */
#if !defined(OMC_EMCC)
  MMC_CATCH_INTERNAL(simulationJumpBuffer)
#endif
  threadData->currentErrorStage = saveJumpState;
  if (!success)
  {
    FILTERED_LOG(comp, fmi2OK, LOG_FMI2_CALL, "fmi2GetReal: Catched error")
    return fmi2Discard;
  }
#endif
  return fmi2OK;
}

@lochel I think for the problem described in #5965 I can add defines with OMC_NO_THREADS, so that it will not add more problems for that. Fixing some of the problems from #5965 along the way should be possible as well.

comment:6 Changed 4 years ago by AnHeuermann

  • Resolution set to fixed
  • Status changed from new to closed

The PR is merged into the master. There are probably still some fmi functions left that don't catch asserts.
But I'm closing this for now. If there are more problems feel free to re-open.

comment:7 Changed 4 years ago by casella

  • Milestone changed from 1.17.0 to 1.16.0

The fix will be available in 1.16.0

Note: See TracTickets for help on using tickets.