Beispiel #1
0
class PVDERModel:
    def __init__(self):
        self._pvModel = {}
        self._sim = {}
        self._lastSol = {}
        self._lastT = 0

    def setup(self, nodeid):
        try:
            VpuInitial = 1.0
            SinglePhase = False

            if 'myconfig' in OpenDSSData.config and 'DERParameters' in OpenDSSData.config[
                    'myconfig']:
                if 'DERParameters' in OpenDSSData.config['myconfig']:
                    pvderConfig = OpenDSSData.config['myconfig'][
                        'DERParameters']
                    power_rating = OpenDSSData.config['myconfig'][
                        'DERParameters']['power_rating'] * 1e3
                    voltage_rating = OpenDSSData.config['myconfig'][
                        'DERParameters']['voltage_rating']
                    SteadyState = OpenDSSData.config['myconfig'][
                        'DERParameters']['SteadyState']

                if 'nodenumber' in OpenDSSData.config['myconfig']:
                    DER_location = str(os.getpid()) + '-' + 'bus_' + str(
                        OpenDSSData.config['myconfig']
                        ['nodenumber']) + '-' + 'node_' + nodeid
                else:
                    DER_location = str(os.getpid()) + '-' + 'node_' + nodeid

            else:
                print(
                    'DERParameters not found in `OpenDSSData` object - using default ratings and parameters!'
                )
                pvderConfig = None
                SteadyState = True
                DER_location = 'node_' + nodeid

                if SinglePhase:
                    power_rating = 10.0e3
                else:
                    power_rating = 50.0e3

            Va = (.50 + 0j) * Grid.Vbase
            Vb = (-.25 - .43301270j) * Grid.Vbase
            Vc = (-.25 + .43301270j) * Grid.Vbase

            events = SimulationEvents()

            if SinglePhase:
                self.PV_model = PV_model = SolarPV_DER_SinglePhase(
                    events=events,
                    Sinverter_rated=power_rating,
                    Vrms_rated=voltage_rating,
                    gridVoltagePhaseA=Va * VpuInitial,
                    gridVoltagePhaseB=Vb * VpuInitial,
                    gridVoltagePhaseC=Vc * VpuInitial,
                    gridFrequency=2 * math.pi * 60.0,
                    standAlone=False,
                    STEADY_STATE_INITIALIZATION=SteadyState,
                    pvderConfig=pvderConfig,
                    identifier=DER_location)
            else:
                self.PV_model = PV_model = SolarPV_DER_ThreePhase(
                    events=events,
                    Sinverter_rated=power_rating,
                    Vrms_rated=voltage_rating,
                    gridVoltagePhaseA=Va * VpuInitial,
                    gridVoltagePhaseB=Vb * VpuInitial,
                    gridVoltagePhaseC=Vc * VpuInitial,
                    gridFrequency=2 * math.pi * 60.0,
                    standAlone=False,
                    STEADY_STATE_INITIALIZATION=SteadyState,
                    pvderConfig=pvderConfig,
                    identifier=DER_location)

            self.PV_model.LVRT_ENABLE = True  #Disconnects PV-DER based on ride through settings in case of voltage anomaly
            self.sim = DynamicSimulation(PV_model=PV_model,
                                         events=events,
                                         LOOP_MODE=True,
                                         COLLECT_SOLUTION=True)
            self.sim.jacFlag = True  #Provide analytical Jacobian to ODE solver
            self.sim.DEBUG_SOLVER = False  #Check whether solver is failing to converge at any step

            self.results = SimulationResults(simulation=self.sim,
                                             PER_UNIT=True)

            self.lastSol = copy.deepcopy(self.sim.y0)  # mutable,make copy
            self.lastT = 0
        except Exception as e:
            OpenDSSData.log("Failed Setup PVDER at node:{}!".format(nodeid))

    def prerun(self, gridVoltagePhaseA, gridVoltagePhaseB, gridVoltagePhaseC):
        """Prerun will set the required data in pvder model. This method should be run before
        running the integrator."""
        try:
            # set grid voltage. This value will be kept constant during the run
            # as opendss will sync will grid_simulation only once during the run call.
            # opendss will solve power flow and will set gridVoltagePhase value.
            self.PV_model.gridVoltagePhaseA = gridVoltagePhaseA * math.sqrt(
                2) / Grid.Vbase
            self.PV_model.gridVoltagePhaseB = gridVoltagePhaseB * math.sqrt(
                2) / Grid.Vbase
            self.PV_model.gridVoltagePhaseC = gridVoltagePhaseC * math.sqrt(
                2) / Grid.Vbase
            self.sim.t = self.lastT + 1 / 120.0

            return None
        except Exception as e:
            OpenDSSData.log("Failed prerun in the pvder model")

    def postrun(self, sol, t, KVAbase=50):
        """Postrun will gather results. This method should be run after running the integrator."""
        try:
            if self.sim.COLLECT_SOLUTION:
                self.sim.collect_solution(sol, t)

            #np array is mutable, hence make a copy
            self.lastSol = copy.deepcopy(sol[-1])
            self.lastT = t[-1]

            # get S
            S = self._getS()

            return S * KVAbase
        except Exception as e:
            OpenDSSData.log("Failed postrun in the pvder model")

    def _run(self,
             gridVoltagePhaseA,
             gridVoltagePhaseB,
             gridVoltagePhaseC,
             KVAbase=50):
        #t = [self.lastT, self.lastT + OpenDSSData.data['DNet']['DER']['DERParameters']['dt']]
        t = [self.lastT, self.lastT + 1 / 120.0]

        try:
            # set grid voltage. This value will be kept constant during the run
            # as opendss will sync will grid_simulation only once during the run call.
            # opendss will solve power flow and will set gridVoltagePhase value.
            self.PV_model.gridVoltagePhaseA = gridVoltagePhaseA * math.sqrt(
                2) / Grid.Vbase
            self.PV_model.gridVoltagePhaseB = gridVoltagePhaseB * math.sqrt(
                2) / Grid.Vbase
            self.PV_model.gridVoltagePhaseC = gridVoltagePhaseC * math.sqrt(
                2) / Grid.Vbase
            self.sim.t = t

            sol, info, ConvergeFlag = self.sim.call_ODE_solver(
                self.sim.ODE_model, self.sim.jac_ODE_model, self.lastSol, t)

            if self.sim.COLLECT_SOLUTION:
                self.sim.collect_solution(sol, t)

            #sol,info=odeint(odeFunc,y0,t,Dfun=jac_odeFunc,full_output=1,printmessg=True,hmax = 1/120.,mxstep=50,atol=1e-4,rtol=1e-4)
            #sol,info=odeint(odeFunc,y0,t,full_output=1,printmessg=True,hmax = 1/120.,mxstep=50,atol=1e-4,rtol=1e-4)

            #np array is mutable, hence make a copy
            self.lastSol = copy.deepcopy(sol[-1])
            self.lastT = t[-1]

            # get S
            S = self._getS()

            return S * KVAbase
        except Exception as e:
            #OpenDSSData.log("Failed run in the pvder model")
            OpenDSSData.log(
                "{}:ODE solver failed between {:.4f} s and {:.4f} s!".format(
                    self.PV_model.name, t[0], t[-1]))

        S = 0
        return S

    def _getS(self):
        try:
            return self.sim.PV_model.S_PCC  # value at end of PV-DER simulation
        except Exception as e:
            OpenDSSData.log("Failed getS in the pvder model")
Beispiel #2
0
class PVDERModel:
    def __init__(self):
        self._pvModel = {}
        self._sim = {}
        self._lastSol = {}
        self._lastT = 0

    def setup(self, nodeid, V0):
        try:
            VpuInitial = 1.0
            SinglePhase = False

            if 'myconfig' in OpenDSSData.config and 'DERParameters' in OpenDSSData.config[
                    'myconfig']:
                #pvderConfig = copy.deepcopy(OpenDSSData.config['myconfig']['DERParameters'])

                DERFilePath = OpenDSSData.config['myconfig']['DERFilePath']
                DERModelType = OpenDSSData.config['myconfig']['DERModelType']
                DERSetting = OpenDSSData.config['myconfig']['DERSetting']

                DERParameters = OpenDSSData.config['myconfig']['DERParameters']

                if DERSetting == 'default':
                    pvderConfig = self.get_derconfig(DERParameters['default'])
                    DERArguments = self.get_derarguments(
                        DERParameters['default'])

                elif DERSetting == 'PVPlacement':  # for manual feeder config based on PVPlacement
                    if nodeid in DERParameters['PVPlacement']:
                        pvderConfig = self.get_derconfig(
                            DERParameters['PVPlacement'][nodeid])
                        DERArguments = self.get_derarguments(
                            DERParameters['PVPlacement'][nodeid])
                    else:
                        raise ValueError(
                            'Distribution node {} not found in config file!'.
                            format(nodeid))
                else:
                    raise ValueError(
                        '{} is not a valid DER setting in config file!'.format(
                            DERSetting))

                if 'nodenumber' in OpenDSSData.config['myconfig']:
                    DERLocation = str(os.getpid()) + '-' + 'bus_' + str(
                        OpenDSSData.config['myconfig']
                        ['nodenumber']) + '-' + 'node_' + nodeid
                else:
                    DERLocation = str(os.getpid()) + '-' + 'node_' + nodeid

            else:
                print(
                    'DERParameters not found in `OpenDSSData` object - using default ratings and parameters!'
                )
                DERArguments = {}
                pvderConfig = {}
                SteadyState = True
                if SinglePhase:
                    powerRating = 10.0e3
                else:
                    powerRating = 50.0e3
                DERLocation = 'node_' + nodeid

                DERArguments.update({'pvderConfig': pvderConfig})
                DERArguments.update({'powerRating': powerRating})
                DERArguments.update({'SteadyState': SteadyState})

            #Va = cmath.rect(DERArguments['VrmsRating']*math.sqrt(2),0.0)
            #Vb = utility_functions.Ub_calc(Va)
            #Vc = utility_functions.Uc_calc(Va)
            a = utility_functions.Urms_calc(
                V0['a'], V0['b'], V0['c']) / DERArguments['VrmsRating']
            Va = (V0['a'] / a)  #Convert node voltage at HV side to LV
            Vb = (V0['b'] / a)
            Vc = (V0['c'] / a)

            DERArguments.update({'identifier': DERLocation})
            DERArguments.update({'derConfig': pvderConfig})
            DERArguments.update({'standAlone': False})

            DERArguments.update({'gridFrequency': 2 * math.pi * 60.0})
            DERArguments.update({'gridVoltagePhaseA': Va})
            DERArguments.update({'gridVoltagePhaseB': Vb})
            DERArguments.update({'gridVoltagePhaseC': Vc})

            logging.debug(
                'Creating DER instance of {} model for {} node.'.format(
                    DERModelType, DERLocation))
            print('Creating DER instance of {} model for {} node.'.format(
                DERModelType, DERLocation))
            events = SimulationEvents()

            PVDER_model = DERModel(modelType=DERModelType,
                                   events=events,
                                   configFile=DERFilePath,
                                   **DERArguments)
            self.PV_model = PVDER_model.DER_model

            self.PV_model.LVRT_ENABLE = True  #Disconnects PV-DER based on ride through settings in case of voltage anomaly
            self.sim = DynamicSimulation(PV_model=self.PV_model,
                                         events=events,
                                         LOOP_MODE=True,
                                         COLLECT_SOLUTION=True)
            if DERModelType in self.sim.jac_list:
                self.sim.jacFlag = True  #Provide analytical Jacobian to ODE solver
            else:
                self.sim.jacFlag = False
            self.sim.DEBUG_SOLVER = False  #Check whether solver is failing to converge at any step
            self.results = SimulationResults(simulation=self.sim,
                                             PER_UNIT=True)

            self.lastSol = copy.deepcopy(self.sim.y0)  # mutable,make copy
            self.lastT = 0
        except Exception as e:
            OpenDSSData.log("Failed Setup PVDER at node:{}!".format(nodeid))

    def get_derconfig(self, DERParameters):
        """DER config."""

        derConfig = {}

        for entry in DERParameters:
            if entry in templates.VRT_config_template.keys():
                derConfig.update({entry: DERParameters[entry]})

        return derConfig

    def get_derarguments(self, DERParameters):
        """DER config."""

        DERArguments = {}

        for entry in specifications.DER_argument_spec:
            if entry in DERParameters:
                DERArguments.update({entry: DERParameters[entry]})

        if 'powerRating' in DERArguments:
            DERArguments.update(
                {'powerRating': DERArguments['powerRating'] * 1e3})

        return DERArguments

    def prerun(self, gridVoltagePhaseA, gridVoltagePhaseB, gridVoltagePhaseC):
        """Prerun will set the required data in pvder model. This method should be run before
        running the integrator."""
        try:
            # set grid voltage. This value will be kept constant during the run
            # as opendss will sync will grid_simulation only once during the run call.
            # opendss will solve power flow and will set gridVoltagePhase value.
            self.PV_model.gridVoltagePhaseA = gridVoltagePhaseA * math.sqrt(
                2) / Grid.Vbase
            if templates.DER_design_template[
                    self.PV_model.DER_model_type]['basic_specs']['unbalanced']:
                self.PV_model.gridVoltagePhaseB = gridVoltagePhaseB * math.sqrt(
                    2) / Grid.Vbase
                self.PV_model.gridVoltagePhaseC = gridVoltagePhaseC * math.sqrt(
                    2) / Grid.Vbase
            self.sim.t = self.lastT + 1 / 120.0

            return None
        except Exception as e:
            OpenDSSData.log("Failed prerun in the pvder model")

    def postrun(self, sol, t, KVAbase=50):
        """Postrun will gather results. This method should be run after running the integrator."""
        try:
            if self.sim.COLLECT_SOLUTION:
                self.sim.collect_solution(sol, t)

            #np array is mutable, hence make a copy
            self.lastSol = copy.deepcopy(sol[-1])
            self.lastT = t[-1]

            # get S
            S = self._getS()

            return S * KVAbase
        except Exception as e:
            OpenDSSData.log("Failed postrun in the pvder model")

    def _run(self,
             gridVoltagePhaseA,
             gridVoltagePhaseB,
             gridVoltagePhaseC,
             KVAbase=50):
        #t = [self.lastT, self.lastT + OpenDSSData.data['DNet']['DER']['DERParameters']['dt']]
        t = [self.lastT, self.lastT + 1 / 120.0]

        try:
            # set grid voltage. This value will be kept constant during the run
            # as opendss will sync will grid_simulation only once during the run call.
            # opendss will solve power flow and will set gridVoltagePhase value.
            self.PV_model.gridVoltagePhaseA = gridVoltagePhaseA * math.sqrt(
                2) / Grid.Vbase
            self.PV_model.gridVoltagePhaseB = gridVoltagePhaseB * math.sqrt(
                2) / Grid.Vbase
            self.PV_model.gridVoltagePhaseC = gridVoltagePhaseC * math.sqrt(
                2) / Grid.Vbase
            self.sim.t = t

            sol, info, ConvergeFlag = self.sim.call_ODE_solver(
                self.sim.ODE_model, self.sim.jac_ODE_model, self.lastSol, t)

            if self.sim.COLLECT_SOLUTION:
                self.sim.collect_solution(sol, t)

            #sol,info=odeint(odeFunc,y0,t,Dfun=jac_odeFunc,full_output=1,printmessg=True,hmax = 1/120.,mxstep=50,atol=1e-4,rtol=1e-4)
            #sol,info=odeint(odeFunc,y0,t,full_output=1,printmessg=True,hmax = 1/120.,mxstep=50,atol=1e-4,rtol=1e-4)

            #np array is mutable, hence make a copy
            self.lastSol = copy.deepcopy(sol[-1])
            self.lastT = t[-1]

            # get S
            S = self._getS()

            return S * KVAbase
        except Exception as e:
            #OpenDSSData.log("Failed run in the pvder model")
            OpenDSSData.log(
                "{}:ODE solver failed between {:.4f} s and {:.4f} s!".format(
                    self.PV_model.name, t[0], t[-1]))

        S = 0
        return S

    def _getS(self):
        try:
            return self.sim.PV_model.S_PCC  # value at end of PV-DER simulation
        except Exception as e:
            OpenDSSData.log("Failed getS in the pvder model")