Ask Your Question

GaryB's profile - activity

2023-04-20 16:56:21 -0500 answered a question shift factor
  1. Solve the case and record the MW transfer across a line.
  2. Add 1 MW of load (or generation) on a bus and solve the case again.
  3. Record the MW transfer again.

Shift factor is the difference in flow divided by the load/gen change.

sf = (MW1 - MW2) / (load [or gen] change)

The signs matter as shift factor may be negative or positive.

Example: If you have 100 MW flowing on a line, and you add 1 MW of generation at a particular bus. You now have 100.23 MW flowing on the line, the shift factor is (100.23 - 100) / 1 = 23%.

2023-04-20 16:34:40 -0500 commented question Initial Conditions Suspects

Have you checked the log file for warnings on the CMLD models? These types of messages may exist: At bus 4, CMLD load bus voltage of 0.9471 pu is below 0.95 minimum. Original feeder Z of 0.2295 +j 0.2295 pu on SBASE will be reduced in an attempt to bring V up above 0.95 pu

2023-04-19 19:40:57 -0500 answered a question Initial Conditions Suspects

Start with a problem and try to isolate it. You can disable the other models to get it down to one DSTATE issue.

In the GGOV1 model, find state 2 in a diagram. That’s the differential control. Check RSELECT and other parameters upstream of State 2.

Change RSELECT to zero to try and isolate that circuit.

Manipulate r.

Check State 8. Plot it. If it’s stable, the problem is somewhere else.

I hope you know some control theory.

Move on to the next model. Some DSTATE issues can be tolerated.

It’s not easy. Good luck.

2023-04-19 19:18:48 -0500 commented answer GGOV1 model can I switch from droop to isoc mode in the simulation

Can you please select the answer that worked for others to know how to fix this?

2023-04-14 16:24:42 -0500 commented answer GGOV1 model can I switch from droop to isoc mode in the simulation

It should work; the speed circuit should always be active and working regardless of rselect. The only other thing I would try is to set R=0 (or something small) in the psas file if possible. This should logically do the same thing. Please post if you figure it out.

2023-04-14 09:47:31 -0500 commented answer GGOV1 model can I switch from droop to isoc mode in the simulation

Does it work if it's initialized in ISOC mode?

2023-04-14 08:57:51 -0500 answered a question GGOV1 model can I switch from droop to isoc mode in the simulation

I can't say I know much about GGOV1, but you can change the Rselect or any other ICON with BATCHANGEPLMODICON.

PASSTHRU
BAT_CHANGE_PLMOD_ICON,<busno>,'<unitID>','GGOV1',1,0
FIN

will change RSELECT to '0' inside a PSAS file.

2023-04-14 08:42:00 -0500 commented answer creating a new bus

ChatGPT is better suited to help you with your homework.

2023-02-28 22:01:36 -0500 answered a question when it's a good idea to use Prony analysis?

It’s good to use Prony Analysis if your angle damping rate is difficult or impossible to read.

Some areas can have multiple generators swinging together with different damping rates and natural frequencies. The superposition of these swings can yield rotor angles that don’t resemble a damped sine wave. Prony is a method to decompose the angles into individual damped (ideally) waves with a damping rate for each each component.

2023-02-19 18:53:20 -0500 answered a question create snap file snp

There should be some documentation in this. 1. Load the sav case. 2. Convert the loads and generators. 4. You can save the converted case. 5. Load the dyr file. 6. Initialize the case. 7. You can now save the .snp file. This saves the initialized snapshot before any simulation has occurred.

This is brief. There are tutorials on YouTube. I would look for a tutorial walking you through using the savenw file provided as an example with PSSE.

2022-11-09 06:15:48 -0500 answered a question How to use psspy inside a function??

Another option is to pass psspy into the function:

def TS1_S1_LOADRELIEF(psspy):
2022-06-13 06:05:56 -0500 commented question I need information about how to create a model for a steel factory by pss/e and running harmonic data from it?

I would look at doing an EMTP model with PSCAD or something similar.

2022-05-05 19:54:05 -0500 answered a question Voltage Negative Sequence in dynamic studies

The dynamic models are positive sequence only. It's possible to run unbalanced fault (at least SLG), but PSSE still only simulates the positive sequence. You cannot read negative sequence values because they aren't simulated.

I assume short-circuit analysis simulates negative and zero sequences. The detrimental effects of negative sequence happen during a fault. I would use short-circuit analysis and known breaker timings.

2022-05-05 19:28:19 -0500 answered a question dyntools.CHNF() causes python to crash. Help!

Try this:

import multiprocessing as mp
def load_out(out_file,q):
    try:
        chnfobj = dyntools.CHNF(out_file,outvrsn=0)
    except TypeError:
        chnfobj = None
    q.put(chnfobj)

q = mp.Queue() #load the .out in a separate process 
p = mp.Process(target=load_out, args = (out_file,q,))
p.start()
chnfobj = q.get()

It runs in a subprocess and doesn't collide with psspy.

Note that there is no p.join() function; it hangs indefinitely. There is probably a way to garbage collect or pass data rather than the chnf obj back. But this works for me.

2021-07-01 21:25:34 -0500 received badge  Enthusiast
2021-06-23 20:04:20 -0500 answered a question Understanding dynamic models

The WECC has pretty good resources on the internet. Also googling these models will help find other sources. Dynamics and controls books can help with fundamentals.

2021-06-23 20:01:06 -0500 answered a question Are there any methods to improve the speed of batch dynamic simulations?

0.01s seems long. We run 1/4 cycle time steps.

2021-06-23 19:58:27 -0500 answered a question How do I capture skipped contingencies in contingency analysis automation?

Parsing the log file is probably the best way. Also you will end up with zero length .out files that may also be used to detect such a condition.

Be advised, some simulations may halt and not terminate causing your script to hang up. I use python multiprocessing to launch each dynamics run in its own process. While running, I monitor the file sizes of the .out and .log files. If they stop growing larger and the case is still running, it gets terminated. An ever increasing size of these two files means it’s still working.

2020-12-07 11:44:47 -0500 answered a question Running "Compile" and "Cload4" from python

Try this:

import subprocess

runstr = r'"C:\Windows\SysWOW64\cmd.exe" /k '\
    r'"C:\Program Files (x86)\PTI\PSSE32\SET_PSSE_PATH.BAT"'\
    r'& compile.bat'

def open_app():
    p=subprocess.call(runstr)
open_app()
2020-12-07 11:11:09 -0500 answered a question Retrieving bus numbers in order of connection

Just an idea, the attached code can be run in PSSE to get the shortest path between two buses. If you use your slack bus as one, and the queried bus as the other, the length of the result will be your path length. It is feasible to step through your buses and save the path lengths for each and sort. It is computationally expensive however.

# Delivers shortest path (miles) between two buses
# The two buses must be the same voltage level (the script cannot see past transformers)

# Can't default to swing bus for everything if it's a different voltage level than bus1.


from collections import defaultdict

class Graph():
    def __init__(self):
        """
        self.edges is a dict of all possible next nodes e.g. {'X': ['A', 'B', 'C', 'E'], ...}
        self.weights has all the weights between two nodes, with the two nodes as a tuple as the key
        e.g. {('X', 'A'): 7, ('X', 'B'): 2, ...}
        """
        self.edges = defaultdict(list)
        self.weights = {}
    def add_edge(self, from_node, to_node, weight):
        # Note: assumes edges are bi-directional
        self.edges[from_node].append(to_node)
        self.edges[to_node].append(from_node)
        self.weights[(from_node, to_node)] = weight
        self.weights[(to_node, from_node)] = weight

def dijsktra(graph, initial, end):
    # shortest paths is a dict of nodes whose value is a tuple of (previous node, weight)
    shortest_paths = {initial: (None, 0)}
    current_node = initial
    visited = set()
    while current_node != end:
        visited.add(current_node)
        jbus = 1
        ierr = psspy.inibrn(current_node,2)
        # nxtbrn provides neighboring buses until all have been provided. Then it returns jbus = 0
        while jbus > 0:
            ierr, jbus, kbus, ickt = psspy.nxtbrn3(current_node)
            if jbus > 0:
                # Get the length of the line between these two buses (in miles)
                ierr, weight = psspy.brndat(current_node,jbus,ickt,'LENGTH') # gives the literal shortest path
                weight = 1.0 #override weight to minimize the number of bus hops (longer line miles)
                if weight is None:
                    weight=0.0
                edge = (current_node,jbus,weight)
                # Add this edge to the graph if it's not there already
                if edge not in graph.edges:
                    graph.add_edge(*edge)
        # Destinations: all the buses we can go to from the bus we're currently at
        destinations = graph.edges[current_node]
        # weight_to_current_node: how far we've travelled so far to get to this node
        weight_to_current_node = shortest_paths[current_node][1]

        for next_node in destinations:
            weight = graph.weights[(current_node, next_node)] + weight_to_current_node
            if next_node not in shortest_paths:
                shortest_paths[next_node] = (current_node, weight)
            else:
                current_shortest_weight = shortest_paths[next_node][1]
                if current_shortest_weight > weight:
                    shortest_paths[next_node] = (current_node, weight)
        # Don't visit the same node twice. This would lead to an infinite loop
        next_destinations = {node: shortest_paths[node] for node in shortest_paths if node not in visited}

        if not next_destinations:
            return "Route Not Possible"
        # next node is the destination with the lowest weight
        current_node = min(next_destinations, key = lambda k: next_destinations[k][1])

    # Work back through destinations in shortest path
    path = []
    while current_node is not None:
        path.append(current_node)
        next_node = shortest_paths[current_node][0]
        current_node = next_node
    # Reverse path
    path = path[::-1]
    return path

if __name__ == '__main__':                                    ## Main program!!!
    # cases = glob.glob("*.sav")
    # case = cases[0]
    # ierr = psspy.case(case ...
(more)
2020-12-07 10:56:25 -0500 answered a question how do you run multiple dynamic contingency idevs using python

The way we do it is complicated but bulletproof. In short, use the multiprocessing Module to run the simulations. You will need to put your run script into a function so that you can pass that function to multiprocessing. Please see the code below. The .Process() function starts the simulation by passing the next faultidev to the Function rundynsim(). I have a 28 core machine, so I load up 36 processes and let the multi-threading engine handle the balancing. This is set with the numprocesses Variable. If you want to run sequentially, you can use numprocesses=1.

    while fault_idevs:
    # if we aren't using all the processors AND there is still data left to
    # compute, then spawn another thread
    #Create a new thread if we haven't used all available to us.  Only create 
    #   one per sleep cycle.
    if( len(threads) < num_processes):    
        fault_being_executed = fault_idevs[0]       # Strings passed by value
        p = multiprocessing.Process(target=run_dynsim, args=[cnvcase, snap, fault_idevs.pop(0), lock, generic_VTG])
        p.start()
        print p, p.is_alive()
        threads.append(p)
        # Set us up a dictionary of running processes and some info so that we can 
        #  check to see if they have stalled
        running_processes[p.pid] = {'Fault_Name': fault_being_executed, 'Log_Size': 0, 'Out_Size': 0, 'Num_Stalls': 0, 'Start_Time': datetime.now()}
    else:
        for thread in threads:                        # Remove any threads that have finished
            if not thread.is_alive():
                del running_processes[thread.pid]
                threads.remove(thread)
                print 'REMOVING A THREAD'
    time.sleep(4)                                    
    # Let's check on our processes every minute
    stalled_process_check(running_processes, threads, lock, 60, len(fault_idevs), True)

To answer the main part of your question, running them in separate processes allows you to check and see if they are still working. If not, terminate them and move on. Some of mine can take more than 30 minutes to complete.

See the function below. The gist of it is to check the length of the log file and out Files; and if they aren't changing, terminate the process. The os.stat Functions make a call to get file sizes. These get stored and compared with the next stalled process check. This gets run every minute, so hung processes will be terminated within about three minutes. (The allowed number of stalls below is set to one, so it will terminate a minute after detection.)

# =============================================================================
# Function stalled_process_check
# Input: running_processes - the list of known running processes
#        threads - the list of threads being run by multiprocessing
#        lock - file lock for writing a status update to file
#        update_seconds - How often to actually run the main routine in this
#                         function
#        no_of_waiting - number of processes to queue or threads that are 
#                        waiting at the end
#        still_queueing - Status of whether there are more threads
#  Operation: This code loop through running_processes and save .log and 
#             .out file sizes.  If they don't change, it will record a stall.
#             If it hasn't changed the next time either, it will terminate the 
#             thread and let other code do the garbage collection. There is a 
#             status update at the end.
#  Output: Operates ...
(more)
2020-09-04 21:47:00 -0500 answered a question what is the best way to get started in PSSE, Python?

This is how I do it:

Assuming you can run Python programs currently and you want to run from the command line.

I can't post links, so I had to change this to be more complicated. There is a clever way to put the bulky path stuff in the beginning into a library. This should work with PSSE 33 or 34.

Modify with filenames and try and run this code, preferably from one of the Command Line file links provided by PTI with PSSE (in the PSSE34 Folder on the Start Menu):

import _winreg
import sys
import os
# Add the PSS/E directories to our Windows path variable so we can load in the PSS/E Python libraries that are available there


if 'PSSE34' in os.getenv('PATH'):
    print('PSSE 34 detected')
    try:
        pssepath, regtype = _winreg.QueryValueEx(_winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE, "SOFTWARE\\PTI\\PSSE 34\\Product Paths", 0, _winreg.KEY_READ), "PsseInstallPath")
    except WindowsError:
        pssepath, regtype = _winreg.QueryValueEx(_winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE, "SOFTWARE\\\Wow6432Node\\PTI\\PSSE 34\\Product Paths", 0, _winreg.KEY_READ), "PsseInstallPath")
    sys.path.append(os.path.join(pssepath, 'PSSBIN'))
    sys.path.append(os.path.join(pssepath, 'PSSLIB'))
    sys.path.append(os.path.join(pssepath, 'PSSPY27'))
    os.environ['PATH'] += ';' + os.path.join(pssepath, 'PSSBIN')
    os.environ['PATH'] += ';' + os.path.join(pssepath, 'PSSLIB')
    os.environ['PATH'] += ';' + os.path.join(pssepath, 'PSSPY27')
else:
    try:
        pssepath, regtype = _winreg.QueryValueEx(_winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE, "SOFTWARE\\PTI\\PSSE 33\\Product Paths", 0, _winreg.KEY_READ), "PsseInstallPath")
    except WindowsError:
        pssepath, regtype = _winreg.QueryValueEx(_winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE, "SOFTWARE\\\Wow6432Node\\PTI\\PSSE 33\\Product Paths", 0, _winreg.KEY_READ), "PsseInstallPath")
    sys.path.append(os.path.join(pssepath, 'PSSBIN'))
    sys.path.append(os.path.join(pssepath, 'PSSLIB'))
    os.environ['PATH'] += ';' + os.path.join(pssepath, 'PSSBIN')
    os.environ['PATH'] += ';' + os.path.join(pssepath, 'PSSLIB')

import psspy
import redirect

redirect.psse2py()

psspy.psseinit(150000)

case = r'your_save_case.sav'
resp = r'your_resp_file.idv'

psspy.case(case) #load the case
psspy.runrspnsfile(resp) #run an idev 
psspy.asys(0,1,[330]) #build a subsystem
psspy.area_2(0,0,1) #load/gen report on that subsystem

If it works, use the API in the documentation to build your own code.

You will likely get an error if you don't have certain Python packages installed. You will need to install these using PIP. (Google 'pip install'.)

You can also use the Recorder in the GUI to build .py code like you would .idv files.

2020-06-01 08:08:16 -0500 answered a question Short circuit equivalent generator

You should know at a minimum the system contribution to three-phase faults (magnitude and angle) and line-to-ground faults. With these, you can use what's in a power system analysis book to derive what you need. You also should consider transient and sub-transient responses and some way to optimize other model parameters to reflect that of the system you're modelling.

2020-06-01 08:00:13 -0500 answered a question REPCTA1 model in PSSE

There should be a documentation folder with PSSE or in the Start Menu. What you are looking for is in there.

2019-10-30 21:38:09 -0500 commented question Philosophy for choosing channels to plot

Pro tip: Match the colors so the same bus has the same colors for different plots such as angle and voltage. It may be difficult.

2019-10-30 21:36:16 -0500 commented question Philosophy for choosing channels to plot

1. Save an uninitialized snapshot then code the channel additions with chsb after you load the snapshot. When complete initialize then run your case. 2. Use matplotlib manual and automatic plot functions to get it like you want it. From experience, about 10 plots per page is reasonable.

2019-10-22 19:42:15 -0500 commented answer dyntools.CHNF TypeError: sequence item 0: expected string, int found

By the way, when things to do with file access abruptly stop working, it’s often a file permissions issue. I don’t know about your situation but just a thought.

2019-10-22 19:20:25 -0500 received badge  Editor (source)
2019-10-22 19:19:32 -0500 answered a question dyntools.CHNF TypeError: sequence item 0: expected string, int found

It says sequence item 0 which may be the first argument. I think there’s an issue with setting outfile higher in the code. Check the variable type of it, should be string like it says. I think outvrsn looks fine for 33.12.

2019-07-07 08:43:52 -0500 answered a question Are there any models in PSSE which can model nuclear generators?

Since the steam source is not modeled in PSSE, use typical steam turbine/governor models. If your unit is a cross compound type it will be a little trickier, and you’ll need to research or post this question separately. If your unit runs with no governor or a valves-wide-open mode, then you may remove the governor model in some cases.