B _A@sddlmZmZmZmZmZmZddlmZm Z ddl m Z ddl m ZddlmZmZmZddlmZmZddlmZddlmZdd lmZmZdd lZd Zed Z dd l!m"Z#m$Z$m%Z%dd l&Z&e&'dkZ(e%ddgd\Z)Z*iZ+ddZ,e%de,d\Z-Z.ddZ/ddZ0ddZ1ddZ2Gdddej3Z4d d!Z5Gd"d#d#ej3Z6Gd$d%d%ej7Z8d&d'Z9d(d)Z:Gd*d+d+Z;d S),) ConstraintParamVarvalueSuffixBlock) ContinuousSet DerivativeVar) DAE_Error)current) NumericValuenative_numeric_typesnonpyomo_leaf_types) IndexTemplate_GetItemIndexer)IndexedComponent_slice) Reference)iterkeys itervaluesN) Simulatorz pyomo.core)numpynumpy_availableattempt_importPyPyzscipy.integratescipy)Z alt_namescCs\|rXt|j|j|j|j|j|j|j|j |j |j |j |j |j|j|j|j|j|jddS)N)loglog10sincostancoshsinhtanhasinacosatanexpsqrtasinhacoshatanhceilfloor)casadi_intrinsicupdaterrrrrr r!r"r#r$r%r&r'r(r)r*r+r,)casadi availabler17/tmp/pip-unpacked-wheel-d4p3hk07/pyomo/dae/simulator.py_finalize_casadi1s(r3r/)callbackcCs8t||dtkr0|||d|gSdSdS)a5 Accepts an equality expression and an index value. Checks the GetItemExpression at expr.arg(i) to see if it is a :py:class:`DerivativeVar`. If so, return the GetItemExpression for the :py:class:`DerivativeVar` and the RHS. If not, return None. rN)typeargr )exprir1r1r2_check_getitemexpressionJsr:c Cs||}|dfg}g}d}x|r|\}}|jtjkrd||d|f||d|fq|jtjkr||d|f||d| fq|jtjkr||d| fqt|tj krt|dt kr||f}q|||fqW|dkr dSd}d} x.|D]&\} }|dkr4| | 9} n|| 9}qW|\}}|dkrn||d||| gS|| |d||gSdS)aI Accepts an equality expression and an index value. Checks the ProductExpression at expr.arg(i) to see if it contains a :py:class:`DerivativeVar`. If so, return the GetItemExpression for the :py:class:`DerivativeVar` and the RHS. If not, return None. r5Nr) r7pop __class__EXPRProductExpressionappendDivisionExpressionReciprocalExpressionr6GetItemExpressionr ) r8r9Zexpr_stackZptermsdvcurrZe_ZnumerZdenomZtermr1r1r2_check_productexpressionXs<           rFcCs||d}t|tjkrDt|dtkrD||d| gSt|tjkr|d}|d}t|tks~|r~dSt|tjkrt|dtksdS||d| |gSdS)aJ Accepts an equality expression and an index value. Checks the NegationExpression at expr.arg(i) to see if it contains a :py:class:`DerivativeVar`. If so, return the GetItemExpression for the :py:class:`DerivativeVar` and the RHS. If not, return None. rr5N)r7r6r=rBr r>r is_potentially_variable)r8r9r7lhsrhsr1r1r2_check_negationexpressions    rJc Cs||}g}d}d}xt|jD]\}}|dk r>||q"t|tjkrdt|dtkrd|}q"t|tjkr|d}|d} t|t ks| st| tjkrt| dtkr| }|}q"||q"W|dk r|d|} x|D] }| |8} qW| |} || gSdS)aF Accepts an equality expression and an index value. Checks the Sum expression at expr.arg(i) to see if it contains a :py:class:`DerivativeVar`. If so, return the GetItemExpression for the :py:class:`DerivativeVar` and the RHS. If not, return None. Nr5r) r7 enumerateargsr?r6r=rBr r>r rG) r8r9ZsumexpitemsrDZdvcoefidxitemrHrIRHSr1r1r2_check_viewsumexpressions6        rQcs,eZdZdZfddZfddZZS)Pyomo2Scipy_Visitorzc Expression walker that replaces _GetItemExpression instances with mutable parameters. cstt|||_dS)N)superrR__init__ templatemap)selfrU)r<r1r2rTszPyomo2Scipy_Visitor.__init__cst|tkrd|fSt|tjkrt|}||jkr|tdd|j|<|j|d|jj d dd|j Df|j|_ d|j|fSt t||S)NT)Zmutablez%s[%s],css|]}t|VqdS)N)str).0xr1r1r2 sz>Pyomo2Scipy_Visitor.visiting_potential_leaf..)r6rr=rBrrUrZ constructbasenamejoinrL_namerSrRvisiting_potential_leaf)rVnode_id)r<r1r2r`s  (z+Pyomo2Scipy_Visitor.visiting_potential_leaf)__name__ __module__ __qualname____doc__rTr` __classcell__r1r1)r<r2rRs rRcCsts tdt|}||S)aESubstitute _GetItem nodes in an expression tree. This substition function is used to replace Pyomo _GetItem nodes with mutable Params. Args: templatemap: dictionary mapping _GetItemIndexer objects to mutable params Returns: a new expression tree with all substitutions done zDSciPy is not installed. Cannot substitute SciPy intrinsic functions.)scipy_availabler rRdfs_postorder_stack)r8rUvisitorr1r1r2convert_pyomo2scipys rkcs0eZdZdZfddZddZddZZS)Substitute_Pyomo2Casadi_Visitora Expression walker that replaces * _UnaryFunctionExpression instances with unary functions that point to casadi intrinsic functions. * _GetItemExpressions with _GetItemIndexer objects that references CasADi variables. cstt|||_dS)N)rSrlrTrU)rVrU)r<r1r2rTsz(Substitute_Pyomo2Casadi_Visitor.__init__cCs,t|tjkr(t|d|jt|jS|S)z(Replace a node if it's a unary function.r)r6r=ZUnaryFunctionExpressionr_r-)rVravaluesr1r1r2visits  z%Substitute_Pyomo2Casadi_Visitor.visitcCst|tjkrbt|}||jkrTd|jjddd|jDf}t j ||j|<d|j|fSt|t ks| rt|tkrd|fSdS)z,Replace a node if it's a _GetItemExpression.z%s[%s]rWcss|]}t|VqdS)N)rX)rYrZr1r1r2r[!szJSubstitute_Pyomo2Casadi_Visitor.visiting_potential_leaf..T)FN)r6r=rBrrUr\r]r^rLr/SXsymr is_expression_typer)rVrarbr]r1r1r2r`s    z7Substitute_Pyomo2Casadi_Visitor.visiting_potential_leaf)rcrdrerfrTrnr`rgr1r1)r<r2rls   rlc@s eZdZdZddZddZdS)Convert_Pyomo2Casadi_Visitora Expression walker that evaluates an expression generated by the Substitute_Pyomo2Casadi_Visitor walker. In Coopr3 this walker was not necessary because the expression could be simply evaluated. But in Pyomo5, the evaluation logic was changed to be non-recursive, which involves checks on the types of leaves in the expression tree. Hence, the evaluation logic fails if leaves in the tree are not standard Pyomo5 variable types. cCs ||S)z% Visit nodes that have been expanded )Z_apply_operation)rVrarmr1r1r2rn9sz"Convert_Pyomo2Casadi_Visitor.visitcCsR|jtkrd|fS|jtjkr&d|fS|r:dt|fS|sNdt|fSdS)z^ Visiting a potential leaf. Return True if the node is not expanded. T)FN)r<r r/roZis_variable_typerrq)rVrar1r1r2r`=s    z4Convert_Pyomo2Casadi_Visitor.visiting_potential_leafN)rcrdrerfrnr`r1r1r1r2rr-s rrcCsts tdt|}||S)amSubstitute IndexTemplates in an expression tree. This substition function is used to replace Pyomo intrinsic functions with CasADi functions. Args: expr: a Pyomo expression templatemap: dictionary mapping _GetItemIndexer objects to mutable params Returns: a new expression tree with all substitutions done zUCASADI is not installed. Cannot substitute CasADi variables and intrinsic functions.)casadi_availabler rlri)r8rUrjr1r1r2substitute_pyomo2casadiRsrtcCsts tdt}||S)aConvert a Pyomo expression tree to Casadi. This function replaces a Pyomo expression with a CasADi expression. This assumes that the `substitute_pyomo2casadi` function has been called, so the Pyomo expression contains CasADi variables and intrinsic functions. The resulting expression can be used with the CasADi integrator. Args: expr: a Pyomo expression with CasADi variables and intrinsic functions Returns: a CasADi expression tree. zSCASADI is not installed. Cannot convert a Pyomo expression to a Casadi expression.)rsr rrri)r8rjr1r1r2convert_pyomo2casadigsruc@sNeZdZdZdddZdddZddd Zd d Zd d ZddZ ddZ dS)rar Simulator objects allow a user to simulate a dynamic model formulated using pyomo.dae. Parameters ---------- m : Pyomo Model The Pyomo model to be simulated should be passed as the first argument package : `string` The Python simulator package to use. Currently 'scipy' and 'casadi' are the only supported packages rcs||_|jdkr&td|jddgf|jdkrPts@tdq\tr\tdn ts\tdtt |j t dd d r|td | t }t|d krtd t |d}t|| t}t |}t|drx|jD]}||jqWt|dkrtdiigg}x|jtddD]}d|jkr<q&|dkrNq&|} d} d} d} x^| D]R} | |kr| dkrtd|j| } n| dkr| } n | | } | | j7} qlW| dkrАq&| dkrd} |j}x| D]}|dkr||}n:t|ts|f}|d| f|| d}|||}t |t!j"k rVqd}t |#dt!j$krzt%|d}|dkrt |#d t!j$krt%|d }|dkrt |#dt!j&kst |#dt!j'kst |#dt!j(krt)|d}|dkrPt |#d t!j&ksFt |#d t!j'ksFt |#d t!j(krPt)|d }|dkrzt |#dt!j*krzt+|d}|dkrt |#d t!j*krt+|d }|dkrt |#dt!j,krt-|d}|dkrt |#d t!j,krt-|d }|dkrL|jdkr tdt.|j|#d|#d }t/|}||q|d}|d }t0|}|krtdt.|||jdkrt/||<nt1||<qWq&Wgx,D]$}|j23}t0||j4qWg}x|_?|_@|_A||_B||_C||_Dd|_Ed|_Fd|_Gd|_HdS)N)rr/z8Unrecognized simulator package %s. Please select from %srr/zuThe scipy module is not available. You may build the Simulator object but you will not be able to run the simulation.zThe scipy ODE integrators do not work in pypy. You may build the Simulator object but you will not be able to run the simulation.z:The casadi module is not available. Cannot simulate model.TF)activeZ descend_intoz>The Simulator cannot handle hierarchical models at the moment.r5zWCurrently the simulator may only be applied to Pyomo models with a single ContinuousSetr&_pyomo_dae_reclassified_derivativevarsz+Cannot simulate a model with no derivatives)rvZ_disc_eqzSCannot simulate the constraint %s because it is indexed by duplicate ContinuousSets)NzModel contains an algebraic equation or unrecognized differential equation. Constraint '%s' cannot be simulated using Scipy. If you are trying to simulate a DAE model you must use CasADi as the integration package.z7Found multiple RHS expressions for the DerivativeVar %szDCannot simulate a differential equation with multiple DerivativeVarscs`g}|x.tD]"\}}|kr|||qWxD]}||qDW|S)N) set_valuerKr?)trZZresidualrNvd) cstemplate derivlistdiffvarsrhsdictrUr1r2_rhsfuns  z#Simulator.__init__.._rhsfunz%s[%s]rWcss|]}t|VqdS)N)rX)rYrZr1r1r2r[sz%Simulator.__init__..)I _intpackager rhloggerwarningis_pypyrs ValueErrorlenlistZcomponent_data_objectsrZ component_maprrmrr keyshasattrrwr?r]Zcomponent_objectsrZdimZ index_setZsubsetsZcrossZdimenZrule isinstancetupler6r=ZEqualityExpressionr7rBr:r>rAr@rFZ SumExpressionrQZNegationExpressionrJrXrtrrkr\Z get_state_var_argsrrr^rLr/rorp_contsetZ _cstemplate _diffvars _derivlist _templatemap_rhsdict_alglist_algvars_model_tsim _simsolution _simalgvars _siminputvars)rVmpackagetempZcontsetZderivsr|ZalglistconZconindexZdimsumZcsidxZnoncsidxsZconruler9ZtempexpZtempidxrLZalgexprDrPZdvkeyZderivsvZalgvarsrOrrbr]r1)r}r~rrrUr2rTs*                                                       zSimulator.__init__NcCs4|dkr|jS|dkr|jS|dkr*|jS|jSdS)au This function returns the ordered list of differential variable names. The order corresponds to the order being sent to the integrator function. Knowing the order allows users to provide initial conditions for the differential equations using a list or map the profiles returned by the simulate function to the Pyomo variables. Parameters ---------- vartype : `string` or None Optional argument for specifying the type of variables to return the order for. The default behavior is to return the order of the differential variables. 'time-varying' will return the order of all the time-dependent algebraic variables identified in the model. 'algebraic' will return the order of algebraic variables used in the most recent call to the simulate function. 'input' will return the order of the time-dependent algebraic variables that were treated as inputs in the most recent call to the simulate function. Returns ------- `list` z time-varyingZ algebraicinputN)rrrr)rVvartyper1r1r2get_variable_orderszSimulator.get_variable_ordercCsts td|dkri}|jdkrLdddddg}|dkr>d}qd|d krdd}nd d d d g}|dkrdd }||krtd|j||f|dk r||j|jkrtd||jf|dk r|dk rtd|dkr|dkrd}|dkr tj |j|j|d}nt |j|j|}g} i|_ g|_ |dk rt |tk rTtdxH|jD]>} | j|kr| || j7} | |j | j<n |j | q\W|jdkrt|j dkrtdtt| } | | d|jks| d|jkrtdt|| }n|j|_ |dk rtt|t|jkrLtdt|jt|t|jkrtdt|jng}x|jD]|} x(t| jD]\} } t | tkrPqW|j}t| jd| |ft| j| dd}|t| j|qW|jdkrBtstdt r(td|!||| |||\}}n:t| dkrh|"|||||\}}n|#||||\}}||_$||_%||gS)a= Simulate the model. Integrator-specific options may be specified as keyword arguments and will be passed on to the integrator. Parameters ---------- numpoints : int The number of points for the profiles returned by the simulator. Default is 100 tstep : int or float The time step to use in the profiles returned by the simulator. This is not the time step used internally by the integrators. This is an optional parameter that may be specified in place of 'numpoints'. integrator : string The string name of the integrator to use for simulation. The default is 'lsoda' when using Scipy and 'idas' when using CasADi varying_inputs : ``pyomo.environ.Suffix`` A :py:class:`Suffix` object containing the piecewise constant profiles to be used for certain time-varying algebraic variables. initcon : list of floats The initial conditions for the the differential variables. This is an optional argument. If not specified then the simulator will use the current value of the differential variables at the lower bound of the ContinuousSet for the initial condition. integrator_options : dict Dictionary containing options that should be passed to the integrator. See the documentation for a specific integrator for a list of valid options. Returns ------- numpy array, numpy array The first return value is a 1D array of time points corresponding to the second return value which is a 2D array of the profiles for the simulated differential and algebraic variables. z=The numpy module is not available. Cannot simulate the model.NrZvodeZzvodeZlsodaZdopri5Zdop853ZodeintZcvodesZidasZ collocationZrkzDUnrecognized %s integrator '%s'. Please select an integrator from %szCThe step size %6.2f is larger than the span of the ContinuousSet %szLCannot specify both the step size and the number of points for the simulatord)numzcVarying input values must be specified using a Suffix. Please refer to the simulator documentation.rzWhen simulating with Scipy you must provide values for all parameters and algebraic variables that are indexed by the ContinuoutSet using the 'varying_inputs' keyword argument. Please refer to the simulator documentation for more information.rxzvFound a switching point for one or more of the time-varying inputs that is not within the bounds of the ContinuousSet.z^Too many initial conditions were specified. The simulator was expecting a list with %i values.z]Too few initial conditions were specified. The simulator was expecting a list with %i values.r5z=The scipy module is not available. Cannot simulate the model.zLThe scipy ODE integrators do not work under pypy. Cannot simulate the model.)&rrrr rlastfirstr]npZlinspaceZarangerrr6r TypeErrorr_baserr?rrsetsortZunion1drrKrrrrrhr_simulate_with_scipy!_simulate_with_casadi_with_inputs_simulate_with_casadi_no_inputsrr)rVZ numpointsZtstep integratorvarying_inputsinitconintegrator_optionsZvalid_integratorstsim switchptsalgr{rNr9Z initpointvidxprofiler1r1r2simulates.                 zSimulator.simulatec Cst|jj|f|}|||dt|}d} x|r|j|dkr|| d|krxP|j D]B} || d|| krh|j |j | } | || || dqhW| || } t|| g}| d7} q6W|std|||gS)Nrr5rxz7The Scipy integrator %s did not terminate successfully.)roderZset_integratorZset_initial_valuerarrayZ successfulrzrrrryZ integrateZvstackr ) rVrrrrrrZscipyintrr9r{pZ profilestepr1r1r2rs$  zSimulator._simulate_with_scipycs fddjD}tj|}fddjD}tj|}||d} tjdkrfddjD} tj| } ddjD} tj| } | | d<| | d <||d <d |d <td || |}||d}|d j }tjdkr|d j }t j ||fdd}||gS)Ncsg|]}j|qSr1)r)rYr9)rVr1r2 sz=Simulator._simulate_with_casadi_no_inputs..csg|]}tj|qSr1)rur)rYr9)rVr1r2rs)rZrrcsg|]}j|qSr1)r)rYr9)rVr1r2rscSsg|] }t|qSr1)ru)rYr9r1r1r2rszrZgridTZ output_t0F)x0xfzfr5)axis) rr/vertcatrrrrrrfullTr concatenate)rVrrrrxalltempxall odealltempodealldaezalltempzall algalltempalgallrsolr algprofiler1)rVr2rs,        z)Simulator._simulate_with_casadi_no_inputscs"fddjD}tj|}tjdfddjD}tj|} fddjD} tjf| } || | d} tj dkrԇfddj D} tj| }d dj D}tj|}|| d <|| d <d |d <t d|| |}t}t dddddg}dt|f|_t|g}xjD]~}||tfddDtdgdgfddttD} tj| }||q.timecsg|]}tj|qSr1)rur)rYr9)rVrr1r2rscsg|]}j|qSr1)r)rYr9)rVr1r2rs)rZrrrcsg|]}j|qSr1)r)rYr9)rVr1r2rscSsg|] }t|qSr1)ru)rYr9r1r1r2rsrrg?tfrr5rxcsg|]}|qSr1)Z searchsorted)rYr9)rr1r2rsc s2g|]*}t|d|d|qS)r5)r/Zrepmat)rYr9)rtidxtswitchr1r2rsZ simulator)rrrr)r)rr/rrorprrrmrrrrrrZhstackshapeZDMrrrrangeZhorzcatr?Zmapaccumrrr)rVrrrrrrrrrZptempZpallrrrrrrNZtsimtempZpalltemprrIrrr1)rrVrrrrr2rsR         "    z+Simulator._simulate_with_casadi_with_inputsc Cs|jdkrtdt|j}|j|j}xt|D]\}}x$t|jD]\}}t|t krFPqFWt ||j|j dd|f}xPt|D]D\}}t |jd||ft |j|dd} |||j| <qWq2WdS)z This function will initialize the model using the profile obtained from simulating the dynamic model. Nz9Tried to initialize the model without simulating it firstrr5)rr rrrrrKrr6rrZinterprrr) rVZtvalsZinitvarsrNr{Zidx2r9Zvalinitrzrr1r1r2initialize_models     zSimulator.initialize_model)r)N)NNNNNN) rcrdrerfrTrrrrrrr1r1r1r2r~s   $ M!@r) s:       /.*%