Exemplo n.º 1
0
class TowerScene():
	""" Creates a scene of the heliostats, tower and receiver """
	# recobj is an assembled receiver object
	# surf_ls is a list of all surfaces used in the receiver
	# crit_ls is a list of all surfaces to be viewed in a histogram
	# heliostat is a csv file of coordinates (Example: sandia_hstat_coordinates.csv)
	# dx,dy,dz are x,y,z offsets from the origin (default dz is 6.1 metres)
	# rx,ry,rz are rotations about the x,y,z axes in radians (default 0)
	def __init__(self,rec_obj,surf_ls,crit_ls,heliostat,sun_az = 0.,sun_elev = 34.9,\
	dx = 0., dy = 0., dz = 6.1, rx = 0, ry = 0, rz = 0):
		self.sun_az = sun_az
		self.sun_elev = sun_elev
		self.rec_obj = rec_obj
		self.surf_ls = surf_ls
		self.crit_ls = crit_ls
		# add offset properties
		self.dx = dx
		self.dy = dy
		self.dz = dz
		# add rotation properties
		self.rx = rx
		self.ry = ry
		self.rz = rz
		# add the heliostat coordinates
		self.pos = N.loadtxt(heliostat, delimiter=",")
		self.pos *= 0.1
		# generate the entire plant now
		self.gen_plant()
		# creates an attribute which shows number of rays used, start at zero
		self.no_of_rays = 0
		self.helio_hits = 0

	def gen_rays(self):
		sun_vec = solar_vector(self.sun_az*degree, self.sun_elev*degree)
        	rpos = (self.pos + sun_vec).T
        	direct = N.tile(-sun_vec, (self.pos.shape[0], 1)).T
        	rays = RayBundle(rpos, direct, energy=N.ones(self.pos.shape[0]))

		return rays

	def gen_plant(self):
		"""Generates the entire plant"""
		# set heliostat field characteristics: 0.52m*0.52m, abs = 0, aim_h =61
		self.field = HeliostatField(self.pos, 6.09e-1, 6.09e-1, 0, 6.1, 1e-3)
		# generates a transformation matrix of the receiver rec_trans for rotations
		rx_M = N.matrix(rotx(self.rx))
		ry_M = N.matrix(rotx(self.ry))
		rz_M = N.matrix(rotx(self.rz))
		rec_trans = N.array((rx_M)*(ry_M)*(rz_M))
		# applies translations to the rotation matrix to get the final transformation
		rec_trans[0,3] = self.dx
		rec_trans[1,3] = self.dy
		rec_trans[2,3] = self.dz
		# applies the transformation to the receiver object
		self.rec_obj.set_transform(rec_trans)
		# combines all objects into a single plant
		self.plant = Assembly(objects = [self.rec_obj], subassemblies=[self.field])


	def aim_field(self):
		"""Aims the field to the sun?"""
		self.field.aim_to_sun(self.sun_az*degree, self.sun_elev*degree)

	def trace(self, rph, iters = 10000, minE = 1e-9, render = False):
		"""Commences raytracing using (rph) number of rays per heliostat, for a maximum of 
		   (iters) iterations, discarding rays with energy less than (minE). If render is
		   True, a 3D scene will be displayed which would need to be closed to proceed."""
		# Get the solar vector using azimuth and elevation
		sun_vec = solar_vector(self.sun_az*degree, self.sun_elev*degree)
        	# Calculate number of rays used. Rays per heliostat * number of heliostats.
        	num_rays = rph*len(self.field.get_heliostats())
		self.no_of_rays += num_rays
		# Generates the ray bundle
        	rot_sun = rotation_to_z(-sun_vec)
        	direct = N.dot(rot_sun, pillbox_sunshape_directions(num_rays, 0.00465))
        
        	xy = N.random.uniform(low=-0.25, high=0.25, size=(2, num_rays))
        	base_pos = N.tile(self.pos, (rph, 1)).T #Check if its is rph or num_rays
       		base_pos += N.dot(rot_sun[:,:2], xy)
        	
        	base_pos -= direct
        	rays = RayBundle(base_pos, direct, energy=N.ones(num_rays))

		# Perform the raytracing
		e = TracerEngine(self.plant)
		e.ray_tracer(rays, iters, minE, tree=True)
		e.minener = minE
		rays_in = sum(e.tree._bunds[0].get_energy())
		self.helio_hits = sum(e.tree._bunds[1].get_energy())


		# Optional rendering
		if render == True:
			trace_scene = Renderer(e)
			trace_scene.show_rays()
			
	def hist_comb(self, no_of_bins=100):
		"""Returns a combined histogram of all critical surfaces and relevant data"""
		# H is the histogram array
		# boundlist is a list of plate boundaries given in x coordinates
		# extent is a list of [xmin,xmax,ymin,ymax] values
		# binarea is the area of each bin. Used to estimate flux concentration

		# Define empty elements
		X_offset = 0	# Used to shift values to the right for each subsequent surface
		all_X = []	# List of all x-coordinates
		all_Y = []	# List of all y-coordinates
		all_E = []	# List of all energy values
		boundlist = [0]	# List of plate boundaries, starts with x=0

		#print("length here"+str(len((self.plant.get_local_objects()[0]).get_surfaces())))

		#for plate in self.crit_ls:	#For each surface within the list of critical surfs
		crit_length = len(self.crit_ls)
		count = 0
		while count < crit_length: # count is one less than crit_length for indexing convention
			surface = (self.plant.get_local_objects()[0]).get_surfaces()[count]
			# returns all coordinates where a hit occured and its energy absorbed
			energy, pts = surface.get_optics_manager().get_all_hits()
			corners = surface.mesh(1) #corners is an array of all corners of the plate
			# BLC is bottom left corner "origin" of the histogram plot
			# BRC is the bottom right corner "x-axis" used for vector u
			# TLC is the top right corner "y-axis" used for vector v
			BLC = N.array([corners[0][1][1],corners[1][1][1],corners[2][1][1]])
			BRC = N.array([corners[0][0][1],corners[1][0][1],corners[2][0][1]])
			TLC = N.array([corners[0][1][0],corners[1][1][0],corners[2][1][0]])
			# Get vectors u and v in array form of array([x,y,z])
			u = BRC - BLC
			v = TLC - BLC
			# Get width(magnitude of u) and height(magnitude of v) in float form
			w = (sum(u**2))**0.5
			h = (sum(v**2))**0.5
			# Get unit vectors of u and v in form of array([x,y,z])
			u_hat = u/w
			v_hat = v/h
			# Local x-position determined using dot product of each point with direction
			# Returns a list of local x and y coordinates
			origin = N.array([[BLC[0]],[BLC[1]],[BLC[2]]])
			local_X = list((N.array(N.matrix(u_hat)*N.matrix(pts-origin))+X_offset)[0])
			#local_Y = list((N.array(N.matrix(v_hat)*N.matrix(pts-origin)))[0])
			local_Y = list((((N.array(N.matrix(v_hat)*N.matrix(pts-origin)))[0])*-1)+h)
			# Adds to the lists
			all_X += local_X
			all_Y += local_Y
			all_E += list(energy)
			X_offset += w
			boundlist.append(X_offset)
			count += 1
		# Now time to build a histogram
		rngy = h
		rngx = X_offset
		bins = [no_of_bins,int(no_of_bins*X_offset)]
		H,ybins,xbins = N.histogram2d(all_Y,all_X,bins,range=([0,rngy],[0,rngx]), weights=all_E)
		extent = [xbins[0],xbins[-1],ybins[0],ybins[-1]]
		binarea = (float(h)/no_of_bins)*(float(X_offset)/int(no_of_bins*X_offset))
		return H, boundlist, extent, binarea

	def energies(self):
		"""Returns the total number of hits on the heliostats, receiver and the total energy absorbed"""
		
		totalenergy = 0.0
		totalhits = 0
		heliohits = self.helio_hits
		#length = 0
		#for surface in self.plant.get_local_objects()[0].get_surfaces():
		for surface in (self.plant.get_local_objects()[0]).get_surfaces():
			energy, pts = surface.get_optics_manager().get_all_hits()
			absorp = surface._opt._opt._abs
			#length += len(energy)
			#plt.plot(range(0,len(energy)),energy,'ro')
			#plt.show()
			totalenergy += sum(energy)
			totalhits += sum(energy == absorp)
		#print("Length is"+str(length))
		return totalenergy, totalhits, heliohits
Exemplo n.º 2
0
class TowerSceneZeb():
    """ Square Blackbody receiver on the xz plane with set area. Custom heliotat field"""

    # rec_area = area of the receiver (assumed square)
    # rec_centre = coordinates of the centre of the receiver (global)
    # heliostat is a csv file of coordinates (Example: sandia_hstat_coordinates.csv)
    #   x,y,z,focal_length
    # azimuth and elevation angles are in radians
    def __init__(self,
                 recv_area,
                 recv_centre,
                 heliostat,
                 azimuth=0.0,
                 elevation=0.0,
                 helio_w=1.85,
                 helio_h=2.44,
                 helio_abs=0.10,
                 helio_sigmaxy=1.5e-3,
                 helio_tracking="TiltRoll"):
        self.recv_surf, self.recv_obj = two_sided_receiver(
            recv_area[0],
            recv_area[1],
            location=recv_centre,
            absorptivity=1.00)
        #Sun angles in radians
        self.azimuth = azimuth
        self.zenith = N.pi / 2.0 - elevation
        self.elevation = elevation
        # add the heliostat coordinates
        self.pos = N.loadtxt(
            heliostat, delimiter=",")[:, 0:3]  #These are positions x,y,z (m)
        self.helio_focal = N.loadtxt(
            heliostat, delimiter=",")[:, 3]  #These are focal lengths (m)
        self.layout = N.loadtxt(heliostat,
                                delimiter=",")[:, 0:4]  #Layout of the field
        self.helio_area = float(
            len(self.pos)
        ) * helio_w * helio_h  #These is the total heliostat area (m^2)
        print("heliostat area", self.helio_area, "m2")
        self.helio_w = helio_w  #This is heliostat width
        self.helio_h = helio_h  #This is heliostat height
        self.helio_abs = helio_abs  #This is heliostat absorptivity
        self.helio_sigmaxy = helio_sigmaxy  #This is surface slope error of mirrors
        self.helio_tracking = helio_tracking  #This is tracking strategy "AzEl" or "TiltRoll"
        self.heliostatcsv = heliostat

        self.recv_centre = recv_centre
        self.dz = recv_centre[2]  #The height of the receiver centre

        # Obtain x,y centre and radius of raybundle source
        self.field_centroid = sum(self.pos) / float(len(self.pos))
        self.field_radius = (
            ((max(self.pos[:, 0]) - min(self.pos[:, 0]))**2.0 +
             (max(self.pos[:, 1]) - min(self.pos[:, 1]))**2.0)**0.5) * 0.5
        # generate the entire plant now
        self.gen_plant()
        # creates an attribute which shows number of rays used, start at zero

    def gen_rays(self, rays):
        sun_vec = solar_vector(self.azimuth, self.zenith)
        source_centre = N.array([[self.field_centroid[0] + 200.0 * sun_vec[0]],
                                 [self.field_centroid[1] + 200. * sun_vec[1]],
                                 [self.field_centroid[2] + 200.0 * sun_vec[2]]
                                 ])
        #print(self.field_centroid + (500.0*sun_vec))

        #print(sun_vec_array)
        self.DNI = 1000.0
        self.rays = rays
        #self.raybundle = buie_sunshape(self.rays, source_centre, -1.0*sun_vec, 165.0, 0.0225, flux=self.DNI)
        self.raybundle = solar_disk_bundle(self.rays,
                                           source_centre,
                                           -1.0 * sun_vec,
                                           self.field_radius,
                                           4.65e-3,
                                           flux=self.DNI)
        #print(self.DNI, sum(self.raybundle.get_energy()))
        return rays

    def gen_plant(self):
        """Generates the entire plant"""
        # set heliostat field characteristics: 6.09m*6.09m, abs = 0.04, aim_location_xyz =60
        self.field = HeliostatGenerator(self.helio_w,
                                        self.helio_h,
                                        self.helio_abs,
                                        self.helio_sigmaxy,
                                        slope='normal',
                                        curved=True,
                                        pos=self.pos,
                                        foc=self.helio_focal)
        self.field(
            KnownField(self.heliostatcsv, self.pos,
                       N.array([self.helio_focal]).T))  #field(layout)
        heliostats = Assembly(objects=self.field._heliostats)
        aiming = SinglePointAiming(self.pos, self.recv_centre, False)
        if self.helio_tracking == 'TiltRoll':
            tracking = TiltRoll(solar_vector(self.azimuth, self.zenith), False)
        elif self.helio_tracking == 'AzEl':
            tracking = AzElTrackings(solar_vector(self.azimuth, self.zenith),
                                     False)
        tracking.aim_to_sun(-self.pos, aiming.aiming_points, False)
        tracking(self.field)

        self.plant = Assembly(objects=[self.recv_obj],
                              subassemblies=[heliostats])

        ##### Calculate Total Recv area #####
        areacount = 0.
        corners = self.recv_surf.mesh(
            0)  #corners is an array of all corners of the plate
        # BLC is bottom left corner "origin" of the histogram plot
        # BRC is the bottom right corner "x-axis" used for vector u
        # TLC is the top right corner "y-axis" used for vector v
        BLC = N.array([corners[0][1][1], corners[1][1][1], corners[2][1][1]])
        BRC = N.array([corners[0][0][1], corners[1][0][1], corners[2][0][1]])
        TLC = N.array([corners[0][1][0], corners[1][1][0], corners[2][1][0]])
        # Get vectors u and v in array form of array([x,y,z])
        u = BRC - BLC
        v = TLC - BLC
        # Get width(magnitude of u) and height(magnitude of v) in float form
        w = (sum(u**2))**0.5
        h = (sum(v**2))**0.5
        areacount += w * h
        self.recv_area = areacount
        print("Reciver area", self.recv_area)

    #def aim_field(self):
    #"""Aims the field to the sun?"""
    #self.sun_vec = solar_vector(self.azimuth,self.zenith)
    #aiming = SinglePointAiming(self.pos, self.recv_centre, False)
    #if self.helio_tracking == "TiltRoll":
    #tracking = TiltRoll(self.sun_vec,False)
    #else:
    #tracking = AzElTrackings(self.sun_vec,False)
    #tracking.aim_to_sun(-self.pos, aiming.aiming_points, False)
    #tracking(self.field.get_objects())
    #self.field.aim_to_sun(self.azimuth, self.elevation)

    def trace(self, iters=10000, minE=1e-9, render=False, bins=20):
        """Commences raytracing using (rph) number of rays per heliostat, for a maximum of 
		   (iters) iterations, discarding rays with energy less than (minE). If render is
		   True, a 3D scene will be displayed which would need to be closed to proceed."""
        # Get the solar vector using azimuth and elevation

        raytime0 = timeit.default_timer()
        # Perform the raytracing
        e = TracerEngine(self.plant)
        e.ray_tracer(self.raybundle, iters, minE, tree=True)
        e.minener = minE

        raytime1 = timeit.default_timer()
        print("RayTime", raytime1 - raytime0)
        #power_per_ray = self.power_per_ray
        self.power_per_ray = self.DNI / self.rays
        power_per_ray = self.power_per_ray

        # Optional rendering
        if render == True:
            trace_scene = Renderer(e)
            trace_scene.show_rays()

        #pe0 is the array of energies of rays in bundle 0 that have children
        i_list = e.tree._bunds[1].get_parents()
        e_list = e.tree._bunds[0].get_energy()

        pe0 = N.array([])
        for i in i_list:
            pe0 = N.append(pe0, e_list[i])

        #pe1 is the array of energies of rays in bundle 1 that have children
        i_list = e.tree._bunds[2].get_parents()
        e_list = e.tree._bunds[1].get_energy()

        pe1 = N.array([])
        for i in i_list:
            pe1 = N.append(pe1, e_list[i])

        #pz0 is the array of z-vertices of rays in bundle 0 that have children
        i_list = e.tree._bunds[1].get_parents()
        z_list = e.tree._bunds[0].get_vertices()[2]

        pz0 = N.array([])
        for i in i_list:
            pz0 = N.append(pz0, z_list[i])

        #az1 is the array of z-vertices of rays in bundle 1 that have children
        i_list = e.tree._bunds[2].get_parents()
        z_list = e.tree._bunds[1].get_vertices()[2]

        pz1 = N.array([])
        for i in i_list:
            pz1 = N.append(pz1, z_list[i])

        #Helio_0 initial rays incident on heliostat


##############ASSUMING PERFECT REFLECTORS, HELIO1 IS ALSO RAYS COMING OUT OF THE HELIOSTAT INITIALLY#######(NOT CORRECTED FOR BLOCK)
#azh1 = array of z-values less than half of recv height
        azh1 = e.tree._bunds[1].get_vertices()[2] < self.dz / 2.0
        #array of parent energies of those rays is pe0
        self.helio_0 = float(sum(azh1 * pe0))  #*power_per_ray

        #Helio_1 is all rays coming out of a heliostat
        #ape1 is array of all energies in bundle 1
        ape1 = e.tree._bunds[1].get_energy()
        self.helio_1 = float(sum(ape1 * azh1))  #*power_per_ray

        #Recv_0 initial rays incident on receiver
        #azr1 = array of z-values greater than half of recv height
        azr1 = e.tree._bunds[1].get_vertices()[2] > self.dz / 2.0
        self.recv_0 = float(sum(azr1 * pe0))  #*power_per_ray

        #Helio_b rays out of heliostat that are blocked by other mirrors
        #azh2 = array of z-values less than half of recv height of bundle 2
        azh2 = e.tree._bunds[2].get_vertices()[2] < self.dz / 2.0
        #pz1 = array of z-values of bundle 1 that have children
        pzh1 = pz1 < self.dz / 2.0
        #pe1 = array of energies of bundle 1 that have children
        self.helio_b = float(sum(azh2 * pzh1 * pe1))  #*power_per_ray

        #Helio_2 is effectively what comes out of the heliostats
        self.helio_2 = self.helio_1 - self.helio_b  #This is effective power out of heliostat in kW

        #Recv_2 is rays hitting receiver from heliostat
        azr2 = e.tree._bunds[2].get_vertices()[2] > self.dz / 2.0
        pzh1 = pz1 < self.dz / 2.0
        self.recv_1 = float(sum(azr2 * pzh1 * pe1))  #*power_per_ray

        totalabs = 0
        #energy locations
        front = 0
        back = 0
        for surface in (self.plant.get_local_objects()[0]).get_surfaces():
            energy, pts = surface.get_optics_manager().get_all_hits()
            totalabs += sum(energy)
            #if surface.iden == "front":
            #front += sum(energy)

            #if surface.iden == "back":
            #back += sum(energy)
        #Cosine efficiency calculations
        sun_vec = solar_vector(self.azimuth, self.zenith)
        tower_vec = -1.0 * self.pos
        tower_vec += self.recv_centre
        tower_vec /= N.sqrt(N.sum(tower_vec**2, axis=1)[:, None])
        hstat = sun_vec + tower_vec
        hstat /= N.sqrt(N.sum(hstat**2, axis=1)[:, None])
        self.cos_efficiency = sum(N.dot(sun_vec,
                                        (hstat).T)) / float(len(hstat))

        #Intermediate Calculation
        self.cosshadeeff = (self.helio_0) / (self.DNI * self.helio_area)

        #Results
        self.p_recvabs = totalabs  #Total power absrorbed by receiver

        self.coseff = self.cos_efficiency
        self.shadeeff = self.cosshadeeff / self.coseff
        self.refleff = (self.helio_1) / (self.helio_0)
        self.blockeff = (self.helio_1 - self.helio_b) / (self.helio_1)
        self.spilleff = (self.recv_1) / (self.helio_2)
        self.abseff = (self.p_recvabs - self.recv_0) / (self.recv_1)
        self.opteff = (self.p_recvabs - self.recv_0) / (
            self.DNI * self.helio_area)  #OpticalEfficiency
        self.hist_out = self.hist_flux(bins)
        self.Square_spilleff = (self.SquareEnergy - self.recv_0) / (
            self.helio_2)  #provided absorptivity of recv is 1.0
        self.Square_opteff = (self.SquareEnergy - self.recv_0) / (
            self.DNI * self.helio_area)  #ditto

    def hist_flux(self, no_of_bins=1000):
        """Returns a combined histogram of all critical surfaces and relevant data"""
        # H is the histogram array
        # boundlist is a list of plate boundaries given in x coordinates
        # extent is a list of [xmin,xmax,ymin,ymax] values
        # binarea is the area of each bin. Used to estimate flux concentration

        # Define empty elements
        X_offset = 0  # Used to shift values to the right for each subsequent surface
        all_X = []  # List of all x-coordinates
        all_Y = []  # List of all y-coordinates
        all_E = []  # List of all energy values
        boundlist = [0]  # List of plate boundaries, starts with x=0

        #print("length here"+str(len((self.plant.get_local_objects()[0]).get_surfaces())))

        #for plate in self.crit_ls:	#For each surface within the list of critical surfs
        #crit_length = len(self.crit_ls)
        count = 0

        #surface = (self.plant.get_local_objects()[0]).get_surfaces()[count]
        #print(surface)

        energy, pts = self.recv_surf.get_optics_manager().get_all_hits()
        corners = self.recv_surf.mesh(
            0)  #corners is an array of all corners of the plate
        # BLC is bottom left corner "origin" of the histogram plot
        # BRC is the bottom right corner "x-axis" used for vector u
        # TLC is the top right corner "y-axis" used for vector v
        BLC = N.array([corners[0][1][1], corners[1][1][1], corners[2][1][1]])
        BRC = N.array([corners[0][0][1], corners[1][0][1], corners[2][0][1]])
        TLC = N.array([corners[0][1][0], corners[1][1][0], corners[2][1][0]])
        # Get vectors u and v in array form of array([x,y,z])
        u = BRC - BLC
        v = TLC - BLC
        # Get width(magnitude of u) and height(magnitude of v) in float form
        w = (sum(u**2))**0.5
        h = (sum(v**2))**0.5
        # Get unit vectors of u and v in form of array([x,y,z])
        u_hat = u / w
        v_hat = v / h
        # Local x-position determined using dot product of each point with direction
        # Returns a list of local x and y coordinates
        origin = N.array([[BLC[0]], [BLC[1]], [BLC[2]]])
        local_X = list(
            (N.array(N.matrix(u_hat) * N.matrix(pts - origin)) + X_offset)[0])
        #local_Y = list((N.array(N.matrix(v_hat)*N.matrix(pts-origin)))[0])
        local_Y = list(((
            (N.array(N.matrix(v_hat) * N.matrix(pts - origin)))[0]) * -1) + h)
        # Adds to the lists
        all_X += local_X
        all_Y += local_Y
        all_E += list(energy)
        X_offset += w
        boundlist.append(X_offset)
        count += 1
        # Now time to build a histogram
        rngy = h
        rngx = X_offset
        bins = [no_of_bins, no_of_bins]
        H, ybins, xbins = N.histogram2d(all_Y,
                                        all_X,
                                        bins,
                                        range=([0, rngy], [0, rngx]),
                                        weights=all_E)

        #22/08/18 Add in the concentric squares code Note: Assumes 10mx10m SQUARE, 20*20 bins
        #self.SquareEnergy = [1,2,3,4,5,6,7,8,9,10] where the number is side length eg 4 x 4.
        L = 1  #Start with side length = 1
        absorb_list = [
        ]  #Start with empty list of all energy absorbed in that square
        while L <= 10:  #Stops at 10.0m x 10.0m

            absorbed = N.sum(H[(10 - L):(10 + L), (10 - L):(10 + L)])
            absorb_list.append(absorbed)
            L += 1
        self.SquareEnergy = N.array(absorb_list)

        extent = [xbins[0], xbins[-1], ybins[0], ybins[-1]]
        binarea = 1.0 * (float(h) / no_of_bins) * (
            float(X_offset) / int(no_of_bins * X_offset))  #this is in metres
        #print("maxH",N.amax(H))
        return [H / binarea, boundlist, extent]