namespace rrllvm
{

typedef std::tr1::weak_ptr<ModelResources> WeakModelPtr;
typedef std::tr1::shared_ptr<ModelResources> SharedModelPtr;
typedef std::tr1::unordered_map<std::string, WeakModelPtr> ModelPtrMap;

static Poco::Mutex cachedModelsMutex;
static ModelPtrMap cachedModels;

/**
 * copy the cached model fields between a cached model, and a
 * executable model.
 *
 * We don't want to have ExecutableModel inherit from CahcedModel
 * because they do compleltly different things, and have completly
 * differnt deletion semantics
 */
template <typename a_type, typename b_type>
void copyCachedModel(a_type* src, b_type* dst)
{
    dst->symbols = src->symbols;
    dst->context = src->context;
    dst->executionEngine = src->executionEngine;
    dst->errStr = src->errStr;

    dst->evalInitialConditionsPtr = src->evalInitialConditionsPtr;
    dst->evalReactionRatesPtr = src->evalReactionRatesPtr;
    dst->getBoundarySpeciesAmountPtr = src->getBoundarySpeciesAmountPtr;
    dst->getFloatingSpeciesAmountPtr = src->getFloatingSpeciesAmountPtr;
    dst->getBoundarySpeciesConcentrationPtr = src->getBoundarySpeciesConcentrationPtr;
    dst->getFloatingSpeciesConcentrationPtr = src->getFloatingSpeciesConcentrationPtr;
    dst->getCompartmentVolumePtr = src->getCompartmentVolumePtr;
    dst->getGlobalParameterPtr = src->getGlobalParameterPtr;
    dst->evalRateRuleRatesPtr = src->evalRateRuleRatesPtr;
    dst->getEventTriggerPtr = src->getEventTriggerPtr;
    dst->getEventPriorityPtr = src->getEventPriorityPtr;
    dst->getEventDelayPtr = src->getEventDelayPtr;
    dst->eventTriggerPtr = src->eventTriggerPtr;
    dst->eventAssignPtr = src->eventAssignPtr;
    dst->evalVolatileStoichPtr = src->evalVolatileStoichPtr;
    dst->evalConversionFactorPtr = src->evalConversionFactorPtr;
}


LLVMModelGenerator::LLVMModelGenerator()
{
    Log(Logger::PRIO_TRACE) << __FUNC__;
}

LLVMModelGenerator::~LLVMModelGenerator()
{
    Log(Logger::PRIO_TRACE) << __FUNC__;

}

bool LLVMModelGenerator::setTemporaryDirectory(const string& path)
{
    return true;
}

string LLVMModelGenerator::getTemporaryDirectory()
{
    return LLVMCompiler::gurgle();
}

class test
{
public:
    const int* p;
};

void testt(const int** p)
{
    *p = 0;
}

void testtt()
{
    test *t = new test();

    testt(&t->p);
}




ExecutableModel* LLVMModelGenerator::createModel(const std::string& sbml,
        uint options)
{
    bool computeAndAssignConsevationLaws =
            options & ModelGenerator::ComputeAndAssignConsevationLaws;

    bool forceReCompile = options & ModelGenerator::ForceReCompile;

    string md5;

    if (!forceReCompile)
    {
        // check for a chached copy
        md5 = rr::getMD5(sbml);

        ModelPtrMap::const_iterator i;

        SharedModelPtr sp;

        cachedModelsMutex.lock();

        if ((i = cachedModels.find(md5)) != cachedModels.end())
        {
            sp = i->second.lock();
        }

        cachedModelsMutex.unlock();

        // we could have recieved a bad ptr, a model could have been deleted,
        // in which case, we should have a bad ptr.

        if (sp)
        {
            Log(Logger::PRIO_DEBUG) << "found a cached model for " << md5;
            return new LLVMExecutableModel(sp);
        }
        else
        {
            Log(Logger::PRIO_TRACE) << "no cached model found for " << md5
                    << ", creating new one";
        }
    }

    SharedModelPtr rc(new ModelResources());

    ModelGeneratorContext context(sbml, computeAndAssignConsevationLaws);

    rc->evalInitialConditionsPtr =
            EvalInitialConditionsCodeGen(context).createFunction();

    rc->evalReactionRatesPtr =
            EvalReactionRatesCodeGen(context).createFunction();

    rc->getBoundarySpeciesAmountPtr =
            GetBoundarySpeciesAmountCodeGen(context).createFunction();

    rc->getFloatingSpeciesAmountPtr =
            GetFloatingSpeciesAmountCodeGen(context).createFunction();

    rc->getBoundarySpeciesConcentrationPtr =
            GetBoundarySpeciesConcentrationCodeGen(context).createFunction();

    rc->getFloatingSpeciesConcentrationPtr =
            GetFloatingSpeciesConcentrationCodeGen(context).createFunction();

    rc->getCompartmentVolumePtr =
            GetCompartmentVolumeCodeGen(context).createFunction();

    rc->getGlobalParameterPtr =
            GetGlobalParameterCodeGen(context).createFunction();

    rc->evalRateRuleRatesPtr =
            EvalRateRuleRatesCodeGen(context).createFunction();

    rc->getEventTriggerPtr =
            GetEventTriggerCodeGen(context).createFunction();

    rc->getEventPriorityPtr =
            GetEventPriorityCodeGen(context).createFunction();

    rc->getEventDelayPtr =
            GetEventDelayCodeGen(context).createFunction();

    rc->eventTriggerPtr =
            EventTriggerCodeGen(context).createFunction();

    rc->eventAssignPtr =
            EventAssignCodeGen(context).createFunction();

    rc->evalVolatileStoichPtr =
            EvalVolatileStoichCodeGen(context).createFunction();

    rc->evalConversionFactorPtr =
            EvalConversionFactorCodeGen(context).createFunction();

    if (options & ModelGenerator::ReadOnlyModel)
    {
        rc->setBoundarySpeciesAmountPtr = 0;
        rc->setBoundarySpeciesConcentrationPtr = 0;
        rc->setFloatingSpeciesConcentrationPtr = 0;
        rc->setCompartmentVolumePtr = 0;
        rc->setFloatingSpeciesAmountPtr = 0;
        rc->setGlobalParameterPtr = 0;
    }
    else
    {
        rc->setBoundarySpeciesAmountPtr = SetBoundarySpeciesAmountCodeGen(
                context).createFunction();

        rc->setBoundarySpeciesConcentrationPtr =
                SetBoundarySpeciesConcentrationCodeGen(context).createFunction();

        rc->setFloatingSpeciesConcentrationPtr =
                SetFloatingSpeciesConcentrationCodeGen(context).createFunction();

        rc->setCompartmentVolumePtr =
                SetCompartmentVolumeCodeGen(context).createFunction();

        rc->setFloatingSpeciesAmountPtr = SetFloatingSpeciesAmountCodeGen(
                context).createFunction();

        rc->setGlobalParameterPtr =
                SetGlobalParameterCodeGen(context).createFunction();
    }


    // if anything up to this point throws an exception, thats OK, because
    // we have not allocated any memory yet that is not taken care of by
    // something else.
    // Now that everything that could have thrown would have thrown, we
    // can now create the model and set its fields.

    // * MOVE * the bits over from the context to the exe model.
    context.stealThePeach(&rc->symbols, &rc->context,
            &rc->executionEngine, &rc->errStr);

    if (!forceReCompile)
    {
        // check for a chached copy, another thread could have
        // created one while we were making ours...

        ModelPtrMap::const_iterator i;

        SharedModelPtr sp;

        cachedModelsMutex.lock();

        // whilst we have it locked, clear any expired ptrs
        for (ModelPtrMap::const_iterator j = cachedModels.begin();
                j != cachedModels.end();)
        {
            if (j->second.expired())
            {
                Log(Logger::PRIO_INFORMATION) <<
                        "removing expired model resource for hash " << md5;

                j = cachedModels.erase(j);
            }
            else
            {
                ++j;
            }
        }

        if ((i = cachedModels.find(md5)) == cachedModels.end())
        {
            Log(Logger::PRIO_INFORMATION) << "could not find existing cached resource "
                    "resources, for hash " << md5 <<
                    ", inserting new resources into cache";

            cachedModels[md5] = rc;
        }

        cachedModelsMutex.unlock();
    }

    return new LLVMExecutableModel(rc);
}

Compiler* LLVMModelGenerator::getCompiler()
{
    return &compiler;
}

bool LLVMModelGenerator::setCompiler(const string& compiler)
{
    return true;
}

/************ LLVM Utility Functions, TODO: Move To Separate File ************/

/**
 * C++ 11 style to_string for LLVM types
 */
std::string to_string(const llvm::Value *value)
{
    std::string str;
    llvm::raw_string_ostream stream(str);
    value->print(stream);
    return str;
}

} /* namespace rr */
Exemplo n.º 2
0
ExecutableModel* LLVMModelGenerator::createModel(const std::string& sbml,
        uint options)
{
    bool forceReCompile = options & LoadSBMLOptions::RECOMPILE;

    string md5;

    if (!forceReCompile)
    {
        // check for a chached copy
        md5 = rr::getMD5(sbml);

        if (options & LoadSBMLOptions::CONSERVED_MOIETIES)
        {
            md5 += "_conserved";
        }

        ModelPtrMap::const_iterator i;

        SharedModelPtr sp;

        cachedModelsMutex.lock();

        if ((i = cachedModels.find(md5)) != cachedModels.end())
        {
            sp = i->second.lock();
        }

        cachedModelsMutex.unlock();

        // we could have recieved a bad ptr, a model could have been deleted,
        // in which case, we should have a bad ptr.

        if (sp)
        {
            Log(Logger::LOG_DEBUG) << "found a cached model for " << md5;
            return new LLVMExecutableModel(sp, createModelData(*sp->symbols, sp->random));
        }
        else
        {
            Log(Logger::LOG_TRACE) << "no cached model found for " << md5
                    << ", creating new one";
        }
    }

    SharedModelPtr rc(new ModelResources());

    ModelGeneratorContext context(sbml, options);

    rc->evalInitialConditionsPtr =
            EvalInitialConditionsCodeGen(context).createFunction();

    rc->evalReactionRatesPtr =
            EvalReactionRatesCodeGen(context).createFunction();

    rc->getBoundarySpeciesAmountPtr =
            GetBoundarySpeciesAmountCodeGen(context).createFunction();

    rc->getFloatingSpeciesAmountPtr =
            GetFloatingSpeciesAmountCodeGen(context).createFunction();

    rc->getBoundarySpeciesConcentrationPtr =
            GetBoundarySpeciesConcentrationCodeGen(context).createFunction();

    rc->getFloatingSpeciesConcentrationPtr =
            GetFloatingSpeciesConcentrationCodeGen(context).createFunction();

    rc->getCompartmentVolumePtr =
            GetCompartmentVolumeCodeGen(context).createFunction();

    rc->getGlobalParameterPtr =
            GetGlobalParameterCodeGen(context).createFunction();

    rc->evalRateRuleRatesPtr =
            EvalRateRuleRatesCodeGen(context).createFunction();

    rc->getEventTriggerPtr =
            GetEventTriggerCodeGen(context).createFunction();

    rc->getEventPriorityPtr =
            GetEventPriorityCodeGen(context).createFunction();

    rc->getEventDelayPtr =
            GetEventDelayCodeGen(context).createFunction();

    rc->eventTriggerPtr =
            EventTriggerCodeGen(context).createFunction();

    rc->eventAssignPtr =
            EventAssignCodeGen(context).createFunction();

    rc->evalVolatileStoichPtr =
            EvalVolatileStoichCodeGen(context).createFunction();

    rc->evalConversionFactorPtr =
            EvalConversionFactorCodeGen(context).createFunction();

    if (options & LoadSBMLOptions::READ_ONLY)
    {
        rc->setBoundarySpeciesAmountPtr = 0;
        rc->setBoundarySpeciesConcentrationPtr = 0;
        rc->setFloatingSpeciesConcentrationPtr = 0;
        rc->setCompartmentVolumePtr = 0;
        rc->setFloatingSpeciesAmountPtr = 0;
        rc->setGlobalParameterPtr = 0;
    }
    else
    {
        rc->setBoundarySpeciesAmountPtr = SetBoundarySpeciesAmountCodeGen(
                context).createFunction();

        rc->setBoundarySpeciesConcentrationPtr =
                SetBoundarySpeciesConcentrationCodeGen(context).createFunction();

        rc->setFloatingSpeciesConcentrationPtr =
                SetFloatingSpeciesConcentrationCodeGen(context).createFunction();

        rc->setCompartmentVolumePtr =
                SetCompartmentVolumeCodeGen(context).createFunction();

        rc->setFloatingSpeciesAmountPtr = SetFloatingSpeciesAmountCodeGen(
                context).createFunction();

        rc->setGlobalParameterPtr =
                SetGlobalParameterCodeGen(context).createFunction();
    }

    if (options & LoadSBMLOptions::MUTABLE_INITIAL_CONDITIONS)
    {
        rc->getFloatingSpeciesInitConcentrationsPtr =
                GetFloatingSpeciesInitConcentrationCodeGen(context).createFunction();
        rc->setFloatingSpeciesInitConcentrationsPtr =
                SetFloatingSpeciesInitConcentrationCodeGen(context).createFunction();

        rc->getFloatingSpeciesInitAmountsPtr =
                GetFloatingSpeciesInitAmountCodeGen(context).createFunction();
        rc->setFloatingSpeciesInitAmountsPtr =
                SetFloatingSpeciesInitAmountCodeGen(context).createFunction();

        rc->getCompartmentInitVolumesPtr =
                GetCompartmentInitVolumeCodeGen(context).createFunction();
        rc->setCompartmentInitVolumesPtr =
                SetCompartmentInitVolumeCodeGen(context).createFunction();

        rc->getGlobalParameterInitValuePtr =
                GetGlobalParameterInitValueCodeGen(context).createFunction();
        rc->setGlobalParameterInitValuePtr =
                SetGlobalParameterInitValueCodeGen(context).createFunction();
    }
    else
    {
        rc->getFloatingSpeciesInitConcentrationsPtr = 0;
        rc->setFloatingSpeciesInitConcentrationsPtr = 0;

        rc->getFloatingSpeciesInitAmountsPtr = 0;
        rc->setFloatingSpeciesInitAmountsPtr = 0;

        rc->getCompartmentInitVolumesPtr = 0;
        rc->setCompartmentInitVolumesPtr = 0;

        rc->getGlobalParameterInitValuePtr = 0;
        rc->setGlobalParameterInitValuePtr = 0;
    }


    // if anything up to this point throws an exception, thats OK, because
    // we have not allocated any memory yet that is not taken care of by
    // something else.
    // Now that everything that could have thrown would have thrown, we
    // can now create the model and set its fields.

    LLVMModelData *modelData = createModelData(context.getModelDataSymbols(),
            context.getRandom());

    uint llvmsize = ModelDataIRBuilder::getModelDataSize(context.getModule(),
            &context.getExecutionEngine());

    if (llvmsize != modelData->size)
    {
        std::stringstream s;

        s << "LLVM Model Data size " << llvmsize << " is different from " <<
                "C++ size of LLVM ModelData, " << modelData->size;

        LLVMModelData_free(modelData);

        Log(Logger::LOG_FATAL) << s.str();

        throw_llvm_exception(s.str());
    }

    // * MOVE * the bits over from the context to the exe model.
    context.stealThePeach(&rc->symbols, &rc->context,
            &rc->executionEngine, &rc->random, &rc->errStr);


    if (!forceReCompile)
    {
        // check for a chached copy, another thread could have
        // created one while we were making ours...

        ModelPtrMap::const_iterator i;

        SharedModelPtr sp;

        cachedModelsMutex.lock();

        // whilst we have it locked, clear any expired ptrs
        for (ModelPtrMap::const_iterator j = cachedModels.begin();
                j != cachedModels.end();)
        {
            if (j->second.expired())
            {
                Log(Logger::LOG_DEBUG) <<
                        "removing expired model resource for hash " << md5;

                j = cachedModels.erase(j);
            }
            else
            {
                ++j;
            }
        }

        if ((i = cachedModels.find(md5)) == cachedModels.end())
        {
            Log(Logger::LOG_DEBUG) << "could not find existing cached resource "
                    "resources, for hash " << md5 <<
                    ", inserting new resources into cache";

            cachedModels[md5] = rc;
        }

        cachedModelsMutex.unlock();
    }

    return new LLVMExecutableModel(rc, modelData);
}
ExecutableModel* LLVMModelGenerator::createModel(const std::string& sbml,
        uint options)
{
    bool computeAndAssignConsevationLaws =
            options & ModelGenerator::ComputeAndAssignConsevationLaws;

    bool forceReCompile = options & ModelGenerator::ForceReCompile;

    string md5;

    if (!forceReCompile)
    {
        // check for a chached copy
        md5 = rr::getMD5(sbml);

        ModelPtrMap::const_iterator i;

        SharedModelPtr sp;

        cachedModelsMutex.lock();

        if ((i = cachedModels.find(md5)) != cachedModels.end())
        {
            sp = i->second.lock();
        }

        cachedModelsMutex.unlock();

        // we could have recieved a bad ptr, a model could have been deleted,
        // in which case, we should have a bad ptr.

        if (sp)
        {
            Log(Logger::PRIO_DEBUG) << "found a cached model for " << md5;
            return new LLVMExecutableModel(sp);
        }
        else
        {
            Log(Logger::PRIO_TRACE) << "no cached model found for " << md5
                    << ", creating new one";
        }
    }

    SharedModelPtr rc(new ModelResources());

    ModelGeneratorContext context(sbml, computeAndAssignConsevationLaws);

    rc->evalInitialConditionsPtr =
            EvalInitialConditionsCodeGen(context).createFunction();

    rc->evalReactionRatesPtr =
            EvalReactionRatesCodeGen(context).createFunction();

    rc->getBoundarySpeciesAmountPtr =
            GetBoundarySpeciesAmountCodeGen(context).createFunction();

    rc->getFloatingSpeciesAmountPtr =
            GetFloatingSpeciesAmountCodeGen(context).createFunction();

    rc->getBoundarySpeciesConcentrationPtr =
            GetBoundarySpeciesConcentrationCodeGen(context).createFunction();

    rc->getFloatingSpeciesConcentrationPtr =
            GetFloatingSpeciesConcentrationCodeGen(context).createFunction();

    rc->getCompartmentVolumePtr =
            GetCompartmentVolumeCodeGen(context).createFunction();

    rc->getGlobalParameterPtr =
            GetGlobalParameterCodeGen(context).createFunction();

    rc->evalRateRuleRatesPtr =
            EvalRateRuleRatesCodeGen(context).createFunction();

    rc->getEventTriggerPtr =
            GetEventTriggerCodeGen(context).createFunction();

    rc->getEventPriorityPtr =
            GetEventPriorityCodeGen(context).createFunction();

    rc->getEventDelayPtr =
            GetEventDelayCodeGen(context).createFunction();

    rc->eventTriggerPtr =
            EventTriggerCodeGen(context).createFunction();

    rc->eventAssignPtr =
            EventAssignCodeGen(context).createFunction();

    rc->evalVolatileStoichPtr =
            EvalVolatileStoichCodeGen(context).createFunction();

    rc->evalConversionFactorPtr =
            EvalConversionFactorCodeGen(context).createFunction();

    if (options & ModelGenerator::ReadOnlyModel)
    {
        rc->setBoundarySpeciesAmountPtr = 0;
        rc->setBoundarySpeciesConcentrationPtr = 0;
        rc->setFloatingSpeciesConcentrationPtr = 0;
        rc->setCompartmentVolumePtr = 0;
        rc->setFloatingSpeciesAmountPtr = 0;
        rc->setGlobalParameterPtr = 0;
    }
    else
    {
        rc->setBoundarySpeciesAmountPtr = SetBoundarySpeciesAmountCodeGen(
                context).createFunction();

        rc->setBoundarySpeciesConcentrationPtr =
                SetBoundarySpeciesConcentrationCodeGen(context).createFunction();

        rc->setFloatingSpeciesConcentrationPtr =
                SetFloatingSpeciesConcentrationCodeGen(context).createFunction();

        rc->setCompartmentVolumePtr =
                SetCompartmentVolumeCodeGen(context).createFunction();

        rc->setFloatingSpeciesAmountPtr = SetFloatingSpeciesAmountCodeGen(
                context).createFunction();

        rc->setGlobalParameterPtr =
                SetGlobalParameterCodeGen(context).createFunction();
    }


    // if anything up to this point throws an exception, thats OK, because
    // we have not allocated any memory yet that is not taken care of by
    // something else.
    // Now that everything that could have thrown would have thrown, we
    // can now create the model and set its fields.

    // * MOVE * the bits over from the context to the exe model.
    context.stealThePeach(&rc->symbols, &rc->context,
            &rc->executionEngine, &rc->errStr);

    if (!forceReCompile)
    {
        // check for a chached copy, another thread could have
        // created one while we were making ours...

        ModelPtrMap::const_iterator i;

        SharedModelPtr sp;

        cachedModelsMutex.lock();

        // whilst we have it locked, clear any expired ptrs
        for (ModelPtrMap::const_iterator j = cachedModels.begin();
                j != cachedModels.end();)
        {
            if (j->second.expired())
            {
                Log(Logger::PRIO_INFORMATION) <<
                        "removing expired model resource for hash " << md5;

                j = cachedModels.erase(j);
            }
            else
            {
                ++j;
            }
        }

        if ((i = cachedModels.find(md5)) == cachedModels.end())
        {
            Log(Logger::PRIO_INFORMATION) << "could not find existing cached resource "
                    "resources, for hash " << md5 <<
                    ", inserting new resources into cache";

            cachedModels[md5] = rc;
        }

        cachedModelsMutex.unlock();
    }

    return new LLVMExecutableModel(rc);
}
Exemplo n.º 4
0
namespace rrllvm
{

typedef cxx11_ns::weak_ptr<ModelResources> WeakModelPtr;
typedef cxx11_ns::shared_ptr<ModelResources> SharedModelPtr;
typedef cxx11_ns::unordered_map<std::string, WeakModelPtr> ModelPtrMap;

static Poco::Mutex cachedModelsMutex;
static ModelPtrMap cachedModels;


/**
 * copy the cached model fields between a cached model, and a
 * executable model.
 *
 * We don't want to have ExecutableModel inherit from CahcedModel
 * because they do compleltly different things, and have completly
 * differnt deletion semantics
 */
template <typename a_type, typename b_type>
void copyCachedModel(a_type* src, b_type* dst)
{
    dst->symbols = src->symbols;
    dst->context = src->context;
    dst->executionEngine = src->executionEngine;
    dst->errStr = src->errStr;

    dst->evalInitialConditionsPtr = src->evalInitialConditionsPtr;
    dst->evalReactionRatesPtr = src->evalReactionRatesPtr;
    dst->getBoundarySpeciesAmountPtr = src->getBoundarySpeciesAmountPtr;
    dst->getFloatingSpeciesAmountPtr = src->getFloatingSpeciesAmountPtr;
    dst->getBoundarySpeciesConcentrationPtr = src->getBoundarySpeciesConcentrationPtr;
    dst->getFloatingSpeciesConcentrationPtr = src->getFloatingSpeciesConcentrationPtr;
    dst->getCompartmentVolumePtr = src->getCompartmentVolumePtr;
    dst->getGlobalParameterPtr = src->getGlobalParameterPtr;
    dst->evalRateRuleRatesPtr = src->evalRateRuleRatesPtr;
    dst->getEventTriggerPtr = src->getEventTriggerPtr;
    dst->getEventPriorityPtr = src->getEventPriorityPtr;
    dst->getEventDelayPtr = src->getEventDelayPtr;
    dst->eventTriggerPtr = src->eventTriggerPtr;
    dst->eventAssignPtr = src->eventAssignPtr;
    dst->evalVolatileStoichPtr = src->evalVolatileStoichPtr;
    dst->evalConversionFactorPtr = src->evalConversionFactorPtr;
}


ExecutableModel* LLVMModelGenerator::createModel(const std::string& sbml,
        uint options)
{
    bool forceReCompile = options & LoadSBMLOptions::RECOMPILE;

    string md5;

    if (!forceReCompile)
    {
        // check for a chached copy
        md5 = rr::getMD5(sbml);

        if (options & LoadSBMLOptions::CONSERVED_MOIETIES)
        {
            md5 += "_conserved";
        }

        ModelPtrMap::const_iterator i;

        SharedModelPtr sp;

        cachedModelsMutex.lock();

        if ((i = cachedModels.find(md5)) != cachedModels.end())
        {
            sp = i->second.lock();
        }

        cachedModelsMutex.unlock();

        // we could have recieved a bad ptr, a model could have been deleted,
        // in which case, we should have a bad ptr.

        if (sp)
        {
            Log(Logger::LOG_DEBUG) << "found a cached model for " << md5;
            return new LLVMExecutableModel(sp, createModelData(*sp->symbols, sp->random));
        }
        else
        {
            Log(Logger::LOG_TRACE) << "no cached model found for " << md5
                    << ", creating new one";
        }
    }

    SharedModelPtr rc(new ModelResources());

    ModelGeneratorContext context(sbml, options);

    rc->evalInitialConditionsPtr =
            EvalInitialConditionsCodeGen(context).createFunction();

    rc->evalReactionRatesPtr =
            EvalReactionRatesCodeGen(context).createFunction();

    rc->getBoundarySpeciesAmountPtr =
            GetBoundarySpeciesAmountCodeGen(context).createFunction();

    rc->getFloatingSpeciesAmountPtr =
            GetFloatingSpeciesAmountCodeGen(context).createFunction();

    rc->getBoundarySpeciesConcentrationPtr =
            GetBoundarySpeciesConcentrationCodeGen(context).createFunction();

    rc->getFloatingSpeciesConcentrationPtr =
            GetFloatingSpeciesConcentrationCodeGen(context).createFunction();

    rc->getCompartmentVolumePtr =
            GetCompartmentVolumeCodeGen(context).createFunction();

    rc->getGlobalParameterPtr =
            GetGlobalParameterCodeGen(context).createFunction();

    rc->evalRateRuleRatesPtr =
            EvalRateRuleRatesCodeGen(context).createFunction();

    rc->getEventTriggerPtr =
            GetEventTriggerCodeGen(context).createFunction();

    rc->getEventPriorityPtr =
            GetEventPriorityCodeGen(context).createFunction();

    rc->getEventDelayPtr =
            GetEventDelayCodeGen(context).createFunction();

    rc->eventTriggerPtr =
            EventTriggerCodeGen(context).createFunction();

    rc->eventAssignPtr =
            EventAssignCodeGen(context).createFunction();

    rc->evalVolatileStoichPtr =
            EvalVolatileStoichCodeGen(context).createFunction();

    rc->evalConversionFactorPtr =
            EvalConversionFactorCodeGen(context).createFunction();

    if (options & LoadSBMLOptions::READ_ONLY)
    {
        rc->setBoundarySpeciesAmountPtr = 0;
        rc->setBoundarySpeciesConcentrationPtr = 0;
        rc->setFloatingSpeciesConcentrationPtr = 0;
        rc->setCompartmentVolumePtr = 0;
        rc->setFloatingSpeciesAmountPtr = 0;
        rc->setGlobalParameterPtr = 0;
    }
    else
    {
        rc->setBoundarySpeciesAmountPtr = SetBoundarySpeciesAmountCodeGen(
                context).createFunction();

        rc->setBoundarySpeciesConcentrationPtr =
                SetBoundarySpeciesConcentrationCodeGen(context).createFunction();

        rc->setFloatingSpeciesConcentrationPtr =
                SetFloatingSpeciesConcentrationCodeGen(context).createFunction();

        rc->setCompartmentVolumePtr =
                SetCompartmentVolumeCodeGen(context).createFunction();

        rc->setFloatingSpeciesAmountPtr = SetFloatingSpeciesAmountCodeGen(
                context).createFunction();

        rc->setGlobalParameterPtr =
                SetGlobalParameterCodeGen(context).createFunction();
    }

    if (options & LoadSBMLOptions::MUTABLE_INITIAL_CONDITIONS)
    {
        rc->getFloatingSpeciesInitConcentrationsPtr =
                GetFloatingSpeciesInitConcentrationCodeGen(context).createFunction();
        rc->setFloatingSpeciesInitConcentrationsPtr =
                SetFloatingSpeciesInitConcentrationCodeGen(context).createFunction();

        rc->getFloatingSpeciesInitAmountsPtr =
                GetFloatingSpeciesInitAmountCodeGen(context).createFunction();
        rc->setFloatingSpeciesInitAmountsPtr =
                SetFloatingSpeciesInitAmountCodeGen(context).createFunction();

        rc->getCompartmentInitVolumesPtr =
                GetCompartmentInitVolumeCodeGen(context).createFunction();
        rc->setCompartmentInitVolumesPtr =
                SetCompartmentInitVolumeCodeGen(context).createFunction();

        rc->getGlobalParameterInitValuePtr =
                GetGlobalParameterInitValueCodeGen(context).createFunction();
        rc->setGlobalParameterInitValuePtr =
                SetGlobalParameterInitValueCodeGen(context).createFunction();
    }
    else
    {
        rc->getFloatingSpeciesInitConcentrationsPtr = 0;
        rc->setFloatingSpeciesInitConcentrationsPtr = 0;

        rc->getFloatingSpeciesInitAmountsPtr = 0;
        rc->setFloatingSpeciesInitAmountsPtr = 0;

        rc->getCompartmentInitVolumesPtr = 0;
        rc->setCompartmentInitVolumesPtr = 0;

        rc->getGlobalParameterInitValuePtr = 0;
        rc->setGlobalParameterInitValuePtr = 0;
    }


    // if anything up to this point throws an exception, thats OK, because
    // we have not allocated any memory yet that is not taken care of by
    // something else.
    // Now that everything that could have thrown would have thrown, we
    // can now create the model and set its fields.

    LLVMModelData *modelData = createModelData(context.getModelDataSymbols(),
            context.getRandom());

    uint llvmsize = ModelDataIRBuilder::getModelDataSize(context.getModule(),
            &context.getExecutionEngine());

    if (llvmsize != modelData->size)
    {
        std::stringstream s;

        s << "LLVM Model Data size " << llvmsize << " is different from " <<
                "C++ size of LLVM ModelData, " << modelData->size;

        LLVMModelData_free(modelData);

        Log(Logger::LOG_FATAL) << s.str();

        throw_llvm_exception(s.str());
    }

    // * MOVE * the bits over from the context to the exe model.
    context.stealThePeach(&rc->symbols, &rc->context,
            &rc->executionEngine, &rc->random, &rc->errStr);


    if (!forceReCompile)
    {
        // check for a chached copy, another thread could have
        // created one while we were making ours...

        ModelPtrMap::const_iterator i;

        SharedModelPtr sp;

        cachedModelsMutex.lock();

        // whilst we have it locked, clear any expired ptrs
        for (ModelPtrMap::const_iterator j = cachedModels.begin();
                j != cachedModels.end();)
        {
            if (j->second.expired())
            {
                Log(Logger::LOG_DEBUG) <<
                        "removing expired model resource for hash " << md5;

                j = cachedModels.erase(j);
            }
            else
            {
                ++j;
            }
        }

        if ((i = cachedModels.find(md5)) == cachedModels.end())
        {
            Log(Logger::LOG_DEBUG) << "could not find existing cached resource "
                    "resources, for hash " << md5 <<
                    ", inserting new resources into cache";

            cachedModels[md5] = rc;
        }

        cachedModelsMutex.unlock();
    }

    return new LLVMExecutableModel(rc, modelData);
}



/************ LLVM Utility Functions, TODO: Move To Separate File ************/

/**
 * C++ 11 style to_string for LLVM types
 */
std::string to_string(const llvm::Value *value)
{
    std::string str;
    llvm::raw_string_ostream stream(str);
    value->print(stream);
    return str;
}

LLVMModelData *createModelData(const rrllvm::LLVMModelDataSymbols &symbols,
        const Random *random)
{
    uint modelDataBaseSize = sizeof(LLVMModelData);

    uint numIndCompartments = symbols.getIndependentCompartmentSize();
    uint numIndFloatingSpecies = symbols.getIndependentFloatingSpeciesSize();
    uint numIndBoundarySpecies = symbols.getIndependentBoundarySpeciesSize();
    uint numIndGlobalParameters = symbols.getIndependentGlobalParameterSize();

    uint numInitCompartments = symbols.getInitCompartmentSize();
    uint numInitFloatingSpecies = symbols.getInitFloatingSpeciesSize();
    uint numInitBoundarySpecies = symbols.getInitBoundarySpeciesSize();
    uint numInitGlobalParameters = symbols.getInitGlobalParameterSize();

    // no initial conditions for these
    uint numRateRules = symbols.getRateRuleSize();
    uint numReactions = symbols.getReactionSize();

    uint modelDataSize = modelDataBaseSize +
        sizeof(double) * (
            numIndCompartments +
            numInitCompartments +
            numInitFloatingSpecies +
            numIndBoundarySpecies +
            numInitBoundarySpecies +
            numIndGlobalParameters +
            numInitGlobalParameters +
            numReactions +
            numRateRules +
            numIndFloatingSpecies
            );

    LLVMModelData *modelData = (LLVMModelData*)calloc(
            modelDataSize, sizeof(unsigned char));

    modelData->size = modelDataSize;
    modelData->numIndCompartments = numIndCompartments;
    modelData->numIndFloatingSpecies = numIndFloatingSpecies;
    modelData->numIndBoundarySpecies = numIndBoundarySpecies;
    modelData->numIndGlobalParameters = numIndGlobalParameters;

    modelData->numInitCompartments = numInitCompartments;
    modelData->numInitFloatingSpecies = numInitFloatingSpecies;
    modelData->numInitBoundarySpecies = numInitBoundarySpecies;
    modelData->numInitBoundarySpecies = numInitGlobalParameters;

    modelData->numRateRules = numRateRules;
    modelData->numReactions = numReactions;
    modelData->numEvents = symbols.getEventAttributes().size();

    // set the aliases to the offsets
    uint offset = 0;

    modelData->compartmentVolumesAlias = &modelData->data[offset];
    offset += numIndCompartments;

    modelData->initCompartmentVolumesAlias = &modelData->data[offset];
    offset += numInitCompartments;

    modelData->initFloatingSpeciesAmountsAlias = &modelData->data[offset];
    offset += numInitFloatingSpecies;

    modelData->boundarySpeciesAmountsAlias = &modelData->data[offset];
    offset += numIndBoundarySpecies;

    modelData->initBoundarySpeciesAmountsAlias = &modelData->data[offset];
    offset += numInitBoundarySpecies;

    modelData->globalParametersAlias = &modelData->data[offset];
    offset += numIndGlobalParameters;

    modelData->initGlobalParametersAlias = &modelData->data[offset];
    offset += numInitGlobalParameters;

    modelData->reactionRatesAlias = &modelData->data[offset];
    offset += numReactions;

    modelData->rateRuleValuesAlias = &modelData->data[offset];
    offset += numRateRules;

    modelData->floatingSpeciesAmountsAlias = &modelData->data[offset];
    offset += numIndFloatingSpecies;

    assert (modelDataBaseSize + offset * sizeof(double) == modelDataSize  &&
            "LLVMModelData size not equal to base size + data");

    // allocate the stoichiometry matrix
    const std::vector<uint> &stoichRowIndx = symbols.getStoichRowIndx();
    const std::vector<uint> &stoichColIndx = symbols.getStoichColIndx();
    std::vector<double> stoichValues(stoichRowIndx.size(), 0);

    modelData->stoichiometry = rr::csr_matrix_new(numIndFloatingSpecies, numReactions,
            stoichRowIndx, stoichColIndx, stoichValues);

    // make a copy of the random object
    modelData->random = random ? new Random(*random) : 0;

    return modelData;
}

} /* namespace rrllvm */