Source code for daetools.code_generators.cxx_mpi

"""
***********************************************************************************
                            cxx_mpi.py
                DAE Tools: pyDAE module, www.daetools.com
                Copyright (C) Dragan Nikolic
***********************************************************************************
DAE Tools is free software; you can redistribute it and/or modify it under the
terms of the GNU General Public License version 3 as published by the Free Software
Foundation. DAE Tools 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 the
DAE Tools software; if not, see <http://www.gnu.org/licenses/>.
************************************************************************************
"""
import os, shutil, sys, numpy, math, traceback, pprint
from daetools.pyDAE import *
from .formatter import daeExpressionFormatter
from .analyzer import daeCodeGeneratorAnalyzer
from .code_generator import daeCodeGenerator

class daeExpressionFormatter_cxx_mpi(daeExpressionFormatter):
    def __init__(self):
        daeExpressionFormatter.__init__(self)
        self.indexBase                              = 0
        self.useFlattenedNamesForAssignedVariables  = True
        self.IDs                                    = {}
        self.indexMap                               = {}

        # Use relative names
        self.useRelativeNames         = True
        self.flattenIdentifiers       = True

        self.domain                   = 'adouble(_m_->{domain}[{index}])'

        self.parameter                = 'adouble(_m_->{parameter}{indexes})'
        self.parameterIndexStart      = '['
        self.parameterIndexEnd        = ']'
        self.parameterIndexDelimiter  = ']['

        self.variable                 = '_v_({blockIndex})'
        self.variableIndexStart       = ''
        self.variableIndexEnd         = ''
        self.variableIndexDelimiter   = ''

        self.assignedVariable         = 'adouble(_m_->{variable})'
        
        self.feMatrixItem             = 'adouble({value})'
        self.feVectorItem             = 'adouble({value})'

        self.derivative               = '_dv_({blockIndex})'
        self.derivativeIndexStart     = ''
        self.derivativeIndexEnd       = ''
        self.derivativeIndexDelimiter = ''

        # Constants
        self.constant = 'adouble({value})'
        
        # External functions
        self.scalarExternalFunction = 'modCalculateScalarExtFunction("{name}", _m_, _current_time_, _values_, _time_derivatives_)'
        self.vectorExternalFunction = 'adouble(0.0, 0.0)'

        # Logical operators
        self.AND   = '({leftValue} && {rightValue})'
        self.OR    = '({leftValue} || {rightValue})'
        self.NOT   = '(! {value})'

        self.EQ    = '({leftValue} == {rightValue})'
        self.NEQ   = '({leftValue} != {rightValue})'
        self.LT    = '({leftValue} < {rightValue})'
        self.LTEQ  = '({leftValue} <= {rightValue})'
        self.GT    = '({leftValue} > {rightValue})'
        self.GTEQ  = '({leftValue} >= {rightValue})'

        # Mathematical operators
        self.SIGN   = '(-{value})'

        self.PLUS   = '({leftValue} + {rightValue})'
        self.MINUS  = '({leftValue} - {rightValue})'
        self.MULTI  = '({leftValue} * {rightValue})'
        self.DIVIDE = '({leftValue} / {rightValue})'
        self.POWER  = '({leftValue} ^ {rightValue})'

        # Mathematical functions
        self.SIN    = 'sin_({value})'
        self.COS    = 'cos_({value})'
        self.TAN    = 'tan_({value})'
        self.ASIN   = 'asin_({value})'
        self.ACOS   = 'acos_({value})'
        self.ATAN   = 'atan_({value})'
        self.EXP    = 'exp_({value})'
        self.SQRT   = 'sqrt_({value})'
        self.LOG    = 'log_({value})'
        self.LOG10  = 'log10_({value})'
        self.FLOOR  = 'floor_({value})'
        self.CEIL   = 'ceil_({value})'
        self.ABS    = 'abs_({value})'
        self.SINH   = 'sinh_({value})'
        self.COSH   = 'cosh_({value})'
        self.TANH   = 'tanh_({value})'
        self.ASINH  = 'asinh_({value})'
        self.ACOSH  = 'acosh_({value})'
        self.ATANH  = 'atanh_({value})'
        self.ERF    = 'erf_({value})'

        self.MIN     = 'min_({leftValue}, {rightValue})'
        self.MAX     = 'max_({leftValue}, {rightValue})'
        self.ARCTAN2 = 'atan2_({leftValue}, {rightValue})'

        # Current time in simulation
        self.TIME   = '_time_'

    def formatNumpyArray(self, arr):
        if isinstance(arr, (numpy.ndarray, list)):
            return '{' + ', '.join([self.formatNumpyArray(val) for val in arr]) + '}'
        else:
            return str(arr)

    def formatQuantity(self, quantity):
        # Formats constants/quantities in equations that have a value and units
        return str(quantity.value)
     
[docs]class daeCodeGenerator_cxx_mpi(daeCodeGenerator): def __init__(self): self.wrapperInstanceName = '' self.defaultIndent = ' ' self.warnings = [] self.topLevelModel = None self.simulation = None self.equationGenerationMode = '' self.assignedVariablesDefs = [] self.assignedVariablesInits = [] self.initialConditions = [] self.stnDefs = [] self.initiallyActiveStates = [] self.runtimeInformation_h = [] self.runtimeInformation_init = [] self.parametersDefs = [] self.parametersInits = [] self.intValuesReferences = [] self.floatValuesReferences = [] self.stringValuesReferences = [] self.residuals = [] self.jacobians = [] self.checkForDiscontinuities = [] self.executeActions = [] self.numberOfRoots = [] self.rootFunctions = [] self.variableNames = [] self.fmiInterface = [] self.exprFormatter = daeExpressionFormatter_cxx_mpi() self.analyzer = daeCodeGeneratorAnalyzer() # MPI self.Nnodes = 0 self.Neq_per_node = 0 self.mpi_synchronise = '' self.mpi_node_block_indexes_map = {}
[docs] def generateSimulation(self, simulation, directory, Nnodes): if not simulation: raise RuntimeError('Invalid simulation object') if not os.path.isdir(directory): os.makedirs(directory) self.assignedVariablesDefs = [] self.assignedVariablesInits = [] self.initialConditions = [] self.stnDefs = [] self.initiallyActiveStates = [] self.runtimeInformation_h = [] self.runtimeInformation_init = [] self.parametersDefs = [] self.parametersInits = [] self.intValuesReferences = [] self.floatValuesReferences = [] self.stringValuesReferences = [] self.residuals = [] self.jacobians = [] self.checkForDiscontinuities = [] self.executeActions = [] self.numberOfRoots = [] self.rootFunctions = [] self.variableNames = [] self.warnings = [] self.simulation = simulation self.topLevelModel = simulation.m # Achtung, Achtung!! # wrapperInstanceName and exprFormatter.modelCanonicalName should not be stripped # of illegal characters, since they are used to get relative names self.wrapperInstanceName = simulation.m.Name self.exprFormatter.modelCanonicalName = simulation.m.Name indent = 1 s_indent = indent * self.defaultIndent self.analyzer.analyzeSimulation(simulation) self.exprFormatter.IDs = self.analyzer.runtimeInformation['IDs'] self.exprFormatter.indexMap = self.analyzer.runtimeInformation['IndexMappings'] #import pprint #pp = pprint.PrettyPrinter(indent=2) #pp.pprint(self.analyzer.runtimeInformation) # MPI self.mpi_synchronise = '' self.mpi_node_block_indexes_map = {} Neq = self.analyzer.runtimeInformation['NumberOfEquations'] self.Nnodes = Nnodes self.Neq_per_node = int(Neq / self.Nnodes) #+ 1 for node in range(self.Nnodes): i_start = self.Neq_per_node*node i_end = self.Neq_per_node*(node+1) if i_end > Neq: i_end = Neq # block indexes, owned block indexes range self.mpi_node_block_indexes_map[node] = (set(), (i_start, i_end)) self._generateRuntimeInformation(self.analyzer.runtimeInformation) # MPI self._generateMPICommunication() residuals = [] for node, residual in enumerate(self.residuals): if node == 0: residuals.append(s_indent + 'if(_m_->mpi_rank == %d)' % node) else: residuals.append(s_indent + 'else if(_m_->mpi_rank == %d)' % node) residuals.append(s_indent + '{') residuals.extend([s_indent+s for s in residual]) residuals.append(s_indent + '}') jacobians = [] for node, jacobian in enumerate(self.jacobians): if node == 0: jacobians.append(s_indent + 'if(_m_->mpi_rank == %d)' % node) else: jacobians.append(s_indent + 'else if(_m_->mpi_rank == %d)' % node) jacobians.append(s_indent + '{') jacobians.extend([s_indent+s for s in jacobian]) jacobians.append(s_indent + '}') nodesInitialConditions = {} for node in range(self.Nnodes): nodesInitialConditions[node] = [] for (bi, ic) in self.initialConditions: node = int(bi / self.Neq_per_node) nodesInitialConditions[node].append(ic) # Initial conditions initialConditions = [] if self.Nnodes == 1: for node, ics in nodesInitialConditions.items(): if node == 0: initialConditions.append('if(_m_->mpi_rank == %d)' % node) else: initialConditions.append('else if(_m_->mpi_rank == %d)' % node) initialConditions.append('{') initialConditions.extend([s_indent+ic for ic in ics]) initialConditions.append('}') rtInformation_h = self.runtimeInformation_h rtInformation_init= '\n '.join(self.runtimeInformation_init) paramsDef = '\n '.join(self.parametersDefs) paramsInits = '\n '.join(self.parametersInits) stnDef = '\n '.join(self.stnDefs) stnActiveStates = '\n '.join(self.initiallyActiveStates) assignedVarsDefs = '\n '.join(self.assignedVariablesDefs) assignedVarsInits = '\n '.join(self.assignedVariablesInits) initConds = '\n '.join(initialConditions) eqnsRes = '\n'.join(residuals) jacobRes = '\n'.join(jacobians) rootsDef = '\n'.join(self.rootFunctions) checkDiscont = '\n'.join(self.checkForDiscontinuities) execActionsDef = '\n'.join(self.executeActions) noRootsDef = '\n'.join(self.numberOfRoots) warnings = '\n'.join(self.warnings) # MPI mpi_synchronise = self.mpi_synchronise # Values' references intValuesReferences_Def = '' intValuesReferences_Init = '' floatValuesReferences_Def = '' floatValuesReferences_Init = '' stringValuesReferences_Def = '' stringValuesReferences_Init = '' if self.Nnodes == 1: # intValuesReferences if len(self.intValuesReferences) > 0: intValuesReferences_Def = 'int* intValuesReferences[{0}];'.format(len(self.intValuesReferences)) else: intValuesReferences_Def = 'int* intValuesReferences[1]; /* Array is empty but we need its declaration */' valRefInit = [] for i, (ref_type, ref_name, ref_flat_name, block_index) in enumerate(self.intValuesReferences): if ref_type == 'NumberOfPointsInDomain': init = '_m_->intValuesReferences[{0}] = &_m_->{1};'.format(i, ref_flat_name) else: raise RuntimeError('Invalid integer variable reference type') valRefInit.append(init) intValuesReferences_Init = '\n '.join(valRefInit) # floatValuesReferences if len(self.floatValuesReferences) > 0: floatValuesReferences_Def = 'real_t* floatValuesReferences[{0}];'.format(len(self.floatValuesReferences)) else: floatValuesReferences_Def = 'real_t* floatValuesReferences[1]; /* Array is empty but we need its declaration */' # FMI: initialize value references tuple: (ref_type, name) valRefInit = [] for i, (ref_type, ref_name, ref_flat_name, block_index) in enumerate(self.floatValuesReferences): if ref_type == 'Assigned': init = '_m_->floatValuesReferences[{0}] = &_m_->{1};'.format(i, ref_flat_name) elif ref_type == 'Algebraic' or ref_type == 'Differential': init = '_m_->floatValuesReferences[{0}] = &_m_->values[{1}];'.format(i, block_index) elif ref_type == 'Differential': init = '_m_->floatValuesReferences[{0}] = &_m_->values[{1}];'.format(i, block_index) elif ref_type == 'Parameter': init = '_m_->floatValuesReferences[{0}] = &_m_->{1};'.format(i, ref_flat_name) #elif ref_type == 'NumberOfPointsInDomain': # init = '_m_->floatValuesReferences[{0}] = &_m_->{1};'.format(i, ref_flat_name) elif ref_type == 'DomainPoints': init = '_m_->floatValuesReferences[{0}] = &_m_->{1};'.format(i, ref_flat_name) else: raise RuntimeError('Invalid variable reference type (%s): %s' % (ref_type, ref_name)) valRefInit.append(init) floatValuesReferences_Init = '\n '.join(valRefInit) if len(self.stringValuesReferences) > 0: stringValuesReferences_Def = 'char* stringValuesReferences[{0}];'.format(len(self.stringValuesReferences)) else: stringValuesReferences_Def = 'char* stringValuesReferences[1]; /* Array is empty but we need its declaration */' valRefInit = [] stringValuesReferences_Init = '\n '.join(valRefInit) dictInfo = { 'runtimeInformation_init' : rtInformation_init, 'parameters' : paramsDef, 'parametersInits' : paramsInits, 'intValuesReferences_Init' : intValuesReferences_Init, 'intValuesReferences_Def' : intValuesReferences_Def, 'floatValuesReferences_Init' : floatValuesReferences_Init, 'floatValuesReferences_Def' : floatValuesReferences_Def, 'stringValuesReferences_Init' : stringValuesReferences_Init, 'stringValuesReferences_Def' : stringValuesReferences_Def, 'stns' : stnDef, 'stnActiveStates' : stnActiveStates, 'assignedVariablesDefs' : assignedVarsDefs, 'assignedVariablesInits' : assignedVarsInits, 'initialConditions' : initConds, 'residuals' : eqnsRes, 'jacobian' : jacobRes, 'roots' : rootsDef, 'numberOfRoots' : noRootsDef, 'checkForDiscontinuities' : checkDiscont, 'executeActions' : execActionsDef, 'warnings' : warnings } cxx_dir = os.path.join(os.path.dirname(__file__), 'cxx') f = open(os.path.join(cxx_dir, 'model.h'), "r") daetools_model_h_templ = f.read() f.close() f = open(os.path.join(cxx_dir, 'model-mpi.cpp'), "r") daetools_model_c_templ = f.read() f.close() f = open(os.path.join(cxx_dir, 'mpi_sync.h'), "r") daetools_mpi_sync_templ = f.read() f.close() f = open(os.path.join(cxx_dir, 'runtime_information.h'), "r") daetools_runtime_h_templ = f.read() f.close() daetools_model_h_contents = daetools_model_h_templ % dictInfo; daetools_model_c_contents = daetools_model_c_templ % dictInfo; daetools_mpi_sync_h_contents = daetools_mpi_sync_templ % {'mpi_synchronise_data' : mpi_synchronise}; daetools_runtime_h_contents = daetools_runtime_h_templ % {'runtimeInformation_h' : rtInformation_h} path, dirName = os.path.split(directory) shutil.copy2(os.path.join(cxx_dir, 'main.cpp'), os.path.join(directory, 'main.cpp')) shutil.copy2(os.path.join(cxx_dir, 'adouble.h'), os.path.join(directory, 'adouble.h')) shutil.copy2(os.path.join(cxx_dir, 'adouble.cpp'), os.path.join(directory, 'adouble.cpp')) shutil.copy2(os.path.join(cxx_dir, 'typedefs.h'), os.path.join(directory, 'typedefs.h')) shutil.copy2(os.path.join(cxx_dir, 'daesolver.h'), os.path.join(directory, 'daesolver.h')) shutil.copy2(os.path.join(cxx_dir, 'daesolver-mpi.cpp'), os.path.join(directory, 'daesolver.cpp')) shutil.copy2(os.path.join(cxx_dir, 'simulation.h'), os.path.join(directory, 'simulation.h')) shutil.copy2(os.path.join(cxx_dir, 'simulation.cpp'), os.path.join(directory, 'simulation.cpp')) shutil.copy2(os.path.join(cxx_dir, 'auxiliary.h'), os.path.join(directory, 'auxiliary.h')) shutil.copy2(os.path.join(cxx_dir, 'auxiliary.cpp'), os.path.join(directory, 'auxiliary.cpp')) shutil.copy2(os.path.join(cxx_dir, 'Makefile-gcc'), os.path.join(directory, 'Makefile')) shutil.copy2(os.path.join(cxx_dir, 'vc++2008.vcproj'), os.path.join(directory, 'daetools-simulation.vcproj')) shutil.copy2(os.path.join(cxx_dir, 'qt_project.pro'), os.path.join(directory, 'daetools-simulation.pro')) f = open(os.path.join(directory, 'model.h'), "w") f.write(daetools_model_h_contents) f.close() f = open(os.path.join(directory, 'model.cpp'), "w") f.write(daetools_model_c_contents) f.close() f = open(os.path.join(directory, 'mpi_sync.h'), "w") f.write(daetools_mpi_sync_h_contents) f.close() f = open(os.path.join(directory, 'runtime_information.h'), "w") f.write(daetools_runtime_h_contents) f.close() if len(self.warnings) > 0: print('CODE GENERATOR WARNINGS:') print(warnings)
# MPI def _generateMPICommunication(self): pp = pprint.PrettyPrinter(indent=2) #pp.pprint(self.mpi_node_block_indexes_map) mpi_sync_map = {} for node_rank, node_data in self.mpi_node_block_indexes_map.items(): block_indexes = node_data[0] i_start = node_data[1][0] i_end = node_data[1][1] all_indexes = block_indexes # this is set! owned_indexes = [] foreign_indexes = [] bi_to_bi_local = {} to_send_indexes = {} to_receive_indexes = {} mpi_sync_map[node_rank] = { 'all_indexes' : all_indexes, 'i_start' : i_start, 'i_end' : i_end, 'owned_indexes' : owned_indexes, 'foreign_indexes' : foreign_indexes, 'bi_to_bi_local' : bi_to_bi_local, 'send_to' : to_send_indexes, 'receive_from' : to_receive_indexes} for bi in sorted(all_indexes): if bi >= i_start and bi < i_end: owned_indexes.append(bi) bi_to_bi_local[bi] = bi-i_start else: foreign_indexes.append(bi) bi_to_bi_local[bi] = (i_end-i_start) + len(foreign_indexes) - 1 #print bi_to_bi_local for node_rank, node_data in mpi_sync_map.items(): for bi in node_data['foreign_indexes']: owner_rank = int(bi / self.Neq_per_node) owner_map = mpi_sync_map[owner_rank]['send_to'] if node_rank in owner_map: owner_map[node_rank].append(bi) else: owner_map[node_rank] = [bi] this_map = mpi_sync_map[node_rank]['receive_from'] if owner_rank in this_map: this_map[owner_rank].append(bi) else: this_map[owner_rank] = [bi] foundMissing = False for ni, n_data in mpi_sync_map.items(): missing = [bi for bi in range(n_data['i_start'], n_data['i_end']) if not (bi in n_data['owned_indexes'])] if missing: print('Node [%d] does not contain indexes: %s' % (ni, missing)) foundMissing = True if foundMissing: raise RuntimeError('Missing block indexes found') """ Working printout!!! for ni, n_data in mpi_sync_map.items(): print('[Node %d]:' % ni) print(' index_range: [%d - %d)' % (n_data['i_start'], n_data['i_end'])) print(' all_indexes:') print(' %s' % sorted(n_data['all_indexes'])) print(' owned_indexes:') print(' %s' % n_data['owned_indexes']) print(' foreign_indexes:') print(' %s' % n_data['foreign_indexes']) print(' send_to:') for sti, st_data in n_data['send_to'].items(): print(' %d: %s' % (sti, st_data)) print(' receive_from:') for rfi, rf_data in n_data['receive_from'].items(): print(' %d: %s' % (rfi, rf_data)) """ mapTemplate = """const std::map<int, mpiIndexesData> mapIndexesData = { %(map_items)s }; """ mapTemplateData = """std::map<int, mpiValuesData> mapValuesData = { %(map_items)s }; """ itemsTemplate=""" { %(node_rank)d, { %(mpi_sync_node_data)s } }""" mpi_sync_node_tmpl = """ %(i_start)d, %(i_end)d, (vector<int>){%(foreign_indexes)s}, (map<int,int>){%(bi_to_bi_local)s}, (mpiSyncMap){ // send to %(send_to)s }, (mpiSyncMap){ // receive from %(receive_from)s } """ mpi_sync_node_data_tmpl = """ (mpiSyncValuesMap){ // send to %(send_to)s }, (mpiSyncValuesMap){ // receive from %(receive_from)s } """ send_receive_tmpl = """{%(node)d, {%(indexes)s}}""" send_receive_data_tmpl = """{%(node)d, {{%(values)s}, {%(derivs)s}}}""" map_items = [] map_items_data = [] for ni, n_data in mpi_sync_map.items(): node_rank = ni i_start = n_data['i_start'] i_end = n_data['i_end'] # foreign_indexes_block are unmodified indexes in the range [0, Nequations) foreign_indexes = ', '.join([str(i) for i in n_data['foreign_indexes']]) bi_to_bi_local = ', '.join(['{%d,%d}'%(bi,bi_local) for bi,bi_local in n_data['bi_to_bi_local'].items()]) send_to_items = [] send_to_data_items = [] for st_node, st_data in n_data['send_to'].items(): indexes = ', '.join([str(i) for i in st_data]) values = ', '.join(['0' for i in st_data]) derivs = values send_to_items.append(send_receive_tmpl % {'node' : st_node, 'indexes' : indexes }) send_to_data_items.append(send_receive_data_tmpl % {'node' : st_node, 'values' : values, 'derivs' : derivs }) send_to = ',\n '.join(send_to_items) send_to_data = ',\n '.join(send_to_data_items) receive_from_items = [] receive_from_data_items = [] for rf_node, rf_data in n_data['receive_from'].items(): indexes = ', '.join([str(i) for i in rf_data]) values = ', '.join(['0' for i in rf_data]) derivs = values receive_from_items.append(send_receive_tmpl % {'node' : rf_node, 'indexes' : indexes }) receive_from_data_items.append(send_receive_data_tmpl % {'node' : rf_node, 'values' : values, 'derivs' : derivs }) receive_from = ',\n '.join(receive_from_items) receive_from_data = ',\n '.join(receive_from_data_items) mpi_sync_node = mpi_sync_node_tmpl % {'i_start' : i_start, 'i_end' : i_end, 'foreign_indexes' : foreign_indexes, 'bi_to_bi_local' : bi_to_bi_local, 'send_to' : send_to, 'receive_from' : receive_from} mpi_sync_node_data = mpi_sync_node_data_tmpl % {'send_to' : send_to_data, 'receive_from' : receive_from_data} map_items.append(itemsTemplate % {'node_rank' : ni, 'mpi_sync_node_data' : mpi_sync_node }) map_items_data.append(itemsTemplate % {'node_rank' : ni, 'mpi_sync_node_data' : mpi_sync_node_data }) s_indexes = mapTemplate % {'map_items' : ',\n'.join(map_items)} s_values = mapTemplateData % {'map_items' : ',\n'.join(map_items_data)} self.mpi_synchronise = s_indexes #+ '\n' + s_values def _processEquations(self, Equations, indent): s_indent = indent * self.defaultIndent s_indent2 = (indent+1) * self.defaultIndent map_oi_bi = self.exprFormatter.indexMap current_node = 0 node_eqn_counter = 0 if self.equationGenerationMode == 'residuals': current_node_residual = [] self.residuals.append(current_node_residual) for equation in Equations: for eeinfo in equation['EquationExecutionInfos']: # MPI overall_indexes = eeinfo['VariableIndexes'] n = len(overall_indexes) block_indexes = [] for oi in overall_indexes: bi = self.exprFormatter.indexBase + map_oi_bi[oi] block_indexes.append(bi) self.mpi_node_block_indexes_map[current_node][0].update(set(block_indexes)) res = self.exprFormatter.formatRuntimeNode(eeinfo['ResidualRuntimeNode']) current_node_residual.append(s_indent + '/* Equation type: ' + eeinfo['EquationType'] + ' */') current_node_residual.append(s_indent + '_temp_ = {0};'.format(res)) current_node_residual.append(s_indent + '_residuals_[_ec_++] = _temp_.getValue();') # MPI node_eqn_counter += 1 # Reset the counter if node_eqn_counter == self.Neq_per_node: current_node_residual = [] self.residuals.append(current_node_residual) current_node += 1 node_eqn_counter = 0 elif self.equationGenerationMode == 'jacobian': current_node_jacobian = [] self.jacobians.append(current_node_jacobian) for equation in Equations: for eeinfo in equation['EquationExecutionInfos']: overall_indexes = eeinfo['VariableIndexes'] n = len(overall_indexes) ID = node_eqn_counter #len(self.jacobians) block_indexes = [] for oi in overall_indexes: if oi in self.exprFormatter.indexMap: bi = self.exprFormatter.indexBase + self.exprFormatter.indexMap[oi] else: bi = -1 block_indexes.append(bi) str_indexes = self.exprFormatter.formatNumpyArray(block_indexes) current_node_jacobian.append(s_indent + 'int _block_indexes_{0}[{1}] = {2};'.format(ID, n, str_indexes)) current_node_jacobian.append(s_indent + 'for(_i_ = 0; _i_ < {0}; _i_++) {{'.format(n)) current_node_jacobian.append(s_indent2 + '_block_index_ = _block_indexes_{0}[_i_];'.format(ID)) current_node_jacobian.append(s_indent2 + 'if(_block_index_ < i_start_ || _block_index_ >= i_end_) // block index is out of the [i_start,i_end) range') current_node_jacobian.append(s_indent2 + ' continue;') current_node_jacobian.append(s_indent2 + '_block_index_local_ = _map_bi_to_bi_local_[_block_index_];'.format(ID)) current_node_jacobian.append(s_indent2 + '_current_index_for_jacobian_evaluation_ = _block_index_;') res = self.exprFormatter.formatRuntimeNode(eeinfo['ResidualRuntimeNode']) current_node_jacobian.append(s_indent2 + '_temp_ = {0};'.format(res)) current_node_jacobian.append(s_indent2 + '_jacobianItem_ = _temp_.getDerivative();') current_node_jacobian.append(s_indent2 + '_set_matrix_item_(_jacobian_matrix_, _ec_, _block_index_local_, _jacobianItem_);') current_node_jacobian.append(s_indent + '}') current_node_jacobian.append(s_indent + '_ec_++;') # MPI node_eqn_counter += 1 # Reset the counter if node_eqn_counter == self.Neq_per_node: current_node_jacobian = [] self.jacobians.append(current_node_jacobian) current_node += 1 node_eqn_counter = 0 def _processSTNs(self, STNs, indent): if len(STNs) > 0: raise RuntimeError('c++(MPI) code generator cannot handle models with state transition networks at the moment') s_indent = indent * self.defaultIndent for stn in STNs: if stn['Class'] == 'daeIF': relativeName = daeGetRelativeName(self.wrapperInstanceName, stn['CanonicalName']) relativeName = self.exprFormatter.formatIdentifier(relativeName) stnVariableName = self.exprFormatter.flattenIdentifier(relativeName) + '_ifstn' description = stn['Description'] states = ', '.join(st['Name'] for st in stn['States']) activeState = stn['ActiveState'] varTemplate = 'char* {name}; /* States: [{states}] ({description}) */' self.stnDefs.append(varTemplate.format(name = stnVariableName, states = states, description = description)) varTemplate = '_m_->{name} = "{activeState}";' self.initiallyActiveStates.append(varTemplate.format(name = stnVariableName, activeState = activeState)) nStates = len(stn['States']) for i, state in enumerate(stn['States']): # Not all states have state_transitions ('else' state has no state transitions) on_condition_action = None if i == 0: temp = s_indent + '/* IF {0} */'.format(stnVariableName) self.residuals.append(temp) self.jacobians.append(temp) self.checkForDiscontinuities.append(temp) self.executeActions.append(temp) self.numberOfRoots.append(temp) self.rootFunctions.append(temp) # There is only one OnConditionAction in IF on_condition_action = state['OnConditionActions'][0] condition = self.exprFormatter.formatRuntimeConditionNode(on_condition_action['ConditionRuntimeNode']) temp = s_indent + 'if(_compare_strings_(_m_->{0}, "{1}")) {{'.format(stnVariableName, state['Name']) self.residuals.append(temp) self.jacobians.append(temp) # We need to detect the number of roots and root functions for the current state of affairs, # that is active states after execute actions (or at the very beggining of a simulation). # Therefore, put those here and not below in the: if(condition) block. self.numberOfRoots.append(temp) self.rootFunctions.append(temp) temp = s_indent + 'if({0}) {{'.format(condition) self.checkForDiscontinuities.append(temp) self.executeActions.append(temp) elif (i > 0) and (i < nStates - 1): # There is only one OnConditionAction in ELSE_IFs on_condition_action = state['OnConditionActions'][0] condition = self.exprFormatter.formatRuntimeConditionNode(on_condition_action['ConditionRuntimeNode']) temp = s_indent + 'else if(_compare_strings_(_m_->{0}, "{1}")) {{'.format(stnVariableName, state['Name']) self.residuals.append(temp) self.jacobians.append(temp) # We need to detect the number of roots and root functions for the current state of affairs, # that is active states after execute actions (or at the very beggining of a simulation). # Therefore, put those here and not below in the: if(condition) block. self.numberOfRoots.append(temp) self.rootFunctions.append(temp) temp = s_indent + 'else if({0}) {{'.format(condition) self.checkForDiscontinuities.append(temp) self.executeActions.append(temp) else: temp = s_indent + 'else {' self.residuals.append(temp) self.jacobians.append(temp) self.checkForDiscontinuities.append(temp) self.executeActions.append(temp) # Here it does not matter self.numberOfRoots.append(temp) self.rootFunctions.append(temp) # 1a. Generate NestedSTNs self._processSTNs(state['NestedSTNs'], indent+1) # 1b. Put equations into the residuals list self.equationGenerationMode = 'residuals' self._processEquations(state['Equations'], indent+1) self.residuals.append(s_indent + '}') # 1c. Put equations into the jacobians list self.equationGenerationMode = 'jacobian' self._processEquations(state['Equations'], indent+1) self.jacobians.append(s_indent + '}') s_indent2 = (indent + 1) * self.defaultIndent s_indent3 = (indent + 2) * self.defaultIndent # 2. checkForDiscontinuities self.checkForDiscontinuities.append(s_indent2 + 'if(! _compare_strings_(_m_->{0}, "{1}")) {{'.format(stnVariableName, state['Name'])) self.checkForDiscontinuities.append(s_indent3 + 'foundDiscontinuity = true;') self.checkForDiscontinuities.append(s_indent2 + '}') self.checkForDiscontinuities.append(s_indent + '}') # 3. executeActions self.executeActions.append(s_indent2 + 'printf("The state [{0}] in the IF [{1}] is active now.\\n");'.format(state['Name'], relativeName)) self.executeActions.append(s_indent2 + '_m_->{0} = "{1}";'.format(stnVariableName, state['Name'])) self.executeActions.append(s_indent + '}') # 4. numberOfRoots if on_condition_action: # For 'else' state has no state transitions nExpr = len(on_condition_action['Expressions']) self.numberOfRoots.append(s_indent + '_noRoots_ += {0};'.format(nExpr)) self.numberOfRoots.append(s_indent + '}') # 5. rootFunctions if on_condition_action: # For 'else' state has no state transitions for expression in on_condition_action['Expressions']: self.rootFunctions.append(s_indent + '_temp_ = {0};'.format(self.exprFormatter.formatRuntimeNode(expression))) self.rootFunctions.append(s_indent + '_roots_[_rc_++] = _temp_.getValue();') self.rootFunctions.append(s_indent + '}') elif stn['Class'] == 'daeSTN': relativeName = daeGetRelativeName(self.wrapperInstanceName, stn['CanonicalName']) relativeName = self.exprFormatter.formatIdentifier(relativeName) stnVariableName = self.exprFormatter.flattenIdentifier(relativeName) + '_stn' description = stn['Description'] states = ', '.join(st['Name'] for st in stn['States']) activeState = stn['ActiveState'] varTemplate = 'char* {name}; /* States: [{states}] ({description}) */' self.stnDefs.append(varTemplate.format(name = stnVariableName, states = states, description = description)) varTemplate = '_m_->{name} = "{activeState}";' self.initiallyActiveStates.append(varTemplate.format(name = stnVariableName, activeState = activeState)) nStates = len(stn['States']) for i, state in enumerate(stn['States']): if i == 0: temp = s_indent + '/* STN {0} */'.format(stnVariableName) self.residuals.append(temp) self.jacobians.append(temp) self.checkForDiscontinuities.append(temp) self.executeActions.append(temp) self.numberOfRoots.append(temp) self.rootFunctions.append(temp) temp = s_indent + 'if(_compare_strings_(_m_->{0}, "{1}")) {{'.format(stnVariableName, state['Name']) self.residuals.append(temp) self.jacobians.append(temp) self.checkForDiscontinuities.append(temp) self.executeActions.append(temp) self.numberOfRoots.append(temp) self.rootFunctions.append(temp) elif (i > 0) and (i < nStates - 1): temp = s_indent + 'else if(_compare_strings_(_m_->{0}, "{1}")) {{'.format(stnVariableName, state['Name']) self.residuals.append(temp) self.jacobians.append(temp) self.checkForDiscontinuities.append(temp) self.executeActions.append(temp) self.numberOfRoots.append(temp) self.rootFunctions.append(temp) else: temp = s_indent + 'else {' self.residuals.append(temp) self.jacobians.append(temp) self.checkForDiscontinuities.append(temp) self.executeActions.append(temp) self.numberOfRoots.append(temp) self.rootFunctions.append(temp) # 1a. Generate NestedSTNs self._processSTNs(state['NestedSTNs'], indent+1) # 1b. Put equations into the residuals list self.equationGenerationMode = 'residuals' self._processEquations(state['Equations'], indent+1) self.residuals.append(s_indent + '}') # 1c. Put equations into the jacobians list self.equationGenerationMode = 'jacobian' self._processEquations(state['Equations'], indent+1) self.jacobians.append(s_indent + '}') s_indent2 = (indent + 1) * self.defaultIndent s_indent3 = (indent + 2) * self.defaultIndent # 2. checkForDiscontinuities for i, on_condition_action in enumerate(state['OnConditionActions']): condition = self.exprFormatter.formatRuntimeConditionNode(on_condition_action['ConditionRuntimeNode']) if i == 0: self.checkForDiscontinuities.append(s_indent2 + 'if({0}) {{'.format(condition)) self.checkForDiscontinuities.append(s_indent3 + 'foundDiscontinuity = true;') self.checkForDiscontinuities.append(s_indent2 + '}') elif (i > 0) and (i < nStates - 1): self.checkForDiscontinuities.append(s_indent2 + 'else if({0}) {{'.format(condition)) self.checkForDiscontinuities.append(s_indent3 + 'foundDiscontinuity = true;') self.checkForDiscontinuities.append(s_indent2 + '}') else: self.checkForDiscontinuities.append(s_indent2 + 'else {') self.checkForDiscontinuities.append(s_indent3 + 'foundDiscontinuity = true;') self.checkForDiscontinuities.append(s_indent2 + '}') self.checkForDiscontinuities.append(s_indent + '}') # 3. executeActions for i, on_condition_action in enumerate(state['OnConditionActions']): condition = self.exprFormatter.formatRuntimeConditionNode(on_condition_action['ConditionRuntimeNode']) if i == 0: self.executeActions.append(s_indent2 + 'if({0}) {{'.format(condition)) elif (i > 0) and (i < nStates - 1): self.executeActions.append(s_indent2 + 'else if({0}) {{'.format(condition)) else: self.executeActions.append(s_indent2 + 'else {') self._processActions(on_condition_action['Actions'], indent+2) self.executeActions.append(s_indent2 + '}') self.executeActions.append(s_indent + '}') # 4. numberOfRoots for i, on_condition_action in enumerate(state['OnConditionActions']): nExpr = len(on_condition_action['Expressions']) self.numberOfRoots.append(s_indent2 + '_noRoots_ += {0};'.format(nExpr)) self.numberOfRoots.append(s_indent + '}') # 5. rootFunctions for i, on_condition_action in enumerate(state['OnConditionActions']): for expression in on_condition_action['Expressions']: self.rootFunctions.append(s_indent2 + '_temp_ = {0};'.format(self.exprFormatter.formatRuntimeNode(expression))) self.rootFunctions.append(s_indent2 + '_roots_[_rc_++] = _temp_.getValue();') self.rootFunctions.append(s_indent + '}') def _processActions(self, Actions, indent): s_indent = indent * self.defaultIndent for action in Actions: if action['Type'] == 'eChangeState': relativeName = daeGetRelativeName(self.wrapperInstanceName, action['STNCanonicalName']) relativeName = self.exprFormatter.formatIdentifier(relativeName) stnVariableName = self.exprFormatter.flattenIdentifier(relativeName) + '_stn' stateTo = action['StateTo'] self.executeActions.append(s_indent + '_log_message_("The state: [{0}] in the STN [{1}] is active now.\\n");'.format(stateTo, relativeName)) self.executeActions.append(s_indent + '_m_->{0} = "{1}";'.format(stnVariableName, stateTo)) elif action['Type'] == 'eSendEvent': self.warnings.append('C code cannot be generated for SendEvent actions on [%s] event port' % action['SendEventPort']) elif action['Type'] == 'eReAssignOrReInitializeVariable': relativeName = daeGetRelativeName(self.wrapperInstanceName, action['VariableCanonicalName']) relativeName = self.exprFormatter.formatIdentifier(relativeName) domainIndexes = action['DomainIndexes'] overallIndex = action['OverallIndex'] ID = action['ID'] node = action['RuntimeNode'] strDomainIndexes = '' if len(domainIndexes) > 0: strDomainIndexes = '(' + ','.join() + ')' variableName = relativeName + strDomainIndexes value = self.exprFormatter.formatRuntimeNode(node) self.executeActions.append(s_indent + '_log_message_("The variable [{0}] new value is [{1}] now.\\n");'.format(variableName, value)) self.executeActions.append(s_indent + '_temp_ = {0};'.format(value)) if ID == cnDifferential: # Write a new value directly into the _values_ array # All actions that need this variable will use a new value. # Is that what we want??? Should be... self.executeActions.append(s_indent + '_values_[{0}] = _temp_.getValue();'.format(overallIndex)) elif ID == cnAssigned: self.executeActions.append(s_indent + '{0} = _temp_.getValue();'.format(variableName)) else: raise RuntimeError('Cannot reset a value of the state variable: {0}'.format(relativeName)) self.executeActions.append(s_indent + '_copy_values_to_solver_ = true;') elif action['Type'] == 'eUserDefinedAction': self.warnings.append('C code cannot be generated for UserDefined actions') else: raise RuntimeError('Unknown action type') def _generateRuntimeInformation(self, runtimeInformation): Ntotal = runtimeInformation['TotalNumberOfVariables'] Neq = runtimeInformation['NumberOfEquations'] IDs = runtimeInformation['IDs'] initValues = runtimeInformation['Values'] initDerivatives = runtimeInformation['TimeDerivatives'] indexMappings = runtimeInformation['IndexMappings'] absoluteTolerances = runtimeInformation['AbsoluteTolerances'] self.runtimeInformation_init.append('_m_->Ntotal_vars = %d;' % Ntotal) self.runtimeInformation_init.append('_m_->Nequations = %d;' % Neq) self.runtimeInformation_init.append('_m_->Nequations_local = rtnd.i_end - rtnd.i_start;') self.runtimeInformation_init.append('_m_->startTime = %f;' % 0.0) self.runtimeInformation_init.append('_m_->timeHorizon = %f;' % runtimeInformation['TimeHorizon']) self.runtimeInformation_init.append('_m_->reportingInterval = %f;' % runtimeInformation['ReportingInterval']) self.runtimeInformation_init.append('_m_->relativeTolerance = %f;' % runtimeInformation['RelativeTolerance']) self.runtimeInformation_init.append('_m_->quasiSteadyState = %s;\n' % ('true' if runtimeInformation['QuasiSteadyState'] else 'false')) self.variableNames = Neq * [''] blockIDs = Neq * [-1] blockInitValues = Neq * [-1] absTolerances = Neq * [1E-5] blockInitDerivatives = Neq * [0.0] for oi, bi in list(indexMappings.items()): if IDs[oi] == cnAlgebraic: blockIDs[bi] = cnAlgebraic elif IDs[oi] == cnDifferential: blockIDs[bi] = cnDifferential if IDs[oi] != cnAssigned: blockInitValues[bi] = initValues[oi] blockInitDerivatives[bi] = initDerivatives[oi] absTolerances[bi] = absoluteTolerances[oi] runtime_data_map = {} for node_rank, node_data in self.mpi_node_block_indexes_map.items(): i_start = node_data[1][0] i_end = node_data[1][1] init_values = blockInitValues[i_start:i_end] init_derivatives = blockInitDerivatives[i_start:i_end] absolute_tolerances = absTolerances[i_start:i_end] ids = blockIDs[i_start:i_end] variable_names = [] runtime_data_map[node_rank] = { 'i_start' : i_start, 'i_end' : i_end, 'init_values' : init_values, 'init_derivatives' : init_derivatives, 'absolute_tolerances': absolute_tolerances, 'ids' : ids, 'variable_names' : variable_names} mapTemplate = """std::map<int, runtimeInformationData> mapRuntimeInformationData = { %(map_items)s }; """ itemsTemplate=""" { %(node_rank)d, { %(runtime_node_data)s } }""" runtime_node_data_tmpl = """ %(i_start)d, %(i_end)d, (vector<real_t>){%(init_values)s}, (vector<real_t>){%(init_derivatives)s}, (vector<real_t>){%(absolute_tolerances)s}, (vector<int>) {%(ids)s}, (vector<string>){%(variable_names)s} """ map_items = [] for ni, n_data in runtime_data_map.items(): node_rank = ni i_start = n_data['i_start'] i_end = n_data['i_end'] init_values = ', '.join([str(i) for i in n_data['init_values']]) init_derivatives = ', '.join([str(i) for i in n_data['init_derivatives']]) absolute_tolerances = ', '.join([str(i) for i in n_data['absolute_tolerances']]) ids = ', '.join([str(i) for i in n_data['ids']]) variable_names = ', '.join([str(i) for i in n_data['variable_names']]) runtime_node_data = runtime_node_data_tmpl % {'i_start' : i_start, 'i_end' : i_end, 'init_values' : init_values, 'init_derivatives' : init_derivatives, 'absolute_tolerances': absolute_tolerances, 'ids' : ids, 'variable_names' : variable_names} map_items.append(itemsTemplate % {'node_rank' : ni, 'runtime_node_data' : runtime_node_data }) self.runtimeInformation_h = mapTemplate % {'map_items' : ',\n'.join(map_items)} for domain in runtimeInformation['Domains']: relativeName = daeGetRelativeName(self.wrapperInstanceName, domain['CanonicalName']) formattedName = self.exprFormatter.formatIdentifier(relativeName) name = self.exprFormatter.flattenIdentifier(formattedName) description = domain['Description'] numberOfPoints = domain['NumberOfPoints'] units = ('-' if (domain['Units'] == unit()) else str(domain['Units'])) domains = '[' + str(domain['NumberOfPoints']) + ']' points = self.exprFormatter.formatNumpyArray(domain['Points']) # Numpy array domTemplate = 'int {name}_np; /* Number of points in domain: {relativeName} */' paramTemplate = 'real_t {name}{domains}; /* Domain: {relativeName} ({units}, {description}) */' self.parametersDefs.append(domTemplate.format(name = name, relativeName = relativeName)) self.parametersDefs.append(paramTemplate.format(name = name, units = units, domains = domains, relativeName = relativeName, description = description)) domTemplate = 'const int {name}_np = {numberOfPoints};' paramTemplate = 'real_t {name}{domains} = {points}; /* {units} */' self.parametersInits.append(domTemplate.format(name = name, numberOfPoints = numberOfPoints)) self.parametersInits.append(paramTemplate.format(name = name, domains = domains, points = points, units = units, description = description)) domTemplate = '_m_->{name}_np = {name}_np;' paramTemplate = 'memcpy(&_m_->{name}, &{name}, {numberOfPoints} * sizeof(real_t));\n' self.parametersInits.append(domTemplate.format(name = name)) self.parametersInits.append(paramTemplate.format(name = name, numberOfPoints = numberOfPoints)) struct_name = formattedName + '_np' flat_name = name + '_np' self.intValuesReferences.append( ('NumberOfPointsInDomain', struct_name, flat_name, None) ) for i in range(len(domain['Points'])): struct_name = '{0}[{1}]'.format(formattedName, i) flat_name = '{0}[{1}]'.format(name, i) self.floatValuesReferences.append( ('DomainPoints', struct_name, flat_name, None) ) for parameter in runtimeInformation['Parameters']: relativeName = daeGetRelativeName(self.wrapperInstanceName, parameter['CanonicalName']) formattedName = self.exprFormatter.formatIdentifier(relativeName) name = self.exprFormatter.flattenIdentifier(formattedName) description = parameter['Description'] numberOfPoints = int(parameter['NumberOfPoints']) units = ('-' if (parameter['Units'] == unit()) else str(parameter['Units'])) values = self.exprFormatter.formatNumpyArray(parameter['Values']) # Numpy array numberOfDomains = len(parameter['Domains']) domains = '' if numberOfDomains > 0: domains = '[{0}]'.format(']['.join(str(np) for np in parameter['Domains'])) paramTemplate = 'real_t {name}{domains}; /* Parameter: {relativeName} ({units}, {description}) */' self.parametersDefs.append(paramTemplate.format(name = name, units = units, domains = domains, relativeName = relativeName, description = description)) paramTemplate = 'real_t {name}{domains} = {values} /* {units} */;' self.parametersInits.append(paramTemplate.format(name = name, units = units, domains = domains, values = values)) paramTemplate = 'memcpy(&_m_->{name}, &{name}, {numberOfPoints} * sizeof(real_t));\n' self.parametersInits.append(paramTemplate.format(name = name, numberOfPoints = numberOfPoints)) else: paramTemplate = 'real_t {name}; /* Parameter: {relativeName} ({units}, {description}) */' self.parametersDefs.append(paramTemplate.format(name = name, units = units, relativeName = relativeName, description = description)) paramTemplate = '_m_->{name} = {value} /* {units} */;' self.parametersInits.append(paramTemplate.format(name = name, units = units, value = values)) if numberOfDomains == 0: struct_name = formattedName flat_name = self.exprFormatter.flattenIdentifier(struct_name) self.floatValuesReferences.append( ('Parameter', struct_name, flat_name, None) ) else: domainsIndexesMap = parameter['DomainsIndexesMap'] for i in range(0, numberOfPoints): domIndexes = tuple(domainsIndexesMap[i]) # list of integers struct_name = '{0}[{1}]'.format(formattedName, ']['.join(str(index) for index in domIndexes)) flat_name = '{0}[{1}]'.format(name, ']['.join(str(index) for index in domIndexes)) self.floatValuesReferences.append( ('Parameter', struct_name, flat_name, None) ) """ it = numpy.nditer(parameter['Values'], flags=['c_index', 'multi_index']) while not it.finished: #print name + "%s = %d" % (it.multi_index, it[0]) p_name = '{0}[{1}]'.format(name, ']['.join(str(index) for index in it.multi_index)) self.floatValuesReferences.append( ('Parameter', p_name, value_ref) ) print p_name value_ref += 1 it.iternext() """ for variable in runtimeInformation['Variables']: relativeName = daeGetRelativeName(self.wrapperInstanceName, variable['CanonicalName']) formattedName = self.exprFormatter.formatIdentifier(relativeName) name = self.exprFormatter.flattenIdentifier(formattedName) numberOfPoints = variable['NumberOfPoints'] units = ('-' if (variable['Units'] == unit()) else str(variable['Units'])) if numberOfPoints == 1: ID = int(variable['IDs']) # cnDifferential, cnAssigned or cnAlgebraic value = float(variable['Values']) # numpy float overallIndex = variable['OverallIndex'] fullName = relativeName blockIndex = None nodeIndex = None if ID != cnAssigned: blockIndex = indexMappings[overallIndex] + self.exprFormatter.indexBase nodeIndex = blockIndex / self.Nnodes self.variableNames[blockIndex] = fullName if ID == cnDifferential: name_ = 'values[{0}]'.format(nodeIndex) temp = '{name} = {value} /* {units} */; /* {fullName} */'.format(name = name_, value = value, units = units, fullName = fullName) self.initialConditions.append((blockIndex, temp)) elif ID == cnAssigned: name_ = name temp = 'real_t {name}; /* {fullName}, {units} */'.format(name = name, units = units, fullName = fullName) self.assignedVariablesDefs.append(temp) temp = '_m_->{name} = {value} /* {units} */;'.format(name = name, value = value, units = units) self.assignedVariablesInits.append(temp) if ID == cnAssigned: ref_type = 'Assigned' elif ID == cnDifferential: ref_type = 'Differential' else: ref_type = 'Algebraic' struct_name = name # Name as it appears in daeModel_t (Assigned vars. only) flat_name = self.exprFormatter.flattenIdentifier(struct_name) self.floatValuesReferences.append( (ref_type, struct_name, flat_name, blockIndex) ) else: domainsIndexesMap = variable['DomainsIndexesMap'] for i in range(0, numberOfPoints): domIndexes = tuple(domainsIndexesMap[i]) # list of integers ID = int(variable['IDs'][domIndexes]) # cnDifferential, cnAssigned or cnAlgebraic value = float(variable['Values'][domIndexes]) # numpy float overallIndex = variable['OverallIndex'] + i fullName = relativeName + '(' + ','.join(str(di) for di in domIndexes) + ')' blockIndex = None if ID != cnAssigned: blockIndex = indexMappings[overallIndex] + self.exprFormatter.indexBase self.variableNames[blockIndex] = fullName if ID == cnDifferential: name_ = 'values[{0}]'.format(blockIndex) temp = '{name} = {value} /* {units}*/; /* {fullName} */'.format(name = name_, value = value, units = units, fullName = fullName) self.initialConditions.append((blockIndex,temp)) elif ID == cnAssigned: name_ = name + '_' + '_'.join(str(di) for di in domIndexes) temp = 'real_t {name}; /* {fullName}, {units} */'.format(name = name_, units = units, fullName = fullName) self.assignedVariablesDefs.append(temp) temp = '_m_->{name} = {value} /* {units} */;'.format(name = name_, value = value, units = units) self.assignedVariablesInits.append(temp) if ID == cnAssigned: ref_type = 'Assigned' struct_name = name_ # Name as it appears in daeModel_t (Assigned vars. only) elif ID == cnDifferential: ref_type = 'Differential' struct_name = name else: ref_type = 'Algebraic' struct_name = name flat_name = self.exprFormatter.flattenIdentifier(struct_name) self.floatValuesReferences.append( (ref_type, struct_name, flat_name, blockIndex) ) varNames = ['"' + name_ + '"' for name_ in self.variableNames] #self.runtimeInformation_h.append('const char* _variable_names_ [%d] = %s;' % (Neq, self.exprFormatter.formatNumpyArray(varNames))) #self.runtimeInformation_init.append('for(int i = 0; i < %d; i++)' % Neq) #self.runtimeInformation_init.append(' _m_->variableNames[i] = _variable_names_[i];') #import pprint #pp = pprint.PrettyPrinter(indent=2) #pp.pprint(self.floatValuesReferences) indent = 1 s_indent = indent * self.defaultIndent # First generate residuals for equations and port connections self.equationGenerationMode = 'residuals' for port_connection in runtimeInformation['PortConnections']: #self.residuals.append(s_indent + '/* Port connection: {0} -> {1} */'.format(port_connection['PortFrom'], port_connection['PortTo'])) self._processEquations(port_connection['Equations'], indent) #self.residuals.append(s_indent + '/* Equations */') self._processEquations(runtimeInformation['Equations'], indent) # Then generate jacobians for equations and port connections self.equationGenerationMode = 'jacobian' for port_connection in runtimeInformation['PortConnections']: #self.jacobians.append(s_indent + '/* Port connection: {0} -> {1} */'.format(port_connection['PortFrom'], port_connection['PortTo'])) self._processEquations(port_connection['Equations'], indent) #self.jacobians.append(s_indent + '/* Equations */') self._processEquations(runtimeInformation['Equations'], indent) # Finally generate together residuals and jacobians for STNs # _processSTNs will take care of self.equationGenerationMode regime self._processSTNs(runtimeInformation['STNs'], indent)