#!/usr/bin/env python # coding: utf-8 # # Manipulate the Simulation # This example shows how to play with the simulation, # such as contingency analysis and manipulate the constraints. # In[1]: import ams import datetime # In[2]: print("Last run time:", datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")) print(f'ams:{ams.__version__}') # In[3]: ams.config_logger(stream_level=20) # ## Manipulate the Simulation # ### Load Case # In[4]: sp = ams.load(ams.get_case('5bus/pjm5bus_uced.xlsx'), setup=True, no_output=True,) # The system load are defined in model `PQ`. # In[5]: sp.PQ.as_df() # In RTED, system load is referred as `pd`. # In[6]: sp.RTED.pd.v # ### Run Simulation # RTED can be solved and one can inspect the results as discussed in # previous example. # In[7]: sp.RTED.run(solver='ECOS') # Power generation `pg` and line flow `plf` can be accessed as follows. # In[8]: sp.RTED.pg.v # In[9]: sp.RTED.plf.v # ### Change Load # The load values can be manipulated in the model `PQ`. # In[10]: sp.PQ.set(src='p0', attr='v', idx=['PQ_1', 'PQ_2'], value=[3.2, 3.2]) # According parameters need to be updated to make the changes effective in the optimization model. # If not sure which parameters need to be updated, one can use # ``update()`` to update all parameters. # In[11]: sp.RTED.update('pd') # After manipulation, the routined can be solved again. # In[12]: sp.RTED.run(solver='ECOS') # In[13]: sp.RTED.pg.v # An alternative way is to alter the load through ``RTED``. # # As ``pd`` has owner ``StaticLoad`` and soruce ``p0``, the parameter update through ``RTED`` actually happens to ``StaticLoad.p0``. # In[14]: sp.RTED.pd.owner # In[15]: sp.RTED.pd.src # Similarly, the load can be changed using ``set`` method. # In[16]: sp.RTED.set(src='pd', attr='v', idx=['PQ_1', 'PQ_2'], value=[3.8, 3.8]) # Remember to update the optimization parameters after the change. # In[17]: sp.RTED.update('pd') # We can see that the original load is also updated. # In[18]: sp.PQ.as_df() # In[19]: sp.RTED.run(solver='ECOS') # As expected, the power generation also changed. # In[20]: sp.RTED.pg.v # ### Trip a Generator # We can see that there are three PV generators in the system. # In[21]: sp.PV.as_df() # `PV_1` is tripped by setting its connection status `u` to 0. # In[22]: sp.StaticGen.set(src='u', attr='v', idx='PV_1', value=0) # In AMS, some parameters are defiend as constants in the numerical optimization model # to follow the CVXPY DCP and DPP rules. # Once non-parametric parameters are changed, the optimization model will be # re-initialized to make the changes effective. # # More details can be found at [CVXPY - Disciplined Convex Programming](https://www.cvxpy.org/tutorial/dcp/index.html#disciplined-convex-programming). # In[23]: sp.RTED.update() # Then we can re-solve the model. # In[24]: sp.RTED.run(solver='ECOS') # We can see that the tripped generator has no power generation. # In[25]: sp.RTED.pg.v.round(2) # ### Trip a Line # We can inspect the `Line` model to check the system topology. # In[26]: sp.Line.as_df() # Here line `2` is tripped by setting its connection status `u` to 0. # # Note that in ANDES, dynamic simulation of *line tripping should use model ``Toggle``.* # In[27]: sp.Line.set(src='u', attr='v', idx='Line_1', value=0) # In[28]: sp.RTED.update() # In[29]: sp.RTED.run(solver='ECOS') # Here we can see the tripped line has no flow. # In[30]: sp.RTED.plf.v.round(2) # ## Disable Constraints # In addition to the system parameters, the constraints can also be manipulated. # # Here, we load the case to a new system. # In[31]: spc = ams.load(ams.get_case('5bus/pjm5bus_uced.xlsx'), setup=True, no_output=True,) # In[32]: spc.RTED.init() # In[33]: spc.RTED.set(src='rate_a', attr='v', idx=['Line_2'], value=1.4) # In[34]: spc.RTED.update('rate_a') # We can inspect the constraints status as follows. # All constraints are turned on by default. # In[35]: spc.RTED.constrs # Then, solve the dispatch and inspect the line flow. # In[36]: spc.RTED.run(solver='ECOS') # In[37]: spc.RTED.plf.v.round(2) # In the next, we can disable specific constraints, and the parameter name takes both single constraint name or a list of constraint names. # In[38]: spc.RTED.disable(['plflb', 'plfub']) # Now, it can be seen that the two constraints are disabled. # In[39]: spc.RTED.constrs # In[40]: spc.RTED.run(solver='ECOS') # We can see that now the line flow limits are not in effect. # In[41]: spc.RTED.plf.v.round(2) # Similarly, you can also enable the constraints again. # In[42]: spc.RTED.enable(['plflb', 'plfub']) # In[43]: spc.RTED.constrs # In[44]: spc.RTED.run(solver='ECOS') # In[45]: spc.RTED.plf.v.round(2) # Alternatively, you can also **force init** the dispatch to rebuild the system matrices, enable all constraints, and re-init the optimization models. # In[46]: spc.RTED.disable(['plflb', 'plfub', 'rgu', 'rgd']) # In[47]: spc.RTED.init(force=True) # In[48]: spc.RTED.constrs # ## Alter Config # Routines have an ``config`` attribute as configuration settings. # In[49]: spf = ams.load(ams.get_case('5bus/pjm5bus_uced.xlsx'), setup=True, no_output=True,) # In RTED, the default interval is 5/60 [hour], and the formulations has been adjusted to fit the interval. # In[50]: spf.RTED.config # In[51]: spf.RTED.run(solver='ECOS') # In[52]: spf.RTED.obj.v # We can update the interval to 1 [hour] and re-solve the dispatch. # # Note that in this senario, compared to DCOPF, RTED has extra costs for ``pru`` and ``prd``. # In[53]: spf.RTED.config.t = 60/60 # Remember to update the parameters after the change. # In[54]: spf.RTED.update() # In[55]: spf.RTED.run(solver='SCS') # We can then get the objective value. # In[56]: spf.RTED.obj.v # Note that in this build-in case, the ``cru`` and ``crd`` are defined as zero. # In[57]: spf.RTED.cru.v # In[58]: spf.RTED.crd.v # As benchmark, we can solve the DCOPF. # In[59]: spf.DCOPF.run(solver='SCS') # As expected, the DCOPF has a similar objective value. # In[60]: spf.DCOPF.obj.v