I think for this application it would be best to write a custom USRMDL
in Fortran. This is probably more work if you don't know Fortran, but it has the benefit of running in real time and would probably be the most accurate simulation you could achieve.
Another option that I have never tested but may be worth looking at is to try using the CHNVAL
function. Pause the simulation at any timestep you would like, check the channel values of your choice, then make any decisions based on that. From the API:
7.24 CHNVAL Use this API to return the present value of the simulation
variable assigned to a specified
output channel. Python syntax: ierr,
rval = chnval(n)
You could also post process, like JervisW suggests.
UPDATE
I am not exactly sure what 'angle spread' is, so here is some Fortran code of my interpretation. I assumed it meant measure the bus angle between two buses, if it reached a certain value, then trip a generator. This code trips a bus, not a generator. I am not very experienced with Fortran, and I don't really know PSS/e internal variables and calls that well, but the following code does trip a generator bus if the angle spread between two buses goes above specified threshold.
FORTRAN:
SUBROUTINE TRIPGEN(II,JJ,KK,LL)
INCLUDE 'COMON4.INS'
C ICON(II)=BUS 1
C ICON(II+1)=BUS 2
C ICON(II+2)=BUS 1 INTERNAL ID
C ICON(II+3)=BUS 2 INTERNAL ID
C ICON(II+4)=GEN BUS TO TRIP
C ICON(II+5)=GEN BUS INTERNAL ID
C ICON(II+6)=RUN FLAG (1=RUN, 0=DON'T RUN)
C CON(JJ)=SPREAD VALUE
REAL*4 ANGA, ANGB
INTEGER*4 IERR
C INIT CODE HERE
IF ( MODE .EQ. 1 .OR. KPAUSE .EQ. 2 ) THEN
IF (IFLAG) THEN
CALL BSSEQN(ICON(II+4),ICON(II+5),*7)
1 CALL BSSEQN(ICON(II),ICON(II+2),*8)
2 CALL BSSEQN(ICON(II+1),ICON(II+3),*9)
GO TO 100
7 WRITE ( ITERM, * ) 'BUS NUMBER ', ICON(II+4), ' NOT FOUND'
ICON(II+6)=0
GO TO 1
8 WRITE ( ITERM, * ) 'BUS NUMBER ', ICON(II), ' NOT FOUND'
ICON(II+6)=0
GO TO 2
9 WRITE ( ITERM, * ) 'BUS NUMBER ', ICON(II+1), ' NOT FOUND'
ICON(II+6)=0
ENDIF
10 ENDIF
C ONLY CALCULATE IF SOLUTION CONVERGED
IF (IFLAG) THEN
GO TO 50
ELSE
GO TO 100
ENDIF
C RETURN IF ERROR IN BUS NUMBERS
50 IF (ICON(II+6) .EQ. 0) THEN
GO TO 100
ENDIF
C RUN CODE HERE
IF (MODE .EQ. 2) THEN
CALL BUSDAT(ICON(II),'ANGLED',ANGA,IERR)
CALL BUSDAT(ICON(II+1),'ANGLED',ANGB,IERR)
ANGSPRD = ABS(ANGA-ANGB)
C WRITE ( ITERM, * ) 'ANGLE SPREAD IS = ', ANGSPRD !USED FOR DEBUG
IF (ANGSPRD .GT. CON(JJ)) THEN
CALL BSDSCN(ICON(II+4))
WRITE ( ITERM, * ) 'ANGLE SPREAD REACHED TOLERANCE, BUS ', ICON(II+4), ' TRIPPED'
ICON(II+6)=0
ENDIF
ENDIF
100 RETURN
END
And here would be ...
(more)