Skip to content

Commit

Permalink
Fix alter and set mis-use issue
Browse files Browse the repository at this point in the history
  • Loading branch information
jinningwang committed Nov 6, 2024
1 parent 4a777dc commit afc4626
Show file tree
Hide file tree
Showing 11 changed files with 71 additions and 71 deletions.
30 changes: 15 additions & 15 deletions ams/interop/andes.py
Original file line number Diff line number Diff line change
Expand Up @@ -317,7 +317,7 @@ def parse_addfile(adsys, amsys, addfile):
syg_idx += syg.idx.v
syg_bus_idx = adsys.SynGen.get(src='bus', attr='v', idx=syg_idx)
syg_bus_vn = adsys.Bus.get(src='Vn', idx=syg_bus_idx)
adsys.SynGen.set(src='Vn', attr='v', idx=syg_idx, value=syg_bus_vn)
adsys.SynGen.set(src='Vn', idx=syg_idx, attr='v', value=syg_bus_vn)

# --- for debugging ---
adsys.df_in = df_models
Expand Down Expand Up @@ -417,7 +417,7 @@ def _send_tgr(self, sa, sp):
if syg_mask.any():
logger.debug('Governor is not complete for SynGen.')
# --- pref ---
sa.TurbineGov.set(value=syg_ams, idx=gov_idx, src='pref0')
sa.TurbineGov.set(value=syg_ams, idx=gov_idx, attr='v', src='pref0')

Check warning on line 420 in ams/interop/andes.py

View check run for this annotation

Codecov / codecov/patch

ams/interop/andes.py#L420

Added line #L420 was not covered by tests

# --- paux ---
# TODO: sync paux, using paux0
Expand All @@ -432,7 +432,7 @@ def _send_tgr(self, sa, sp):
dg_ams = sp.recent.get(src='pg', attr='v', idx=stg_dg_idx,
allow_none=True, default=0)
# --- pref ---
sa.DG.set(src='pref0', idx=dg_idx, value=dg_ams)
sa.DG.set(src='pref0', idx=dg_idx, attr='v', value=dg_ams)

Check warning on line 435 in ams/interop/andes.py

View check run for this annotation

Codecov / codecov/patch

ams/interop/andes.py#L435

Added line #L435 was not covered by tests
# TODO: paux, using Pext0, this one should be do in other place rather than here

# 3) RenGen
Expand Down Expand Up @@ -486,9 +486,9 @@ def _send_dgu(self, sa, sp):
msg += ' Otherwise, unexpected results might occur.'
raise ValueError(msg)
# FIXME: below code seems to be unnecessary
sa.SynGen.set(src='u', idx=syg_idx, value=stg_u_ams)
sa.DG.set(src='u', idx=dg_idx, value=dg_u_ams)
sa.RenGen.set(src='u', idx=rg_idx, value=rg_u_ams)
sa.SynGen.set(src='u', idx=syg_idx, attr='v', value=stg_u_ams)
sa.DG.set(src='u', idx=dg_idx, attr='v', value=dg_u_ams)
sa.RenGen.set(src='u', idx=rg_idx, attr='v', value=rg_u_ams)

Check warning on line 491 in ams/interop/andes.py

View check run for this annotation

Codecov / codecov/patch

ams/interop/andes.py#L489-L491

Added lines #L489 - L491 were not covered by tests
return True

def _sync_check(self, amsys, adsys):
Expand Down Expand Up @@ -568,7 +568,7 @@ def send(self, adsys=None, routine=None):
stg_idx = sp.StaticGen.get_idx()
bus_stg = sp.StaticGen.get(src='bus', attr='v', idx=stg_idx)
vBus = rtn.get(src='vBus', attr='v', idx=bus_stg)
sa.StaticGen.set(src='v0', attr='v', idx=stg_idx, value=vBus)
sa.StaticGen.set(src='v0', idx=stg_idx, attr='v', value=vBus)
logger.info(f'*Send <{vname_ams}> to StaticGen.v0')

# 1. gen online status; in TDS running, setting u is invalid
Expand Down Expand Up @@ -600,7 +600,7 @@ def send(self, adsys=None, routine=None):
if syg_mask.any():
logger.debug('Governor is not complete for SynGen.')
# --- pref ---
sa.TurbineGov.set(src='pref0', attr='v', idx=gov_idx, value=syg_ams)
sa.TurbineGov.set(src='pref0', idx=gov_idx, attr='v', value=syg_ams)

# --- DG: DG.pref0 ---
dg_idx = sp.dyn.link['dg_idx'].dropna().tolist() # DG idx
Expand All @@ -610,7 +610,7 @@ def send(self, adsys=None, routine=None):
# corresponding StaticGen pg in AMS
dg_ams = rtn.get(src='pg', attr='v', idx=stg_dg_idx)
# --- pref ---
sa.DG.set(src='pref0', attr='v', idx=dg_idx, value=dg_ams)
sa.DG.set(src='pref0', idx=dg_idx, attr='v', value=dg_ams)

# --- RenGen: seems unnecessary ---
# TODO: which models/params are used to control output and auxillary power?
Expand All @@ -625,7 +625,7 @@ def send(self, adsys=None, routine=None):

# --- other scenarios ---
if _dest_check(mname=mname_ads, pname=pname_ads, idx=idx_ads, adsys=sa):
mdl_ads.set(src=pname_ads, attr='v', idx=idx_ads, value=var_ams.v)
mdl_ads.set(src=pname_ads, idx=idx_ads, attr='v', value=var_ams.v)
logger.warning(f'Send <{vname_ams}> to {mname_ads}.{pname_ads}')
return True

Expand Down Expand Up @@ -695,8 +695,8 @@ def receive(self, adsys=None, routine=None, no_update=False):
idx=link['stg_idx'].values)
# NOTE: only update u if changed actually
u0_rtn = rtn.get(src=vname_ams, attr='v', idx=link['stg_idx'].values).copy()
rtn.set(src=vname_ams, attr='v', idx=link['stg_idx'].values, value=u_stg)
rtn.set(src=vname_ams, attr='v', idx=link['stg_idx'].values, value=u_dyg)
rtn.set(src=vname_ams, idx=link['stg_idx'].values, attr='v', value=u_stg)
rtn.set(src=vname_ams, idx=link['stg_idx'].values, attr='v', value=u_dyg)
u_rtn = rtn.get(src=vname_ams, attr='v', idx=link['stg_idx'].values).copy()
if not np.array_equal(u0_rtn, u_rtn):
pname_to_update.append(vname_ams)
Expand Down Expand Up @@ -733,8 +733,8 @@ def receive(self, adsys=None, routine=None, no_update=False):
# Sync StaticGen.p first, then overwrite the ones with dynamic generator
p_stg = sa.StaticGen.get(src='p', attr='v',
idx=link['stg_idx'].values)
rtn.set(src=vname_ams, attr='v', idx=link['stg_idx'].values, value=p_stg)
rtn.set(src=vname_ams, attr='v', idx=link['stg_idx'].values, value=p_dyg)
rtn.set(src=vname_ams, idx=link['stg_idx'].values, attr='v', value=p_stg)
rtn.set(src=vname_ams, idx=link['stg_idx'].values, attr='v', value=p_dyg)

pname_to_update.append(vname_ams)

Expand All @@ -749,7 +749,7 @@ def receive(self, adsys=None, routine=None, no_update=False):
# --- other scenarios ---
if _dest_check(mname=mname_ads, pname=pname_ads, idx=idx_ads, adsys=sa):
v_ads = mdl_ads.get(src=pname_ads, attr='v', idx=idx_ads)
rtn.set(src=vname_ams, attr='v', idx=idx_ads, value=v_ads)
rtn.set(src=vname_ams, idx=idx_ads, attr='v', value=v_ads)

Check warning on line 752 in ams/interop/andes.py

View check run for this annotation

Codecov / codecov/patch

ams/interop/andes.py#L752

Added line #L752 was not covered by tests
pname_to_update.append(vname_ams)
logger.warning(f'Receive <{vname_ams}> from {mname_ads}.{pname_ads}')

Expand Down
12 changes: 6 additions & 6 deletions ams/routines/dcopf.py
Original file line number Diff line number Diff line change
Expand Up @@ -312,9 +312,9 @@ def unpack(self, **kwargs):
pass
# NOTE: only unpack the variables that are in the model or group
try:
var.owner.set(src=var.src, attr='v', idx=idx, value=var.v)
var.owner.set(src=var.src, idx=idx, attr='v', value=var.v)
except (KeyError, TypeError):
logger.error(f'Failed to unpack {var.name} to {var.owner.name}')
logger.error(f'Failed to unpack <{var}> to <{var.owner.class_name}>.')

Check warning on line 317 in ams/routines/dcopf.py

View check run for this annotation

Codecov / codecov/patch

ams/routines/dcopf.py#L317

Added line #L317 was not covered by tests
pass

# label the most recent solved routine
Expand All @@ -340,16 +340,16 @@ def dc2ac(self, kloss=1.0, **kwargs):
pq_idx = self.system.StaticLoad.get_idx()
pd0 = self.system.StaticLoad.get(src='p0', attr='v', idx=pq_idx).copy()
qd0 = self.system.StaticLoad.get(src='q0', attr='v', idx=pq_idx).copy()
self.system.StaticLoad.alter(src='p0', idx=pq_idx, value=pd0 * kloss)
self.system.StaticLoad.alter(src='q0', idx=pq_idx, value=qd0 * kloss)
self.system.StaticLoad.set(src='p0', idx=pq_idx, attr='v', value=pd0 * kloss)
self.system.StaticLoad.set(src='q0', idx=pq_idx, attr='v', value=qd0 * kloss)

Check warning on line 344 in ams/routines/dcopf.py

View check run for this annotation

Codecov / codecov/patch

ams/routines/dcopf.py#L343-L344

Added lines #L343 - L344 were not covered by tests

ACOPF = self.system.ACOPF
# run ACOPF
ACOPF.run()
# self.exec_time += ACOPF.exec_time
# scale load back
self.system.StaticLoad.alter(src='p0', idx=pq_idx, value=pd0)
self.system.StaticLoad.alter(src='q0', idx=pq_idx, value=qd0)
self.system.StaticLoad.set(src='p0', idx=pq_idx, value=pd0)
self.system.StaticLoad.set(src='q0', idx=pq_idx, value=qd0)

Check warning on line 352 in ams/routines/dcopf.py

View check run for this annotation

Codecov / codecov/patch

ams/routines/dcopf.py#L351-L352

Added lines #L351 - L352 were not covered by tests
if not ACOPF.exit_code == 0:
logger.warning('<ACOPF> did not converge, conversion failed.')
# NOTE: mock results to fit interface with ANDES
Expand Down
2 changes: 1 addition & 1 deletion ams/routines/routine.py
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ def set(self, src: str, idx, attr: str = "v", value=0.0):
owner = self.__dict__[src].owner
src0 = self.__dict__[src].src
try:
res = owner.alter(src=src0, idx=idx, value=value)
res = owner.set(src=src0, idx=idx, attr=attr, value=value)
return res
except KeyError as e:
msg = f"Failed to set <{src0}> in <{owner.class_name}>. "
Expand Down
20 changes: 10 additions & 10 deletions ams/routines/rted.py
Original file line number Diff line number Diff line change
Expand Up @@ -199,20 +199,20 @@ def dc2ac(self, kloss=1.0, **kwargs):
pq_idx = self.system.StaticLoad.get_idx()
pd0 = self.system.StaticLoad.get(src='p0', attr='v', idx=pq_idx).copy()
qd0 = self.system.StaticLoad.get(src='q0', attr='v', idx=pq_idx).copy()
self.system.StaticLoad.alter(src='p0', idx=pq_idx, value=pd0 * kloss)
self.system.StaticLoad.alter(src='q0', idx=pq_idx, value=qd0 * kloss)
self.system.StaticLoad.set(src='p0', idx=pq_idx, attr='v', value=pd0 * kloss)
self.system.StaticLoad.set(src='q0', idx=pq_idx, attr='v', value=qd0 * kloss)
# preserve generator reserve
ACOPF = self.system.ACOPF
pmin = pmin0 + self.prd.v
pmax = pmax0 - self.pru.v
self.system.StaticGen.alter(src='pmin', idx=pr_idx, value=pmin)
self.system.StaticGen.alter(src='pmax', idx=pr_idx, value=pmax)
self.system.StaticGen.alter(src='p0', idx=pr_idx, value=self.pg.v)
self.system.StaticGen.set(src='pmin', idx=pr_idx, attr='v', value=pmin)
self.system.StaticGen.set(src='pmax', idx=pr_idx, attr='v', value=pmax)
self.system.StaticGen.set(src='p0', idx=pr_idx, attr='v', value=self.pg.v)
# run ACOPF
ACOPF.run()
# scale load back
self.system.StaticLoad.alter(src='p0', idx=pq_idx, value=pd0)
self.system.StaticLoad.alter(src='q0', idx=pq_idx, value=qd0)
self.system.StaticLoad.set(src='p0', idx=pq_idx, attr='v', value=pd0)
self.system.StaticLoad.set(src='q0', idx=pq_idx, attr='v', value=qd0)
if not ACOPF.exit_code == 0:
logger.warning('<ACOPF> did not converge, conversion failed.')
# NOTE: mock results to fit interface with ANDES
Expand All @@ -233,9 +233,9 @@ def dc2ac(self, kloss=1.0, **kwargs):
self.exec_time = exec_time

# reset pmin, pmax, p0
self.system.StaticGen.alter(src='pmin', idx=pr_idx, value=pmin0)
self.system.StaticGen.alter(src='pmax', idx=pr_idx, value=pmax0)
self.system.StaticGen.alter(src='p0', idx=pr_idx, value=p00)
self.system.StaticGen.set(src='pmin', idx=pr_idx, attr='v', value=pmin0)
self.system.StaticGen.set(src='pmax', idx=pr_idx, attr='v', value=pmax0)
self.system.StaticGen.set(src='p0', idx=pr_idx, attr='v', value=p00)

# --- set status ---
self.system.recent = self
Expand Down
2 changes: 1 addition & 1 deletion ams/routines/uc.py
Original file line number Diff line number Diff line change
Expand Up @@ -307,7 +307,7 @@ def _initial_guess(self):
off_gen = f'{g_idx}'
else:
off_gen = ', '.join(g_idx)
self.system.StaticGen.set(src='u', attr='v', idx=g_idx, value=ug0)
self.system.StaticGen.set(src='u', idx=g_idx, attr='v', value=ug0)
logger.warning(f"As initial commitment guess, turn off StaticGen: {off_gen}")
return g_idx

Expand Down
40 changes: 20 additions & 20 deletions examples/demonstration/demo_AGC.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -450,8 +450,8 @@
" columns=out_cols)\n",
"\n",
"# --- AMS settings ---\n",
"sp.SFR.alter(src='du', idx=sp.SFR.idx.v, value=0.0015*np.ones(sp.SFR.n))\n",
"sp.SFR.alter(src='dd', idx=sp.SFR.idx.v, value=0.0015*np.ones(sp.SFR.n))\n",
"sp.SFR.set(src='du', idx=sp.SFR.idx.v, value=0.0015*np.ones(sp.SFR.n))\n",
"sp.SFR.set(src='dd', idx=sp.SFR.idx.v, value=0.0015*np.ones(sp.SFR.n))\n",
"\n",
"# --- ANDES settings ---\n",
"sa.TDS.config.no_tqdm = True # turn off ANDES progress bar\n",
Expand All @@ -464,13 +464,13 @@
"# NOTE: might run into error if there exists a TurbineGov model that does not have \"VMAX\"\n",
"tbgov_src = [mdl.idx.v for mdl in sa.TurbineGov.models.values()]\n",
"tbgov_idx = list(chain.from_iterable(tbgov_src))\n",
"sa.TurbineGov.alter(src='VMAX', idx=tbgov_idx,\n",
"sa.TurbineGov.set(src='VMAX', idx=tbgov_idx,\n",
" value=9999 * np.ones(sa.TurbineGov.n),)\n",
"sa.TurbineGov.alter(src='VMIN', idx=tbgov_idx,\n",
"sa.TurbineGov.set(src='VMIN', idx=tbgov_idx,\n",
" value=np.zeros(sa.TurbineGov.n),)\n",
"syg_src = [mdl.idx.v for mdl in sa.SynGen.models.values()]\n",
"syg_idx = list(chain.from_iterable(syg_src))\n",
"sa.SynGen.alter(src='ra', idx=syg_idx,\n",
"sa.SynGen.set(src='ra', idx=syg_idx,\n",
" value=np.zeros(sa.SynGen.n),)\n",
"\n",
"# use constant power model for PQ\n",
Expand Down Expand Up @@ -664,8 +664,8 @@
" # use 5-min average load in dispatch solution\n",
" load_avg = load_coeff[t:t+RTED_interval].mean()\n",
" # set load in to AMS\n",
" sp.PQ.alter(src='p0', idx=pq_idx, value=load_avg * p0_sp)\n",
" sp.PQ.alter(src='q0', idx=pq_idx, value=load_avg * q0_sp)\n",
" sp.PQ.set(src='p0', idx=pq_idx, value=load_avg * p0_sp)\n",
" sp.PQ.set(src='q0', idx=pq_idx, value=load_avg * q0_sp)\n",
" print(f\"--AMS: update disaptch load with factor {load_avg:.6f}.\")\n",
"\n",
" # get dynamic generator output from TDS\n",
Expand Down Expand Up @@ -703,17 +703,17 @@
"\n",
" # set into governor, Exclude NaN values for governor index\n",
" gov_to_set = {gov: pgov for gov, pgov in zip(maptab['gov_idx'], maptab['pgov']) if bool(gov)}\n",
" sa.TurbineGov.alter(src='pref0', idx=list(gov_to_set.keys()), value=list(gov_to_set.values()))\n",
" sa.TurbineGov.set(src='pref0', idx=list(gov_to_set.keys()), value=list(gov_to_set.values()))\n",
" print(f\"--ANDES: update TurbineGov reference.\")\n",
"\n",
" # set into dg, Exclude NaN values for dg index\n",
" dg_to_set = {dg: pdg for dg, pdg in zip(maptab['dg_idx'], maptab['pdg']) if bool(dg)}\n",
" sa.DG.alter(src='pref0', idx=list(dg_to_set.keys()), value=list(dg_to_set.values()))\n",
" sa.DG.set(src='pref0', idx=list(dg_to_set.keys()), value=list(dg_to_set.values()))\n",
" print(f\"--ANDES: update DG reference.\")\n",
"\n",
" # set into rg, Exclude NaN values for rg index\n",
" rg_to_set = {rg: prg for rg, prg in zip(maptab['rg_idx'], maptab['prg']) if bool(rg)}\n",
" sa.RenGen.alter(src='Pref', idx=list(rg_to_set.keys()), value=list(rg_to_set.values()))\n",
" sa.RenGen.set(src='Pref', idx=list(rg_to_set.keys()), value=list(rg_to_set.values()))\n",
" print(f\"--ANDES: update RenGen reference.\")\n",
"\n",
" # record dispatch data\n",
Expand Down Expand Up @@ -745,22 +745,22 @@
"\n",
" # set into governor, Exclude NaN values for governor index\n",
" agov_to_set = {gov: agov for gov, agov in zip(maptab['gov_idx'], maptab['agov']) if bool(gov)}\n",
" sa.TurbineGov.alter(src='paux0', idx=list(agov_to_set.keys()), value=list(agov_to_set.values()))\n",
" sa.TurbineGov.set(src='paux0', idx=list(agov_to_set.keys()), value=list(agov_to_set.values()))\n",
"\n",
" # set into dg, Exclude NaN values for dg index\n",
" adg_to_set = {dg: adg for dg, adg in zip(maptab['dg_idx'], maptab['adg']) if bool(dg)}\n",
" sa.DG.alter(src='Pext0', idx=list(adg_to_set.keys()), value=list(adg_to_set.values()))\n",
" sa.DG.set(src='Pext0', idx=list(adg_to_set.keys()), value=list(adg_to_set.values()))\n",
"\n",
" # set into rg, Exclude NaN values for rg index\n",
" arg_to_set = {rg: arg + prg for rg, arg,\n",
" prg in zip(maptab['rg_idx'], maptab['arg'], maptab['prg']) if bool(rg)}\n",
" sa.RenGen.alter(src='Pref', idx=list(arg_to_set.keys()), value=list(arg_to_set.values()))\n",
" sa.RenGen.set(src='Pref', idx=list(arg_to_set.keys()), value=list(arg_to_set.values()))\n",
"\n",
" # --- TDS interval ---\n",
" if t > 0: # --- run TDS ---\n",
" # set laod into PQ.Ppf and PQ.Qpf\n",
" sa.PQ.alter(src='Ppf', idx=pq_idx, value=load_coeff[t] * p0_sa)\n",
" sa.PQ.alter(src='Qpf', idx=pq_idx, value=load_coeff[t] * q0_sa)\n",
" sa.PQ.set(src='Ppf', idx=pq_idx, value=load_coeff[t] * p0_sa)\n",
" sa.PQ.set(src='Qpf', idx=pq_idx, value=load_coeff[t] * q0_sa)\n",
" sa.TDS.config.tf = t\n",
" sa.TDS.run()\n",
" # Update AGC PI controller\n",
Expand All @@ -785,16 +785,16 @@
" break\n",
" else: # --- init TDS ---\n",
" # set pg to StaticGen.p0\n",
" sa.StaticGen.alter(src='p0', idx=sp.RTED.pg.get_idx(), value=sp.RTED.pg.v)\n",
" sa.StaticGen.set(src='p0', idx=sp.RTED.pg.get_idx(), attr='v', value=sp.RTED.pg.v)\n",
" # set Bus.v to StaticGen.v\n",
" bus_stg = sp.StaticGen.get(src='bus', attr='v', idx=sp.StaticGen.get_idx())\n",
" v_stg = sp.Bus.get(src='v', attr='v', idx=bus_stg)\n",
" sa.StaticGen.alter(src='v0', idx=sp.StaticGen.get_idx(), value=v_stg)\n",
" sa.StaticGen.set(src='v0', idx=sp.StaticGen.get_idx(), attr='v', value=v_stg)\n",
" # set vBus to Bus\n",
" sa.Bus.alter(src='v0', idx=sp.RTED.vBus.get_idx(), value=sp.RTED.vBus.v)\n",
" sa.Bus.set(src='v0', idx=sp.RTED.vBus.get_idx(), attr='v', value=sp.RTED.vBus.v)\n",
" # set load into PQ.p0 and PQ.q0\n",
" sa.PQ.alter(src='p0', idx=pq_idx, value=load_coeff[t] * p0_sa)\n",
" sa.PQ.alter(src='q0', idx=pq_idx, value=load_coeff[t] * q0_sa)\n",
" sa.PQ.set(src='p0', idx=pq_idx, attr='v', value=load_coeff[t] * p0_sa)\n",
" sa.PQ.set(src='q0', idx=pq_idx, attr='v', value=load_coeff[t] * q0_sa)\n",
" sa.PFlow.run() # run power flow\n",
" sa.TDS.init() # initialize TDS\n",
"\n",
Expand Down
4 changes: 2 additions & 2 deletions tests/test_interop.py
Original file line number Diff line number Diff line change
Expand Up @@ -158,8 +158,8 @@ def test_data_exchange(self):
no_output=True,
default_config=True,)
# alleviate limiter
sa.TGOV1.set(src='VMAX', attr='v', idx=sa.TGOV1.idx.v, value=100*np.ones(sa.TGOV1.n))
sa.TGOV1.set(src='VMIN', attr='v', idx=sa.TGOV1.idx.v, value=np.zeros(sa.TGOV1.n))
sa.TGOV1.set(src='VMAX', idx=sa.TGOV1.idx.v, attr='v', value=100*np.ones(sa.TGOV1.n))
sa.TGOV1.set(src='VMIN', idx=sa.TGOV1.idx.v, attr='v', value=np.zeros(sa.TGOV1.n))

# --- test before PFlow ---
self.sp.dyn.send(adsys=sa, routine='RTED')
Expand Down
4 changes: 2 additions & 2 deletions tests/test_rtn_dcopf.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ def test_trip_gen(self):
Test generator tripping.
"""
stg = 'PV_1'
self.ss.StaticGen.set(src='u', attr='v', idx=stg, value=0)
self.ss.StaticGen.set(src='u', idx=stg, attr='v', value=0)

self.ss.DCOPF.update()
self.ss.DCOPF.run(solver='CLARABEL')
Expand All @@ -35,7 +35,7 @@ def test_trip_gen(self):
0, places=6,
msg="Generator trip does not take effect!")

self.ss.StaticGen.alter(src='u', idx=stg, value=1) # reset
self.ss.StaticGen.set(src='u', idx=stg, attr='v', value=1) # reset

def test_trip_line(self):
"""
Expand Down
Loading

0 comments on commit afc4626

Please sign in to comment.