A by Optimization of Electrical Lighting Energy (1999)

advertisement
A Simulation Tool for the Estimation and
Optimization of Electrical Lighting Energy
by
Matthew A Lehar
B.S., Mechanical Engineering (1999)
Stanford University
Submitted to the Department of Mechanical Engineering
in Partial Fulfillment of the Requirements for the Degree of
Master of Science in Mechanical Engineering
at the
MASSACHUSE S INSTITUTE
OF TEC HOLOGY
Massachusetts Institute of Technology
February 2003
JUL 0 8RE
LIBRARIES
©2003 Massachusetts Institute of Technology
All rights reserved
AY
r ......
..............
Department of Mechanical Engineering
March 13, 2003
Signature of Author......................
C ertified by.............................................
1Ieon R. Glicksman
Professor of Mechanical Engineering
Thesis Supervisor
0a
Accepted by..........................-l..................
Ain A. Sonin
Chairman, Department Committee on Graduate Students
BARKER
Room 14-0551
MITLibraries
Document Services
77 Massachusetts Avenue
Cambridge, MA 02139
Ph: 617.253.2800
Email: docs@mit.edu
http://libraries.mit.edu/docs
DISCLAIMER OF QUALITY
Due to the condition of the original material, there are unavoidable
flaws in this reproduction. We have made every effort possible to
provide you with the best copy available. If you are dissatisfied with
this product and find it unusable, please contact Document Services as
soon as possible.
Thank you.
The images contained in this document are of
the best quality available.
A Simulation Tool for the Estimation and Optimization of
Electrical Lighting Energy
by
MATTHEW A. LEHAR
Submitted to the Department of Mechanical Engineering
on January 17, 2003, in Partial Fulfillment of the Requirements
for the Degree of Masters of Science in Engineering
ABSTRACT
The subject of this thesis is a daylighting simulation tool, designed to predict the
distribution of daylight in an office room using a rapid calculation procedure.
Results from this simulation are compared to the output from a professional
rendering program, and are found to agree within 10% normalized error. A
method for finding average light levels in an office room is described, and these
calculations are used to infer a minimum required energy cost to supplement
daylighting with artificial lighting.
Thesis Supervisor:
Leon R. Glicksman
Title:
Professor of Mechanical Engineering
Table of Contents
1. Introduction
9
a. The need for a "Design Advisor" web tool
9
b. The daylighting tool
11
c. Simulation setup
11
2. Method Overview
14
a. Initialization
14
b. Iteration
18
c. Composing the room model
19
d. Displaying regions of light and shade
20
e. Predictions of long-term energy use
24
3. Theory of the Diffuse Reflections Method
28
a. Reflections and smoothing
35
b. Blind reflections
37
c. Daylighting results
40
d. Lighting energy estimation results
47
4. Detailed Method
57
a. Basic room objects
57
b. Initialization routines
59
c. Reflections
63
d. Smoothing
64
Bibliography
67
Appendix: Program Code for the Lighting Module
69
Acknowledgments
I am grateful to Professor Glicksman for introducing me to this work, and for
showing me a how to think like an engineer. I am also indebted to him for laying
the groundwork for the approach presented here, for raising the alarm when we
had bad data, and for the invaluable weekly discussions.
Jim Gouldstone, who wrote the visual interface for my code, also helped me to
understand Java through many informal tutorials. The implementation of my
model is significantly due to him. His great ability as a teacher is matched only
by the generosity with which he gave out his time.
Permasteelisa Corporation provided the funding for my research. I am extremely
grateful to their directors, as well as to the staff scientists who provided technical
advice.
Thanks to my dad for reviewing the thesis and offering advice and
encouragement.
CHAPTER 1: INTRODUCTION
* THE NEED FOR A "DESIGN ADVISOR" WEB TOOL
The Daylighting model described in this thesis has been designed as part of a suite
of design tools currently available to the public through an MIT web service, called
"Design Advisor'." The purpose of the site is to provide preliminary advice to
architects and building engineers about the viability of their building designs. At
present, the site consists of three modules, each intended to give the user easily
comprehensible feedback about the tradeoff between energy efficiency and comfort
in the proposed building. The first, an "Energy" module 2 , estimates the energy
consumption of a building design based on simple user inputs. The second, called
"Comfort," shows the effect of infrared radiation from the window surface on
occupants standing at various positions in a room. "Daylighting" is the latest addition
to the site, and provides a mixture of visual and quantitative results demonstrating
how a typical room in the user's building will respond to natural daylight. The
Daylighting module is the subject of this thesis.
More sophisticated software has long been available for both building energy
calculations (EnergyPlus 3 ) and daylighting simulations (Radiance 4). However, these
tools are invariably difficult to learn, and they require both a detailed knowledge of
the final design geometry and a large investment of time to configure and run.
Consequently, they are seldom practical to use in a design project until a single
concept has been finalized and all its dimensions fully determined - in other words,
until there is no longer any possibility of changing the design in response to the
results of the simulation. By contrast, the Design Advisor is designed to be useful at
9
the conceptual stage of a building project, when the general characteristics of a
building are still being chosen. To this end, the modules in the Design Advisor
package emphasize three priorities:
1.
The interface must be simple and require no special training for the user to
enter the minimal input parameters for a building
2.
Each simulation must run to completion in seconds, returning results to the
user essentially in real time, so that many design options can be explored in a
single sitting
3.
The simulation must return results that are visual and intuitive, and which are
easily comprehended without engineering knowledge
In exchange for these virtues, the Design Advisor sacrifices some degree of
accuracy, but all modules have been designed to return results with, at most, a 15%
margin of error. For simplicity of use, the main console of the tool provides only
basic input options. However, the interface also offers "advanced" controls that are
not visible on the startup screen. Many input fields have adjacent buttons that can
be pressed to bring up palettes of advanced options for users with specialized
knowledge (Fig. 1-1).
AlI
FS
4*m~
A
........
..
..
...
7I
Figure 1-1. The Design Advisor interface, with advanced options shown in a pop-up window
10
e
THE DAYLIGHTING TOOL
The daylighting module of the Design Advisor is the main subject of this thesis. Its
scope has been somewhat limited by requirements that apply to the Design Advisor
as a whole, namely that it be simple to use, have a rapid operation, and present
results that are easy to interpret. To reduce computation time in the daylighting
module, we have focused on modeling the effect of sunlight in a basic rectangular
office room with a single window. To avoid the further computational demands of
calculating the paths of individual rays of light (a procedure known as "ray tracing"),
we assume all interior surfaces to be diffuse reflectors. This is a reasonable
approximation for most interior surfaces, and we can check our implementation by
comparing our results with a Radiance model.
The purpose of a daylight-prediction tool is to give an accurate estimate of the
amount of daylight entering an office room during work hours. Based on this
information, the required investment of energy in artificial lighting can be predicted for
any office room. Our aim has been to develop a daylighting model capable of
delivering a tailored lighting-energy estimate to the user in a matter of seconds, and
within a 10% margin of error. Like the other modules on the Design Advisor site,
"Daylighting" uses data from location-specific weather files5 for its hourly lighting
calculations.
* SIMULATION SETUP
The virtual "room" used in the simulation is a rectilinear space with a window opening
in one wall. The wall containing the window, the two walls flanking the window, the
floor, and the ceiling together make up the basic geometry of the room. The rear wall
11
is left out because it is the viewing plane in the user's visual display. The omission is
acceptable from the standpoint of the simulation because reflections from the rear
wall would contribute minimally to the daylighting on other surfaces. Other elements
include an optional set of blinds positioned in the plane of the window and an
transparent workplane with the same dimensions as the floor, but raised to the
elevation of a desk or work surface (Fig. 1-2). The workplane is transparent in the
sense that it does not cast shadows or reflect light onto the other surfaces. Its only
purpose is to measure the amount of light that reaches the desk level.
Blinds
W~orkplane
Figure 1-2. Layout of the basic room model
Each of the room's panels, including the window and the workplane, is referred to as
a "surface" in the simulation code. The current state of a surface is defined by a two-
12
dimensional array of brightness values representing the area of the surface. The
value at each grid position represents the brightness, or radiosity of the surface at
that location. The simulation proceeds by assigning initial radiosity values to each of
these array elements, then calculating for each position how much reflected light it
receives from all other positions in the room (Fig. 1-3).
Wall
I
Floor
Figure 1-3. The amount of light incident on element i is the sum of contributions
from every other element in the room
13
CHAPTER 2: METHOD OVERVIEW
Simulating daylighting inside an enclosed space consists of two basic operations.
The first task, which we will refer to as initialization, is to model the penetration of the
sun's direct rays into different parts of the room. The second, which we call iteration,
is to carry out the reflection of this direct sunlight, as well as diffuse daylight, from
one interior surface to another.
e INITIALIZATION
Before we can project sunlight through a window opening to illuminate the room
interior, we must first devise a way to assign luminance values selectively to different
parts of the room. We divide each of the room's interior surfaces into rectilinear grids
of many small elements, as shown in Fig. 2-1. Each element is given a numerical
value corresponding to the level of surface brightness at its position, measured as a
radiosity. Certain elements can then be assigned higher radiosities than others,
depending on where the sunlight falls.
14
Fine
Coarse
Radiouity Level
Figure 2-1. A sunlight pattern can be digitized to a coarse or fine mesh, in which
each element records a radiosity value at its location
To determine which areas are directly illuminated by sunlight, and which are left in
shadow, we make geometric calculations based on sun position and measurements
of the window opening. The sun-brightened area of the floor, for example, is limited
in the dimension parallel to the window by the right and left margins of the window
area. In the other dimension (towards/away from the window plane), the limit is set
by the window sill and head heights (Fig. 2-2). The shadows created by the sill and
head are simplest to apply, because they run parallel to the sides of the floor. The
following formula is used to convert sill and head heights into the positions of the
shadow boundaries on the floor (measured from an origin at the window plane):
15
(2.1)
tan(e) = a
A
where e is the elevation angle of the sun, a is the height of the sill or head above
the floor, and A is the distance from the window plane of the corresponding shadow
boundary (Fig. 2-3).
The shadow boundary in the other dimension, the one encountered in moving from
right to left across the floor, parallel to the window plane, is more difficult to impose
because it generally runs diagonally. The angle of the diagonal shadow is
determined only by the azimuthal angle of the sun, so for the purpose of simplifying
our concept drawing, we will assume that the other angle parameter, the angle of
elevation, is 30 degrees. If we use the floor as our coordinate system, with x running
towards and away from the window plane and y running parallel to the window, and
the origin at the intersection of floor, window and right wall, we can say that the
position of the shadow boundary in y depends on our position in x. The following
margin
Region iliuminated
Figure 2-2. Sunlight illuminating part of the floor of the room mode
16
Limit set by right margin
right
Equation: Y
c
+ X* tAn (h)
Margin
ray of
sunlight
----
w~inadow
Sun Elevati~on,
Sun
Azimuth,
h
Figure 2-3. Measuring the extent of the sunlight projection
formula gives the y-position of the shadow boundary on the floor caused by the right
margin of the window:
Ybo.nday
= c + x tan(h)
(2.2)
where c is the y-position of the window's right margin, and h is the sun azimuthal
angle, measured in degrees to the right of the outward-pointing normal to the
window. The y-position of the edge of the shadow imposed by the left-hand margin
obeys the same formula, slightly adjusted:
Yboundary
= c + w + x tan(h)
(2.3)
where w is the width of the window in the y-dimension.
Using these simple formulas, we can entirely describe the boundaries of the
shadows on each of the room's surfaces in Fig. 2-3. Boundaries on the walls and
17
floor that run parallel to the frame of the window each have a constant x-coordinate,
and boundaries running longitudinally (away from the window) can be described by a
linear formula giving the y- or z- coordinate in terms of x. The discrete elements that
make up the virtual "surfaces" used in our simulation can each be set to a higher or
lower value, depending on whether each element lies more in sunlight or shadow.
The magnitude of the radiosity of a surface element in direct sunlight can be
determined from the solar illuminance and the absorptivity of the surface.
* ITERATION
All surface elements in the room must be assigned brightnesses due to their being in
or out of the path of direct sunlight from the window, before a simulation of reflected
light, which we call an "iteration," can be carried out. Once the initial radiosity values
have been set, reflections and re-reflections from the interior surfaces can be
calculated. Any element lying completely outside the path of direct sunlight has its
initial radiosity value set to 0. For simplicity, all surfaces in the room are assumed to
reflect light diffusely. No information need be retained as to the original direction
from which a ray of sunlight has struck a surface element, because there is no
preferred direction in which it will be re-directed after striking the surface. If one
surface element is reflecting sunlight, any other element that does not lie in the same
plane will receive a certain fraction of the light reflected. That fraction is given by the
view factor between the two elements (Fig. 2-4). All reflected light can be accounted
for if view factors have been calculated for every possible permutation of two
elements in the room.
18
Wall
ji
..
j2
3 3
i
Floor
,=(1-a)((vF 1_,R, )+ (VF-
R
+(vF
R )+...)
(2.4)
Figure 2-4. The brightness of element i rendered as a sum of the radiosities
of all other surface elements, each multiplied by a view factor.
a, represents the absorptivity of element i. The equation holds
when all elements have the same area.
A certain fraction of the light reflected from one surface element to another will again
be reflected back into the room. To calculate the effect of this "second bounce," we
simply repeat the operation used to obtain the first set of reflections. By repeating
these "iterations," updating, at each step, the radiosities of each element, we
eventually arrive at an equilibrium of surface radiosities, after which point there is no
detectable change in the relative brightness of different parts of the room.
* COMPOSING THE ROOM MODEL
The time required to calculate each complete set of diffuse reflections (a complete
set consists of one reflection for each surface element) rises geometrically with the
resolution of the surface arrays. The total number of calculations goes as the 4th
19
power of the rank of the surface array, so that a room composed of surfaces with
radiosity arrays measuring 10 elements on a side will take 16 times as long to
compute as a room with arrays that are 5 on a side. Because of the time required to
compute reflections, we use a low-resolution grid of elements to represent the room
when running the reflection iterations. At the same time, a separate model of the
room is stored at a much higher resolution, but is used only for representing the initial
distribution of direct sunlight in the room. The high- and low-resolution surface maps
are then combined into a single room model, which shows a crisp delineation
between directly-lit regions and those that are initially in shadow, superimposed on a
cruder plot showing the distribution of secondary light from reflections (Fig. 2-5).
Since reflected radiation is spread diffusely about the room, one would expect it to
have a smooth distribution, so that using a coarse grid to represent reflected light
might introduce major errors if the grid were not then re-smoothed. To relieve the
artificial "blockiness" of the reflected-light pattern, a blinear interpolation function is
used to smooth the edges of the low-resolution cells.
* DISPLAYING REGIONS OF LIGHT AND SHADE
To display the room model as a realistic rendered image, we map radiosity levels
from the surface grids to a perspective drawing of the walls, floor, and window. To
complete this mapping, it will not be sufficient to do a linear transformation of the
range of luminances in the room into shades of gray on a computer monitor. Even if
we use walls with a high reflectivity (-0.7), the room image will look saturated with
white in areas directly lit by the sun, and very dark elsewhere (Fig. 2-6a). In a real
room, the eye does not perceive luminance values in proportion to their absolute
magnitudes. Instead, the visual system increases contrast in certain bands of the
20
Reflections Smoothed
Fine Grid, Plus Reflections
Figure. 2-5. A coarse grid is used to determine reflections, the initial sunlight pattern is removed, the
resulting pattern is smoothed, and a finer pattern of initial sunlight is added in the final frame
luminance range, and decreases it in others, depending on the relative abundance of
light at different levels of intensity. Contrast is increased for levels of luminance that
are well-represented in the world-image, and reduced for under-represented levels.
The method presented by Larson, Rushmeier, and Piatko6 imitates human
perception by using a Cumulative Population Density function to map worldluminances to display-luminances. We have followed this algorithm in its basic
approach. Once the simulation has run to completion, we record the radiosity value
at each of the grid positions in the fine mesh representing the room. We divide the
spectrum of radiosities, from least to greatest, into 100 equal partitions, and assign
each radiosity value from the room to its corresponding bin. By keeping track of the
number of gridpoint values assigned to each bin, we build up a population histogram
for the room radiosity values (Fig. 2-7a). In fact, we do not use the actual radiosity
values, but the logarithms of the values, to compress the spectrum and better
approximate the human "subjective response" to brightness levels (Larson, 8). Using
the histogram of radiosity values, we can easily construct a "cumulative distribution
function" (Fig. 2-7b), which spans the same range of radiosities as the histogram, but
shows the number of readings with values at or below a given radiosity range, rather
than within that range. The CD function is defined in Larson in the following way:
Zf(b,)
P(b) =
h
(2.5)
Zf(b,)
where f(b,) is the number of radiosity samples to be found within the log-radiosity
range b,, and P(b) is the value of the CD at a given brightness value. This new
function can be used as a transfer function, showing the mapping from the log of
radiosities recorded in the simulation to the log of levels of gray shown in the visual
22
a. Linear Transfer Function
b. Histogram Transfer Function
Figure 2-6. Display methods for the room model. In a.),
radiosity values are linearly mapped to levels of grayscale. In
b.), the transfer function is corrected to represent the image
that the human eye would perceive when looking at a view of
the real room
23
display. The transfer function can be further modified using methods presented in
Larson, but for our relatively simple display purposes, the original CD function
appears to be sufficient. The image resulting from the CD transfer function in Fig. 27b is shown in Fig. 2-6b.
e PREDICTIONS OF LONG-TERM ENERGY USE
So far, a method has been described with the object of creating a display image of
the room model using a fixed sun position. A visual output showing the room at a
certain time of day might be useful as an aesthetic design aid, but provides no
quantitative feedback on the room design, and is of no help in planning for energy
efficiency. The amount of energy consumed in electrical lighting fixtures is zero in a
room that already receives enough natural sunlight through the windows to meet the
lighting requirements of the occupant. But if, in the course of lighting a room, the
sunlight also heats the interior space excessively, energy may have to be expended
on air conditioners to control the temperature. Therefore, the total energy use will be
minimized by an optimization of window size and position that accounts for the
heating and cooling requirements of the building. To estimate the amount of
electrical lighting energy used in a room during a given hour, we define a "desired
light level" consistent with the kind of activity that will be taking place in the room, and
pertaining to an invisible surface, some distance above the floor, called the
"workplane" (Fig. 2-8). The workplane is a surface in its own right, like the walls,
floor, and window. The initialization and iteration methods can be used to apply
direct sunlight and reflections from other surfaces, and the resulting light pattern on
the workplane could be displayed in a finished rendering. We can also use the
24
Population Histogram of Radiosity Values
0.16 ,
~~1
014
I
E 0.12
*t
0
0.1
0.08
C*
0.06
l
I-
0.04
L*
-A
0.02
0
a
C2
Bin Number (Log Radiosity)
a.
Cumulative Distribution Function
CD transfer function - - - -1.2
In
linear transfer function
--
1
E
a)
0.81
0
0.6
CL
0
o 0.4
0
LL 0.2
0
Bin Number (Log Radiosity)
b.
Figure 2-7. Radiosity values from each surface element in the room are organized into bins
according to their magnitudes. a.) shows the population of each bin, and the
running tally of values is shown in b.), rising to 100% of the total population at the
right-hand side of the chart
25
-
WMEN63im - -
- --
-
-.
1.
illuminance values for each element of the workplane to compare the intensity of light
due to daylight with the desired light level. In those regions of the workplane where
natural daylight does not meet the lighting requirement, electrical lighting must make
up the difference. The total electrical energy requirement for the hour can be
expressed as follows:
I.,
= Gii
where
Iar
(2.6)
- Gdaylgh ,
is the artificial light intensity requirement,
light intensity for the workplane, and
Gdalght
direct sunlight and reflections. Rewriting
Gin
is the prescribed minimum
is the local natural light intensity due to
Gd,,igh,
in terms of the radiosity R of the
workplane element in question,
R
ar
RGinin
p
R
(2.7)
(Gnin
(-
a)
where p is the reflectivity of the workplane and a is the absorptivity.
Warkp.Lane
FeWorkfae
e2
sDeuk)
Gaded reflections
Reflections + direct
sunlighht overlay
Figure 2-8. The "Workplane" surface within the simulated room model
26
I - -Ava
This summation can now be compared with the cooling energy for the room during
the same 1-hour period. By running the simulation once for each of the working
hours in the day, and repeating this cycle at least once for each month of the year,
we build a reliable history of electrical energy use. In our model, we assume that the
electrical lighting can be continuously varied, and each fixture individually controlled,
to achieve the desired lighting level.
27
CHAPTER 3: THEORY OF THE DIFFUSE REFLECTIONS METHOD
We have made several key assumptions in constructing our computer model of
daylighting. Firstly, we have simplified the surface properties of the walls and floor in
our model so that they reflect only diffuse light. This step is reasonable as long as
there are no highly polished surfaces present that would reflect light non-uniformly
(i.e. create specular reflections). The diffuse approximation represents a vast
simplification of the task posed by ray-tracing or other specular methods.
Building on the assumption of diffuse reflections, we have further assumed that a
discrete view factor formulation will be adequate to express the share of reflected
light received from one surface by another. In general, the intensity of reflected light
incident on a receiving surface A, is given by the following relation:
Gi=(Ri
A,) F- Fj
G RA
1
A,
31
(3.1)
where i and j denote the source and receiving surfaces, R, is the radiosity of the
source surface, F,, is the view factor, and A is the area of a surface element.
The view factor F is given in terms of the geometry of reflecting and receiving
surfaces, their orientation in space, and the distance between them. As we have
divided our surfaces into rectangular sections, each with a different radiosity, we
would theoretically need to compute the full view factor between two rectangular
surfaces each time we calculated a radiation exchange between surface elements in
the room. The full view factor is found using the general form,
28
1
cosO, cosO
i
R
(3.2)
However, a discrete view factor with a much simpler formulation is applicable,
provided each element's size is small in comparison with the distance between
source and receiving elements. The view factor relation between two discrete
elements i and j can be written:
cosO, cosO
"
CosCR2C
A.
(3.3)
The correspondence between the discrete and exact view factors is generally good,
except where the discrete panels are very close or share a common edge. As shown
in Fig. 3-1a, the error can suddenly increase when the panels are brought close
together. Fig. 3-1b shows the amount by which the discrete formulation differs from
the exact view factor for a range of distances separating the two panels. It is
apparent from the graph that the separation between two grid elements from different
surfaces should be at least three times larger than the average dimension of the
elements themselves to ensure that large errors do not arise from the reflection
calculations. Panels in separate surfaces that connect across a common edge can
record measurements that are inaccurate by as much as 50% (Fig. 3-1a), so
accurate readings of radiosity are not available from grid squares that lie on the
perimeter of a surface.
We can further simplify the view factor expression when we consider that the normal
vectors of any two elements will either be parallel or perpendicular. The discrete
view factor can then be re-written:
29
FA
4
T~7R
[a,(x, -x, )+/,(y,-y
)+ y,(z, -z 1 ) -. a(x, -x,)+,J(y-y,)+7y(zj-z)
-
(3.4)
[a
where R is the distance between source and receiver and x, y, and
z
are the
coordinates of the center of the source and receiving elements. a has a value of 1 if
the normal to the surface element points in the x -direction, and a value of 0
otherwise. 6 and y are similarly defined for the y - and
z -directions.
To initiate the
process in which light is "reflected" between surfaces, a discrete view factor is
computed for every possible permutation of two array elements in the room. With the
directly illuminated regions of each surface having been identified in the initialization
procedure, each surface of the room now contains a completely initialized radiosity
array. The view factor relation is used to compute the amount of light that each
element of one surface's array receives from each of the elements belonging to the
other surfaces.
This exchange of light between discrete surface elements approximates the diffuse
reflection of daylight between surfaces. The reflected light that a surface element
receives from all other surface elements is summed, and the total, multiplied the
reflectivity (or 1 minus the absorptivity of the surface), is added to the radiosity value
for that element, as described by equation 2.4. This proportion of the received light
that is added to the radiosity value represents the part that will be reflected, hence
the part that is visible to an observer. After each element in the room has been
incremented in this way, the entire procedure is repeated, simulating the second,
third, and fourth reflections of sunlight around the room, until an equilibrium is
reached and there is no further change in light levels.
30
1xi
panel
1xI
panels
5
Discrete VF:
0.0127
Discrete VF:
0.3183
Exact VF:
0.0124
Exact VF:
0.2000
Fiqure 3.1 a. Comparison of discrete vs. exact view factors for two panel configurations
% Error Using Discrete View Factor
100
90
80
70
60
0
50
wU
40
30
20
10
0
0.1
1.1
2.1
3.1
4.1
5.1
6.1
7.1
8.1
9.1
Separation Distance I Disk Diameter
Figure 3.1 b. Discrete view factor error for two parallel disk-elements as a function of
separation distance
The method of iterating a series of element-by-element reflections was chosen over
other techniques because of its speed. To achieve an exact result, the simulation
would need to execute an infinite number of reflection-cycles, but experiments have
shown that as few as 3 iterations are sufficient to bring surface radiosities to within 1
percent of their theoretical final values when the surface reflectivity is 0.7 or less (Fig.
3-2). Most of the time required for the reflection procedure is taken up with the
31
calculation of view factors between surface elements. View factors must be
recalculated for each new set of room dimensions or surface resolutions, but once
found for a particular room configuration, they are stored in memory so that
subsequent reflection-iterations take relatively little time to run. The solution to a
multi-surface radiation exchange can be found exactly using a system of linear
equations relating a vector of radiosities to a vector of heat fluxes. However,
comparing the number of algebraic operations required to find all the view factors in
a room to the number of operations required for the solution of the system of linear
equations, we find that the former method takes considerably less time to compute.
Solar Intensity: 200 W/mA2
Radiosity vs. Number of Iterations
Sun Altitude: 15 deg.
9.4
...-.-.
Sun Azimuth: 27 deg. E
9.2
Surface KMj!jWxty
=
0.3
9
8.2
7.8
7.6
7.4
2
3
4
5
6
7
8
9
10
Iteration
Figure 3.2. The brightness history of a single wall element, originally in shadow. It achieves most
of its equilibrium brightness after the first iteration (bounce)
We can determine how much brighter a surface will become after its initial brightness
is reinforced by reflections. Consider the simple case, shown in Fig. 3-3, of two
32
infinite, parallel vertical surfaces with a mutual view factor of 1, and each surface
starting the iteration cycle with the same uniformly applied distribution of sunlight, po.
The intensity of light incident upon one surface (surface 1) from the other on the first
reflection is given by:
Infinite Flat Surface
(directlylluminated)
stBoun ce
infinite Flat Surface
(indirectly illuminated)
Figure 3-3. The infinite parallel plates experiment
G, = (1- a)po
(3.5)
where a is the absorptivity of the other surface. After the second reflection (n = 2),
the light received at the other surface (surface 2) represents the sum of the first and
second reflections, and is given by
33
G 2 = (1- a)(1+(1- a))po, or
G2
=[(-a)+(1---a)2
Successive reflections add new terms to the summation until the value of G stabilizes
completely as n goes to infinity in the geometric series,
G = [(Q - a) +(1 _a)2 + (I - a)' +...+ (I - a)"]pO
Following the Euler-Maclaurin Sum Formula, we render the summation as an
"intensity factor,"
G
(1- a)" -1
pO
(1-a) -1
=
[
-
a(3.6)
which is plotted in Fig. 3-4 for a range of values of a. As shown in the graph, a
surface absorptivity of 0.3, typical for smooth wall surfaces painted white, will result
in only a factor-of-two increase in the radiosity, or visible brightness, of the surface
over the initialization value, (1- a)po. In the case of the full room model, the
increase in brightness due to reflection is diminished by the view factor, the blinds,
and the fact that only a small portion of any surface is directly illuminated by sunlight.
34
Surface Brightness at Equilibrium:
Two Infinite Parallel Surfaces
- -- - - -- -
4.5
- - - - - -- -
- - - - - - - - ------
-
-
4
3.5
o 3
u.
2.5
2
+
1.5
1
0.5
0
0.95
0.85
0.75
0.65
0.55
0.45
0.35
0.25
Surface Absorptivity
Figure 3-4. Ratio of incident reflected light to initial sunlight intensity for the
simplified case of two infinite parallel surfaces, plotted against
surface absorptivity
* REFLECTIONS AND SMOOTHING
The time-intensive nature of the view factor calculations requires that we use a lowresolution grid of radiosities when calculating reflections. The new distribution of
radiosity values that results from the reflections process can then be superimposed
on a high-resolution model containing only the initial sunlight pattern. Because the
incident daylight at any point is an integration of radiosities from all other points, it is
expected that the resulting radiosity distribution over a surface approximates a
smoothly varying, well-behaved function. To approach this smooth distribution in the
program, the blocky, low-resolution grid on which reflections are calculated is
smoothed before it is added to the high-resolution data. Fig. 2-5 shows the steps in
this process.
35
For the smoothing procedure, we use a method of bilinear interpolation. This method
can be explained by using the example of the crude, 2-by-2 radiosity grid in Fig. 3-5.
The four points inside the square panels indicate locations on the surface where
radiosity values have been recorded. Before smoothing, coordinates that lie
between grid points are considered to have the same radiosity value as the nearest
neighboring point. The smoothing procedure assigns intermediate values to these
coordinates, so that when the grid data is transposed onto a grid with higher
resolution, the surface radiosity will vary in a continuous manner between the
positions where original data exists. To ensure that data points from the perimeter of
the coarse grid appear in the smoothed version, the grid is augmented by a fringe of
"dummy values" having the same value as their nearest neighbors on the perimeter.
The radiosity values assigned to the intermediate coordinates (between grid points)
can be expressed in terms of the radiosities at the surrounding points. If the
rectangle defined by points a, b, c, and d in Fig. 3-5 has dimensions of Ax by Ay,
and the point "d" has coordinates (xo,yo), the interpolated radiosity value J that is
assigned to a point inside the rectangle having the coordinates (x,y) is given by
J~~X-( =J,
x-x,
36
y-y
Ax
A
j~.X
3+J
-
1
A
Ax
+Y
)~YY
(X
Ay
")
+
-
1
xJ1
Ax
Y
-f~YoIK .o (3.7)
Ay
Added Fringe Points
b
a
0d
C
-A
0
c
Interpolated Point
d
C
*
0
e
e
0
Boundary of 2x2 Sur face
0
Original Grid Point (radiosity value
applies to area of surrounding square)
Figure 3.5. Bilinear interpolation procedure
* BLIND REFLECTIONS
The daylighting program accounts for light reflecting off blind surfaces, but the
distribution on the walls and ceiling of light emanating from the blinds is too detailed
to be represented meaningfully at low resolutions. Therefore, these reflections are
calculated prior to the iteration phase, so that light from the blinds is applied to the
interior surfaces along with the initial sunlight distribution. The blinds are not
involved in the radiosity equilibrium carried out during the iteration phase; the
iterations involve only the 5 principal interior surfaces of the room.
By adding blinds to the basic room model, we change only the initial distribution of
sunlight in the room. Blinds span the window opening and can be tilted at any angle.
37
Light intercepted by the blinds is either reflected into the room, absorbed, or reflected
to the exterior. To account for the light reflected into the room, we assume that each
blind slat is a diffuse reflector of uniform emissivity. Although, in a real room, blinds
would participate in a radiation exchange with the other surfaces, we account only for
sunlight initially reflected from the blind slats, making this reflected light part of the
initial sunlight distribution that prevails in the room before reflections between
surfaces are calculated. A blind surface is considered to be illuminated by the sun if
the line of sight between the sun and the center of the blind slat is not interrupted by
the edge of the adjacent blind. A section of the ceiling (or wall) is illuminated in turn
by light reflected from the blind slat if there is a line of sight between the center of the
section and the center of the slat (Fig. 3-6). In calculating the view factor between
the blind slat and sections of the inside surfaces, we use the discrete view factor
developed above for the radiation exchange between surfaces (eq. 2.4). In this
calculation, each blind slat is treated as a single element whose position is the
geometric center of the slat. However, because this simplification causes areas of
the ceiling directly over the blind slat centers to receive more light than those areas
over the ends of the slat, the calculated view factors are averaged in the direction
along the slat, and that average value used for the view factor between blinds and
ceiling.
38
~1
Maximum sun elevation
to illuminate slat
slat
-
Blind slat centerline sets:
1. Limit of sun's
Illumination of slat
2. LImit of diffuse reflection
to Interior surfaces
Figure 3-6. Reflection field from a blind slat
To account for the obstruction of direct sunlight by blinds in the window, we
determine the position of the blind shadows. The extent of the shadow cast by each
blind slat on the walls and floor is calculated using the same basic trigonometry from
which the boundaries of sunlit regions were found in Chapter 2. The method for
altering the radiosity grids so that they display blind shadows is explained in Chapter
4.
39
e
DAYLIGHTING RESULTS
The daylighting tool was originally designed to produce a visual output - a 3dimensional view of a room that would give a qualitative sense of the light distribution
in a room lit only by natural light. This picture output from the program is based on
numerical results for the radiosities at each data point inside the room, which are
each associated with a region of the picture and prescribe the particular shade of
gray to be displayed in that region. The data point values are also used in a second
feature of the daylighting tool, in which the simulation cycles through many hours of
daylight in a given room and records the amount by which the local radiosity falls
short of some required minimum during each hour. By summing the shortfalls from
all points on the grid, an hour-by-hour history of the total lighting "deficit" can be
assembled, and a prediction made as to the amount of supplementary lighting
required.
The accuracy of the daylighting model can be judged by comparing the numerical
output values from the simulation with the output from third-party rendering software.
We used Lawrence Berkeley Labs' Radiance[3] on a Sony VAIO Pentium2 with 64
Mb RAM. Radiance is a general-purpose rendering program that can be
programmed to illuminate any surface geometry and accommodate any degree of
transparency or reflectivity in the surface materials, as well as handling light sources
and color. The accuracy of our "initialization" routine, in which areas of the room that
are lit directly by sunlight are identified, can be verified by a visual comparison with a
Radiance model created using the same sun position. The accuracy of the diffuse
reflection scheme used in our model is more difficult to verify. Ideally, we would like
to isolate the reflected light from the direct sunlight in both room models (ours and
40
the Radiance model), and compare equilibrium radiosity values at corresponding
positions in each room. We were able to run our model in parallel with a Radiance
model in the absence of direct sunlight, by defining the window panel as an opaque
surface that glows with the same intensity of diffuse light in both cases.
Unfortunately, it is difficult to calibrate the overall brightness of our diffuse window
surface with the window in the Radiance model, because of the restrictions that
Radiance places on locations around the room where radiosities can be measured
quantitatively by the user. It is not possible in Radiance to ascribe an initial diffuse
brightness to the window surface, as we do in our own code. Instead, a diffuse light
source must be established outside the window, and the light intensity set so as to
produce the right level of brightness close to the inside window surface, where a
measurement is made. This measurement can be made no closer than half an
element-width from the window pane, and the agreement in absolute intensity
between our model and the Radiance simulation is only approximate. We therefore
tried to find a correspondence between the trends of light distribution in each of the
models, rather than a strict agreement between the absolute magnitudes of the
radiosities in each model.
The comparison of models was carried out using a room with a floor area of 4m wide
by 6m deep (in the direction away from the window plane), and 4m in height. The
window sill is set at .6m above the floor, and the head of the window at .6m below
the ceiling. All interior surfaces have 30% reflectance, and the grid of data points in
both models measures 7 by 7 points on each surface. Blinds were not included in
the comparison. Two sets of data from the Radiance model were available: the
radiosity distribution after one reflection-iteration (bounce) and the slightly more
41
Floor Diffuse Brightness, Longitudinal
2.5
02
2
- - MIT Model
1.5
-ca 1
Radiance, 1
bounce
Radiance, 2
bounces
0 0.5
0
1
2
3
4
5
6
7
Distance from Window Plane (Grid Row Number)
Left Wall Diffuse Brightness, Longitudinal
.2
3
2
--
MIT Model
-N-
Radiance, 1
bounce
Radiance, 2
bounce
0
1
2
3
4
5
6
7
Distance from Window Plane (Grid Row Number)
Figure 3-7. Comparison between MIT Design Advisor model results and a Radiance simulation
in the longitudinal direction (towards and away from the window)
42
Floor Diffuse Brightness, Transverse
2.5
0
2
-+-MIT Model
1.5
--
Radiance, 1
bounce
. .......
.U
Radiance, 2
bounces
0.
.2 0.5
0
1
2
3
4
5
6
7
Distance from Left Wall (Grid Row Number)
a.
Left Wall Diffuse Brightness, Transverse
4-
.2
"0
3
-+-MIT Model
-U-Radiance, 1
2_
bounce
Radiance, 2
bounce
..
...
..
"I,
CL
0
1
2
3
4
5
6
7
Distance from Floor (Grid Row Number)
b.
Figure 3-8. Comparison between MIT Design Advisor model results and a Radiance simulation
in the transverse direction (parallel to the window)
43
refined distribution after two. Since the window's sill and head both have the same
thickness and since only diffuse light comes from the window, the lighting pattern on
the floor is symmetrical with that on the ceiling, and the two walls have identical
patterns also. To make a numerical comparison between our model and Radiance,
we condense the 2-dimensional surface arrays into 2 data loci by averaging the
surface radiosities in each of the two directions in turn. By comparing the loci on a 1dimensional basis, we observe that the correspondence between the two programs
is generally stronger in the longitudinal direction, perpendicular to the plane of the
window (Fig. 3-7). In the transverse direction, the floor and ceiling show good
correspondence (Fig. 3-8a), but there is disagreement between the two
representations of the walls (Fig. 3-8b). The values of radiosities in different parts of
the room in relation to each other show almost identical trends in the two models. To
produce the results shown in Figs. 3-7 through 3-9, we increased all of the radiosities
in the MIT model by a constant factor to compare trends in the light distribution
independent of overall brightness.
To clarify some of the inconsistencies between the plots of Radiance surface
brightness and the surface brightness recorded from our model, we ran a longer
simulation using 20 grid points on each side instead of 7. The results are plotted in
Fig. 3-9. Viewing the light distribution at a higher resolution helps to explain the
diverging plots in Fig. 3-7a. The model's higher-than-expected value for grid 1 in Fig.
3-7a is apparently spurious, since the higher-resolution data drops off to a much
lower value at the same distance from the window (Fig. 3-9a). This discovery does
not resolve the discrepancy between the two models in Fig. 3-7a, but it does suggest
that errors in the MIT model at positions close to the common edge of two surfaces
44
Floor Diffuse Brightness, Longitudinal
2.5
2
C
2
1.5
---
MIT Model
1
0
V
M.
(x
0.5
0
1
2
3
4 5
6
7
8
9 10 11 12 13 14 15 16 17 18 1920
Distance from Window Plane (Grid Row Number)
a.
Left Wall Diffuse Brightness, Transverse
4 ,
.2
3
-+-4-MIT Model
2
...........
C1
0
.2
1
2
3
4
5
6
7
8
9 10 11 12 13 14 15 16 17 18 19 20
Distance from Floor (Grid Row Number)
b.
Figure 3-9. High-resolution results from the MIT model for both longitudinal and transverse
directions
45
Figure. 3-10. Visual output from the MIT program, without blinds (top) and with (bottom). Comparable
simulations in Radiance are pictured at right, along with the duration of the test
might be artifacts of the discretization process. We also observe a discrepancy
between the plots of wall brightness in the transverse direction; the Radiance plot
indicates a fairly uniform radiosity distribution across the wall surface in the vertical
direction, whereas the MIT model shows brighter values at the wall's midsection.
The more highly resolved plot of the model's outputs (Fig. 3-9b) shows a previously
unseen inflection in the radiosity curve, corresponding to the upper and lower edges
of the window (the left and right ends of the plot). This expected signature is not
found in the Radiance plot (Fig. 3-8b), which suggests that a finer mesh than 7-by-7
is required for Radiance to be used as a reliable control in this instance. The visual
output from the program is similar to a Radiance image when the same scenarios are
run in parallel. Regions of light and dark in the Radiance image are well preserved in
the more rapid MIT simulation (Fig. 3-10).
e LIGHTING ENERGY ESTIMATION RESULTS
The radiosity values recorded for each grid element can be used to determine how
effectively daylight will illuminate a room without the aid of electric lights. An
architect designing an office space will be aware of the lighting requirement for the
type of work that will go on in the office. This amount is usually given in lux (lumens
per square meter) incident on the work surfaces in the room. We would like to be
able to detect the light level across the workplane, fixed some distance above the
floor at the height of a desk. By creating a new surface, giving it the coordinates of
the workplane, and illuminating it with both direct sunlight and light reflected from the
room's other interior surfaces, we can determine radiosity values at the workplane.
If the sunlight that reaches the workplane does not meet the lighting requirement
specified by the architect, the difference would be made up by electric lights, and the
47
ONE","
9*
-
8
8-9
7
~6-7
5 5-6
5-
.4-5
4 -
03-4
600-
02-3
2-
*1-2
0
a.
9
8
5
7-1
6-
54-
M8-9
07-8
M6-7
E) 5-6
04-5
133-4
02-3
M 1-2
3
2
001
Figure 3-11. Graphs of radiosity across a floor surface, represented as a "terrain." In b.,
setting the floor's minimum radiosity level is analogous to "pouring water"
onto the terrain
48
yearly electricity requirement could be calculated from a knowledge of the sun
position and intensity during each hour of the year. The sunlight distribution can be
thought of as defining a topography over the workplane surface, with areas of high
radiosity represented by hills and darker areas represented by valleys, as in Fig. 311 a. To this "landscape" we add light from electrical sources. The simplest way of
modeling the light distribution from electric bulbs is to assume that a certain intensity
of light can be commanded for each individual grid element of the workplane. If we
assume that electric light can be delivered in this way, it can be added to the original
sunlight illuminance until the lighting requirement for the workplane is satisfied for
each element of the grid. In our topographic analogy, this is equivalent to pouring
water onto the "landscape" defined by the sunlight distribution. The height of the free
surface of the water and/or land represents the light intensity at any given position on
the grid. We add water until the free surface reaches the height corresponding to the
prescribed lighting requirement (Fig. 3-11b). When this point is reached, the
electrical light will have met the lighting requirement using the most efficient
distribution possible. The surface level is everywhere equal to the requirement,
except in those places ("islands") where the intensity of sunlight alone is greater than
the lighting requirement.
Using the maximally efficient distribution of electric light, we can predict the amount
of energy used by the lighting systems during a given hour. We use a quantity called
the lighting "deficit" to represent the difference between the light provided by the sun
and the total requirement for the office. The deficit is calculated every hour during a
49
Lighting Energy Deficit for Working Hours
70
- London
- 400 Lux min.
CI
60-
light level
- West-facing
50
-0
40
-----
0
0I
...
r~
30 -
--
.1
$2m
depth
-N-6m
1Om
15m
20m
20
10
0
1
2
3
4
5
6
7
8
9
10
11
12
Month (Jan = 1)
a.
Average Lighting Deficit
35
- London
- 400 Lux min.
level
light level
- West-facing
30 30
25
20
0
0
15
10
5
0
2m
6m
lOn
15m
20m
Depth of Room (m)
b. '
Figure 3-12. Change in the lighting deficit with varying room depth
50
Average Lighting Deficit, Cairo (Working Hours)
Room Depth = 16m
9
07
im05
5.F 4
-
U)
0
2L --1%-0
north
south
east
west
Orientation
a.
Average Lighting Deficit, Anchorage (Working Hours)
Room Depth = 16m
25
S
20
15
Uo 10
0
0
0
0
north
south
east
west
Orientation
b.
Figure 3-13. Change in the lighting deficit with varying building orientation
51
simulation run, using a sun position and solar direct and diffuse light intensities
specific to each hour.
In Fig. 3-12a, the lighting deficits, averaged by the month, are shown for an office
room situated in London with a west-facing view from a single, wall-spanning
window, a workplane 0.5m off the floor, 4m high and 6m wide, with 0.6-m margins
above and below the window (height = 2.8m). The interior walls have an emissivity
of 0.4. For a minimum lighting requirement at the workplane, we are using 400 lux,
the European Union standard. This is also the maximum possible deficit - the
amount of lighting that must be provided artificially when no light enters from outside
(night conditions). The depth of the room is varied along the abscissa in Fig. 3-12b,
showing an exponential increase in average electricity demand as the room becomes
deeper in the dimension perpendicular to the window. Figure 13 shows the variation
of required lighting energy by room orientation. A north-facing room (in the northern
hemisphere) receives no direct sunlight, while a room with a southern prospect
receives some direct light during every hour that the sun is visible. A west-facing
building is exposed to direct rays for only half the day, but because of the low angle
of incidence towards sunset, may receive more daylight overall than a south-facing
window, as in the case of Cairo (Fig. 3-13a). As we would expect, at higher latitudes
the incidence angle on the south face decreases, and the share of direct sunlight
goes up relative to the west-facing window, as in Fig. 3-13b (Anchorage). Fig. 3-14
shows a range of average deficits for various cities ordered from north to south. In
Cairo, the most southerly location, electrical lighting accounts for only 3.9% of the
total lighting requirement for the working surfaces.
52
Lighting Energy Deficit for Working Hours
Room Depth = 10m
70
-
60
50
-
40
-
-- Anchorage
--
0
London
Chicago
Cairo
30
0
20
10
0
1
2
3
4
5
6
7
8
9
10
11
12
Month (Jan = 1)
a.
Average Lighting Deficit for Working Hours
Room Depth = 10m
18
-
x16
%
14
12
E
o
0
b.
0
10
8
6
Fu 4 Chne
0
nte__hinectwihvryn___to
2
anchorage
london
chicago
cairo
Location
b.-
Figure 3-14. Change in the lighting deficit with varying location
53
Such results are useful for comparisons of energy cost between different scenarios,
but to assess the real impact of a lighting configuration on the cost of building
maintenance, we must find a way to equate electrical lighting energy costs with other
expenses such as cooling and heating. One possible point at which to establish
parity between these different energy quantities is at the power plant, where a
chemical form of energy is converted into heat or electricity. We say there is a 1-to-1
conversion of chemical energy into heating energy, since fuel in the form of oil or
natural gas is almost fully combusted within the building to produce heat for the
rooms. Thus,
E
E H healers
(Ieaters
where E
(3.8)
is the chemical energy consumed at the building plant, and
EHhactr
is the
amount of heating energy produced by the operation of the heaters.
Electrical energy used for chillers and air conditioners inside the building represents
perhaps one-third of the energy embodied in the chemical fuel consumed for its
production. However, given an average coefficient of performance of 3 for the
refrigeration of building air, the amount of energy removed from the air is about equal
to the chemical energy converted to run the chillers:
c hillers
-"E
-
chillers
electric
E
E(
chE
rS =
'clers
E
1
="eectric C
54
chillers
E" cillers
H Chillers
(3.9)
where EEchillers is the electrical energy used by the chillers and
leec,,,c
is the
conversion efficiency (usually taken to be around 0.3).
The amount of chemical energy effectively consumed for the sake of a given amount
of lighting energy is as follows:
1
E ' lights
17
E E lights
EElights
electric
=
-
E
lighis
'lum
1
I
E lIight
7
electric
7
Eght
(3.10)
,
lum
where E'tight. is equal to Iart (the illuminance by artificial light defined in eq. 2.5),
multiplied by duration and area of coverage. The energy contained in the illumination
of the workplane by electric lights is related to the electrical energy input to the lights
This number can be anywhere from 0.019 for incandescent lights, to 0.14
by 77,,,.
for fluorescents. By expressing the consumption of lighting energy as a cost at the
power plant, we generally find that the cost of electric lighting is on the same order as
the cost of heating and cooling. Unless the light fixtures are deliberately cooled, the
electricity used reduces the heating load by the amount of electrical energy that is
dissipated as heat in the fixture. Assuming that any electrical current is ultimately
released into the room as heat, we can expand eq. 3.8 in the following way:
E
Cradiators =E H radiators
EH
gits
=
FE lights
=
L
H load,healing
-
E
-
E
H lights
iights
11lum _
55
radiators :::
E H lod heating
-I
ELlg
(3.11)
E' ii gis
(3.12)
similarly for the cooling load,
E('
enil
=
Er
load,cooling +[
L hun
_
The Design Advisor website presents heating, cooling, and lighting energies in terms
of the total required chemical energy, E" , based on simulation data for the values of
E~load,eating , E
56
load,cooling ,
and ELuiglsj, for each hour of the test.
CHAPTER 4: DETAILED METHOD
o BASIC ROOM OBJECTS
The simulation code for the program has been written in Java, an object-oriented
language. The program is built of separate groupings of code called "classes," each
of which contains the instructions for a certain "object," or component of the
simulation, such as the blinds or the view factors. Once a new simulation has been
ordered by the user, the first task of the software is to construct a room full of virtual
objects in which to perform the daylighting calculations. The parameters specified by
the user are used to create a "Map" object, of which each room is an instance, and
which itself creates all other objects found in the room, including all the interior
surfaces (see flowchart, Fig. 4-1).
The "Surface" class is the basic element in the daylighting model. A room can
contain several surfaces and a set of blinds. The Map class that defines each room
in our program also contains various features that are permanently associated with
any room, including routines that can be used to access information about the state
of the room or its contents, storage space for the view factors between all possible
permutations of surface elements, and software to allow one map to be added to
another, producing a superposition of the two daylighting patterns.
The surface object is the storage area where the simulation results are recorded in
the form of radiosity values for each of the surface grid points. The surface file also
retains information about the geometric dimensions of the surface and its grid point
resolution. It is equipped with methods that allow a surface object to respond to
57
oto
00
-ft
Process
AN
Figure. 4-1. Flowchart describing the operation of one siumulation cycle
Object
requests from the room object of which it is a part. The blinds are organized in a
single package called a "BlindSet." The BlindSet object contains an array where it
stores each of the blind slat objects. The BlindSet retains parameters referring to
groupings of blind slats, such as the spacing between them, and handles all
negotiations between the blind slats and the rest of the room.
e INITIALIZATION ROUTINES
To create a pattern on the inside surfaces where sunlight from the window would
directly illuminate the interior, initialization routines must be adjusted for each
particular kind of surface. One class, called "Surfacenitializer, "has been written as
a universal template for applying a sunlight-pattern to interior surfaces. Different
implementations of the template for floors and ceilings, windows, and walls, extend
the generic methods in Surfacelnitializer to the case of a surface of one particular
orientation.
Using trigonometry, we find the distance from the window plane at which an observer
at the level of the floor can just see the sun over the window sill. This is the minimum
extent of the patch of sunlight on the floor, and the maximum extent, where the head
of the window finally blocks the sun, can be calculated in the same way. To set the
grid points on the floor to register a brightness due to the sunlit region, we find the
rank of grid points in the floor's 2-D grid point array that most closely corresponds to
the theoretical "minimum extent." Then, we begin assigning to this rank and all
successive ranks up to the "maximum extent," the radiosity value that matches the
brightness of reflected sunlight.
59
This procedure must be repeated in the direction parallel to the window surface,
using a slightly different formula. The previous step left a band of illuminated grid
points spanning the floor parallel to the window. However, the left and right
boundaries of the window area will cast a diagonal shadow on the floor, for which the
previous technique of simply blocking out ranks of the data grid is not adequate.
Instead, each rank of grid points that is partly in shadow must have part of its rank
blocked and part left illuminated. In other words, within the "for-loop" structure that
advances away from the window at each increment to treat the next rank of grid
points, there must be nested a second for-loop, which advances parallel to the
window, point-by-point, to set boundaries on the illuminated part (Fig. 4-2).
For-loop #1:
Sets near and far extent
of illumhuted region
For-loop #2:
Further constrains
illumkirted region
(Plae of Window)
Figure 4-2. The sunlit region of a surface (the floor in this case) is first defined as a band of
light between two lines parallel to the window. Then, a further limit on the
region is imposed by moving rank-by-rank in the vertical direction and
assigning individual limits in the horizontal direction for each rank
The foregoing discussion has assumed that no blinds have been used in the window.
For this simplified case, the walls and the floor and ceiling use almost identical
methods to assign values to grid points in direct sunlight. However, when blinds are
60
used, the shadows cast on the floor look different from those on the walls. In the
case of the floor, it is relatively simple to include blind shadows in the sunlight
pattern: the blind slats cast rectangular shadows that run parallel to the window
plane. To locate the blind shadows on the floor grid, we use the same procedure as
we used to find the end of the sill shadow (the minimum extent of the sunlight) and
the beginning of the head shadow (the maximum extent) in the case without blinds.
We now apply the same technique to find the end of the shadow of one blind slat and
the beginning of the shadow of the next. The blind shadows are not applied directly
to the radiosity grid, but to a linear array representing the dimension running from the
window to the back wall. The array consists of values of "1" and "0," and values of 1
are entered for cells corresponding to distances from the window at which a strip of
sunlight penetrates through the blinds. Each rank of the grid containing the actual
radiosities at each of the grid points is then multiplied by each successive element of
the array of 1s and Os. Using this method, we can start with a sunlight pattern
calculated without blinds, and then apply blind shadows to it, darkening the blindshadowed regions shaded by multiplying the corresponding grid points by the zeros
in the array.
Blind shadows cast on the walls have a diagonal pattern, so it is not possible simply
to multiply each rank of the wall data grid by a linear array containing the shadow
pattern. However, the blind shadows do run parallel to the edges of the original
window-frame shadow, so a linear array can be used if it is applied starting with the
lower edge of the diagonal sunlight pattern on the wall. A for-loop cycles through the
ranks of wall grid points from the window surface to the rear wall, registering the blind
shadow array with the beginning of the sunlight pattern for each new rank. By
61
multiplying each rank by a 1 or 0 from the blind shadow array, a diagonal blind
shadow is superimposed on the original sunlight pattern.
The pattern of light on the walls and ceiling includes light reflected from the blinds.
To calculate this contribution to the initial sunlight distribution, we consider the blinds
to be diffuse reflectors, and calculate view factors between the blind slats and each
rectangular surface element represented by a grid point. To reduce the computation
time, each blind slat is considered to be a single element, and the view factors taken
in respect to the position of the center of the slat. We have remarked that one
undesirable side effect of this simplification is that a much larger view factor is
calculated for regions of the ceiling directly above the center of the slats, than for
parts of the ceiling over the ends of the slats. If the problem were not corrected, a
concentration of light would appear on the ceiling over the meridian of the window
pane. Instead, we have calculated view factors between each blind slat and each
surface element along each row from wall to wall across the ceiling. For each row,
we find the average of all the view factors, and use that average as the new view
factor for all surface elements in the row.
Reflections from blind slats may be intercepted by other blinds. To account for this
interference in a simple manner, we assume that:
1. A blind slat is fully illuminated by the sun if the line of sight from the center of the
slat area to the sun is unobstructed, and otherwise the slat is illuminated not at
all.
62
2. A surface element of the ceiling or wall is illuminated by reflections from the blind
slat, using the view factor involving the entire area of the slat, if the line of sight
with the slat center is unobstructed, and otherwise there is no reflection to the
surface element.
Both criteria are applied at the stage when the additional light due to the reflection
from each blind is transferred to an interior surface element. Each criterion is
represented by a test routine which returns a "0" if line-of-sight is broken, and a "1" if
it is intact after the test. The amount of reflected light that stands to be applied to the
surface element is then multiplied by each value returned, so that only if all tests are
passed is there any contribution of reflected light from the slat in question. Each
criterion can be tested by calculating the angle of elevation of the line drawn between
the blind center and the surface element. This angle is compared with a maximumangle-for-unobstructed-sight, which is found as a function of the surface element's
coordinates, the slat number and spacing, and the sun elevation.
* REFLECTIONS
The consideration that limits the resolution at which reflections can be calculated is
the number of times that a view factor must be calculated between two surface
elements in a room (the transmitting element and the receiving element). The
number of these calculations is given by the square of the total number of elements,
since for each element, we must be able to determine the light contribution from each
other element according to a mutual view factor. Because the interior surfaces are
flat, we assume that reflections are not exchanged between two elements of the
same surface. The view factors between different elements need only be calculated
once, just before the first round of reflections (the first "bounce") is performed.
63
Assuming that enough space can be reserved in memory, the view factor values may
then be retained in memory and accessed quickly during successive bounces. A
class called "Iterator" has been built to update radiosity values around the room with
the contributions of reflected light. It manages the creation and referencing of view
factors so that the time-consuming view factor calculation need only happen once.
* SMOOTHING
The daylighting simulation creates two separate versions of a room: the first is a
high-resolution model in which direct sunlight has been applied to the interior
surfaces but reflections have not been calculated. The second is a low-resolution
model initialized in the same way, but in which the reflection procedure has
proceeded to equilibrium. To combine the two models in the program's final output,
we have written a set of routines to transfer the low-resolution data to a highresolution grid, then smooth the data and add it point-by-point to the existing highresolution model.
Because grids cannot be added or subtracted unless they are of exactly the same
dimensions, at least one of the grids involved in the operation must have its
dimensions altered to accord with the dimensions of the other grid. To make it clear
which set of dimensions are being used, we have made it the responsibility of each
surface to create an algebraically compatible version of any other surface that is
passed to it, so that it can then conduct the addition or subtraction at its own original
resolution.
64
Methods for adding one set of grid data to another are embedded in the Surface
class, where the grid data (the radiosity values) themselves are also stored. A
surface object can pass grid data to a class called "Bilinear," which is the unit
responsible for expanding or reducing the scale of a grid. To add low-resolution
model data to a high-resolution model, the program employs a method called
"Add RadiositiesFrom" in each of the "surface" objects of the high-resolution model.
A reference to the low-res surface to be added is passed to the
"AddRadiositiesFrom" method of the high-res surface. The high-res surface can then
create a "Bilinear" object out of the grid from the low-res surface. The low-res
surface grid, packaged in this new "Bilinear" object (see flowchart, Fig. 4-1), can be
expanded and smoothed using methods in the Bilinear class, and the resulting grid
added to the high-res surface's grid of radiosities.
65
66
Bibliography
1 [MIT 1999]
2
[Arons 2000]
MIT Design Advisor website. http://18.80.2.250:8080/design
Arons, Daniel M. M. Properties and Applications of Double-Skin Building
Facades. Masters Thesis for the Department of Architecture, MIT.
Cambridge, Massachusetts: 2000.
and
[Lehar 2001]
Lehar, Matthew A. and Leon Glicksman. A Simulation Tool for Predicting the
Energy Implications of Advanced Facades. MIT Building Technology
Division. Cambridge, Massachusetts: 2002.
3
[DOE 2001]
EnergyPlus building energy simulation program. Produced and distributed by
the U.S. Department of Energy. Available at
http://www.eren.doe.gov/buildings/energy tools/energyplus/
4 [LBL ]
Radiance rendering software. Produced and distributed by Lawrence
Berkeley Labs. Available at http://radsite.lbl.gov/radiance/HOME.html
5
[MeteoTest 2000]
MeteoNorm Global Meteorological Database for Solar Energy and Applied
Climatology. CD-ROM by MeteoTest, Bern: 2000.
6
[Larson, 1997]
Larson, Gregory Ward, Holly Rushmeier, and Christine Piatko. A Visibility
Matching Tone Reproduction Operator for High Dynamic Range Scenes.
Berkeley, California: 1997.
67
68
Appendix: Program Code for the Lighting Module
The Java source code for the Illumination Module of the Design Advisor tool is
presented in the following section.
List of Classes Used in the Program.............................. 70
Program O rganization...............................................
71
Index of Method and Variable Names...............................
72
PROG RAM CODE.....................................................
91
69
1. List of Classes Used in the Program
o
70
class java.lang.Object
o class illumination.ArrayMaker
o class illumination.Azimuth
o class illumination.Bilinear
o class illumination.BinSorter
o class illumination.Blind
o class illumination.BlindSet
o class illumination.Box
o class illumination.FileOut
o class illumination.Fringer
o class illumination.GrayScaleConverter
o class illumination.Illumination
o class illumination.Initializer
o class illumination.Interpolator
o class illumination.Iterator
o class illumination.MaD
o class illumination.PerspectiveView
o class illumination.Point3D
o class illumination.PVTest
o class illumination.Ouadrant
o class illumination.Resizer
o class illumination.SettingSuite
o class illumination.SolarlnfoCalculator
o class illumination.SolarSuite
o class illumination.Surface
o class illumination.Facade
o class illumination.Platform
o class illumination.SideWall
o class illumination.SurfaceInitializer
o class illumination.Facadelnitializer
o class illumination.Platformlnitializer
o class illumination.FloorCeilin2lnitializer
o class illumination.Workplanelnitializer
o class illumination.SideWalllnitializer
o class illumination.ViewFactorSuite
o class illumination.ViewFactory
o class illumination.Wall
o class illumination.WeatherDataReader
o class illumination.WindowSuite
o class illumination.WorkplaneBay
2. Program Organization
Program Classes
I
creates:
JMNM
_FMNIMW
-am
-low
L
71
3. Index of Method and Variable Names
A
a - Variable in class illumination.Surface
Resolution in the principal dimension of the surface.
a - Variable in class illumination.Surfacelnitializer
A - Variable in class illumination.Surface
Array of differential areas of each element that makes up the surface.
addRadiositiesFrom(Map, String!, Stringz) - Method in class illumination.Map
Adds or subtracts the radiosity values of the input Map from the dereferenced Map.
addRadiositiesFrom(Surface, String, String) - Method in class illumination.Surface
alpha - Variable in class illumination.Surface
"alpha," "beta," and "gamma" take values of either 1 or 0.
angleOnSurface - Variable in class illumination.Surfacelnitializer
applyPatchOfSunlight(String) - Method in class illumination.Facadelnitializer
applyPatchOfSunlight(String) - Method in class illumination.FloorCeilinginitializer
applyPatchOfSunlight(Strin2) - Method in class illumination. SideWalilnitializer
applyPatchOfSunlight(String) - Method in class illumination.Surfacelnitializer
applyPatchOfSunlight(Strin) - Method in class illumination.Workplanelnitializer
ArrayMaker - class illumination.ArrayMaker.
ArrayMakerO - Constructor for class illumination.ArrayMaker
Azimuth - class illumination.Azimuth.
Azimuth(double, String) - Constructor for class illumination.Azimuth
Azimuth(double, String, double) - Constructor for class illumination.Azimuth
B
b - Variable in class illumination.Surface
Resolution in the second dimension of the surface.
b - Variable in class illumination.Surfacelnitializer
72
beta - Variable in class illumination.Surface
"alpha," "beta," and "gamma" take values of either 1 or 0.
Bilinear - class illumination.Bilinear.
Bilinear(doublef][1, int, int) - Constructor for class illumination.Bilinear
Reads in input array, creates output buffer, assigns dimensions to the output buffer,
and puts a fringe on the output buffer
bilinearlnterpolateO - Method in class illumination.B ilinear
bilinearlnterpolate(doublel l[ 1) - Method in class illumination.Interpolator
BinSorter - class illumination.BinSorter.
BinSorter(double, double, double) - Constructor for class illumination.BinSorter
Blind - class illumination.Blind.
Blind(double, double) - Constructor for class illumination.Blind
blinds - Variable in class illumination.Map
BlindSet - class illumination.BlindSet.
BlindSet(int, double, double, double, double, double) - Constructor for class
illumination.BlindSet
blindSpacing - Variable in class illumination.SettinaSuite
blindSpacing - Variable in class illumination.Surfacelnitializer
blindStartEndDistances - Variable in class illumination.Surfacelnitializer
blindStartEndlndeces - Variable in class illumination. SurfaceInitializer
blindViewFactorArray - Variable in class illumination.Map
blindViewFactorSum - Variable in class illumination.Surfacelnitializer
blindWidth - Variable in class illumination.Surfacelnitializer
blocki - Variable in class illumination.Surfacelnitializer
block2 - Variable in class illumination.Surfacelnitializer
Box - class illumination.Box.
Box(double, double, double, double, double, double) - Constructor for class
illumination.Box
73
C
calculate(int, int, double, double) - Method in class illumination.Azimuth
calculateAn2leOflncidence(double, double) - Method in class illumination.Azimuth
calculateAn2leOflncidence(double, double, double) - Method in class
illumination.Azimuth
calculateDeclination(double) - Method in class illumination.Azimuth
calculateDiffuseSolarGain(double, double) - Method in class illumination.Azimuth
calculateDirectSolarGain(double, double) - Method in class illumination.Azimuth
calculateFirstReflectionFromBlinds(BlindSet, boolean, ViewFactorSuite, Surface) Method in class illumination.Facadelnitializer
calculateFirstReflectionFromBlinds(BlindSet, boolean, ViewFactorSuite, Surface) Method in class illumination.Platformlnitializer
Only one view factor is computed between each blind slat and each element of the
platform (i.e.
calculateFirstReflectionFromBlinds(BlindSet, boolean, ViewFactorSuite, Surface) Method in class illumination.SideWallInitializer
calculateFirstReflectionFromBlinds(BlindSet, boolean, ViewFactorSuite, Surface) Method in class illumination.Surfacelnitializer
calculateHourAngde(double) - Method in class illumination.Azimuth
calculateSolarRadiationGain(double, double, double, double, double) - Method in class
illumination.Azimuth
calculateSurfaceSolarAzimuth(double, double) - Method in class illumination.Azimuth
calculateWorkplaneLightLevels(SolarSuite, WindowSuite, double) - Method in class
illumination.WorkplaneBay
CALCULATEWORKPLANELIGHTLEVELSO
centerInZ() - Method in class illumination.BlindSet
cleanUpO - Method in class illumination.Map
clearBilinearGridO - Method in class illumination.Surface
columnTemplate - Variable in class illumination.Surfacelnitializer
74
computeViewFactor(double, double, double, double, double, double, double, double,
double, double, double, double, double) - Method in class illumination.ViewFactory
computeViewFactorWithBlinds(Surface, int, int, int, BlindSet, double) - Method in class
illumination.ViewFactory
constantCoordinate - Variable in class illumination.Surface
Position of the surface in the dimension normal to the surface.
constructSurface(String, int, int, double, double, double, double) - Method in class
illumination. Surface
Defines surface variables and allocates space for the surface's data arrays.
convertRadiositvToGrayScale(double) - Method in class illumination.GrayScaleConverter
convertRadiosityToGrayScale(double, double) - Method in class
illumination.GrayScaleConverter
createSurfaceFile(double[lff) - Static method in class illumination.FileOut
createSurfaceFile(doublell HIi) - Static method in class illumination.FileOut
createSurfaceFile(doubleH 11, Strins!) - Static method in class illumination.FileOut
createSurfaceFile(Surface) - Static method in class illumination.FileOut
createWorkplanes(double, int, int, int, int) - Method in class illumination.Map
crossDistance - Variable in class illumination.Surface
Magnitude of the distance across the surface in the direction of "b."
crossDistance - Variable in class illumination.Surfacelnitializer
cumulativeDistributionFunction(double) - Method in class illumination.BinSorter
currentSurface - Variable in class illumination.Surfacelnitializer
D
degToRad(double) - Method in class illumination.Surfacelnitializer
depthMagnitude - Variable in class illumination.SettingSuite
depthResolution - Variable in class illumination.SettingSuite
diffIntensity - Variable in class illumination.SolarSuite
difflntensity - Variable in class illumination.Surfacelnitializer
drawImage(int, int, int) - Method in class illumination.PerspectiveView
75
E
emissivity - Variable in class illumination.SettingSuite
emissivity - Variable in class illumination. Surface
emissivity - Variable in class illumination.Surfacelnitializer
F
Facade - class illumination.Facade.
Populates some of the basic arrays for the surface and invokes methods in the
superclass to completely create the surface.
Facade(String, int, int, double, double, double, double) - Constructor for class
illumination.Facade
FacadeInitializer - class illumination.Facadelnitializer.
Facadelnitializer() - Constructor for class illumination.Facadelnitializer
FileOut - class illumination.FileOut.
FileOut() - Constructor for class illumination.FileOut
findAngleOnSurface(double, double) - Method in class illumination.Facadelnitializer
findAngleOnSurface(double, double) - Method in class illumination.Platformlnitializer
findAngleOnSurface(double, double) - Method in class illumination.SideWalllnitializer
findAngleOnSurface(double, double) - Method in class illumination.Surfacelnitializer
findColumnIndexInRow(StringY, double, int, double, double, double) - Method in class
illumination.Surfacelnitializer
Returns an index corresponding to the near or far extent, in the surface's secondary
direction, and within a particular row of elements specified by "presentlndex," of the
patch of sunlight on a surface.
findIlluminatedSide(double) - Method in class illumination.BlindSet
findlndecesOfNearAndFarReach(double[, int, double) - Method in class
illumination.Surfacelnitializer
Returns a 2-element array containing the indeces of the elements on the surface grid
corresponding to the near and far extent, in the surface's principal direction, of the
projection of sunlight.
76
findNearAndFarDistances(double, double, double) - Method in class
illumination.Surfacelnitializer
Returns a 2-element array containing the near and far extent, in the surface's principal
direction, of the patch of sunlight projected from the window upon the walls or floor.
findObliquelntensityFraction(double) - Method in class illumination.Surfacelnitializer
findRadiosityAtPoint(double, double, double, GrayScaleConverter) - Method in class
illumination.Map
Returns a value between 0 and 255 corresponding to the radiosity levels at the
specified coordinates.
The following conventions apply when using this method:
"x" corresponds to the depth (in-out) dimension
"y" corresponds to the height (up-down) dimension
"z" corresponds to the width (left-right) dimension
All coordinates are measured from an origin at the lower, right-hand corner of the
window surface, assuming the window is viewed from inside the room.
Surface numbers run as follows:
0: floor
1: sideWallI (right-hand side)
2: sideWall2 (left-hand side, looking toward window from inside)
3: ceiling
4: window
findReciuiredLightingEnergy(String, String, double, double) - Method in class
illumination.Illumination
The following method is only for testing purposes:
FINDREQUIREDLIGHTINGENERGY() Runs many daylighting calculations at
different times of the day and during different months of the year.
findStrike(double, double) - Method in class illumination.Box
findStrike(double, double) - Method in class illumination.Quadrant
FloorCeilinglnitializer - class illumination.FloorCeilin gInitializer.
FloorCeilingInitializerO - Constructor for class illumination.FloorCeilingInitializer
frinueArray(double[I W[D - Method in class illumination.Fringer
Operates on an array consisting of two, 2-D arrays stacked one atop the other (a 3-D
array with only two elements in the third dimension).
Fringer - class illumination. Fringer.
Fringer() - Constructor for class illumination.Fringer
G
77
gamma - Variable in class illumination.Surface
"alpha," "beta," and "gamma"take values of either 1 or 0.
ietAltitudeO - Method in class illumination.Azimuth
getAltitude() - Method in class illumination.SolarInfoCalculator
ietArrayAndIndeces(double[ W) - Method in class illumination.Resizer
getArrayAndIndeces(double[l[1, int, int) - Method in class illumination.Resizer
Takes a pair of resolutions and returns a 2-D array of two layers (actually a 3-D array).
getAzimuth() - Method in class illumination.Azimuth
getAzimuth() - Method in class illumination.SolarlnfoCalculator
getBlindSpacing() - Method in class illumination.BlindSet
getBlindWidthO - Method in class illumination.BlindSet
getCollectiveAngle() - Method in class illumination.BlindSet
getCollectiveBlindAngle()
- Method in class illumination.Illumination
GETCOLLECTIVEBLINDANGLEO Returns current blind angle.
getCollectiveBlindAngleo
- Method in class illumination.Map
getDepth() - Method in class illumination.Map
Returns the in-out dimension of the room
getDiffuseHorizonta1Radiation(int, int) - Method in class illumination. WeatherDataReader
getDiffuseIntensityO - Method in class illumination.SolarInfoCalculator
getDiffuseRadiationGaino - Method in class illumination.Azimuth
getDirectIntensity() - Method in class illumination.SolarlnfoCalculator
getDirectNormalRadiation(int, int) - Method in class illumination.WeatherDataReader
getDirectRadiationGain() - Method in class illumination.Azimuth
getDryBulbTemperature(int, int) - Method in class illumination.WeatherDataReader
2etEquivalentDistance(int, double, String) - Method in class illumination.BlindSet
getFloorResolution ao - Method in class illumination.Map
getFloorResolution bo - Method in class illumination.Map
getHeightO - Method in class illumination.Map
Returns the up-down dimension of the room
getLatitudeO - Method in class illumination. WeatherDataReader
78
getMonthAveragedWorkplaneO - Method in class illumination.Illumination
The following method is only for testing purposes:
GETMONTHAVERAGEDWORKPLANE()
getNumberCorrespondingToSurfaceName(String!) - Method in class illumination.Map
getNumBlinds) - Method in class illumination.BlindSet
getProiectedDistance(int, String) - Method in class illumination.BlindSet
getRadiositv() - Method in class illumination.Blind
getRadiosity(int) - Method in class illumination.BlindSet
getResolutionOfExistingInputGrid a() - Method in class illumination.Bilinear
getResolutionOfExistinglnputGrid bo - Method in class illumination.Bilinear
getShade(double, double) - Method in class illumination.Wall
2etSolarRadiationGaino - Method in class illumination.Azimuth
2etSurfaceDimension(String) - Method in class illumination.Surface
2etSurfaceNameCorrespondingToNumber(int) - Method in class illumination.Map
2etSurfaceNewResolution(String, int, int, int) - Method in class illumination.Surface
2etSurfaceSolarAzimuthO - Method in class illumination.Azimuth
getUnsmoothedArrayo - Method in class illumination.Bilinear
uetUnsmoothedArray(doublefl ) - Method in class illumination.Bilinear
2etVerticalPositiono - Method in class illumination.Blind
getVerticalPosition(int) - Method in class illumination.BlindSet
getWidth(O - Method in class illumination.Map
Returns the left-right dimension of the room
GrayScaleConverter - class illumination.GrayScaleConverter.
GrayScaleConverter(Map, int) - Constructor for class illumination.GrayScaleConverter
GrayScaleConverter(Map, Map, int) - Constructor for class
illumination.GrayScaleConverter
79
H
H - Variable in class illumination.Surface
"H" is the array of values of the intensity of light that is reflected from a surface.
head - Variable in class illumination.Surfacelnitializer
headHei2ht - Variable in class illumination.WindowSuite
headIndex - Variable in class illumination.Surfacelnitializer
heiihtMagnitude - Variable in class illumination.SettingSuite
heightResolution - Variable in class illumination. SettingSuite
hiResWorkplane - Variable in class illumination.Map
horizontalAngle - Variable in class illumination.Surfacelnitializer
I
illuminateWithSunlight(String, double) - Method in class illumination.Surfacelnitializer
Applies brightness to selected elements of the surface grid, according to a calculation
of which parts of the surface would be reached by the sunlight.
Illumination - class illumination.Illumination.
Illumination(int, double, double, double, double, double, double, double, double, double)
- Constructor for class illumination.Illumination
"Pre-constructor" (2) for constructor No.1 - NO BLINDS.
Illumination(int, double, double, double, double, double, double, double, double, double,
int, double) - Constructor for class illumination.Illumination
"Pre-constructor" (5) for constructor No.3 - INCLUDES BLINDS. Use this FOR
TESTING ONLY if you want to specify the blind angle 11/20/02
Illumination(int, double, double, double, double, double, double, int, double, double,
double) - Constructor for class illumination.Illumination
"Pre-constructor" (3) for constructor No.1 - INCLUDES BLINDS.
Illumination(int, double, double, double, int, RoomDescription) - Constructor for class
illumination.Illumination
Base constructor for Illumination class. Explanations of the input variables are as
follows:
nameOfJob only for your reference
RESOLUTIONx low-res Map resolution
RESOLUTIONFINE x high-res Map resolution
sillHeight height, measured from floor, of bottom of transparent part of facade
headHeight height, measured from floor, of top of transparent part of facade
Illumination(RoomDescription) - Constructor for class illumination.Illumination
"Pre-constructor" (4) for constructor No.1 - INCLUDES BLINDS.
80
imposeBlindSlatShadows(BlindSet) - Method in class illumination.Facadelnitializer
imposeBlindSlatShadows(BlindSet) - Method in class illumination.FloorCeilinglnitializer
imposeBlindSlatShadows(BlindSet) - Method in class illumination.SideWallInitializer
imposeBlindSlatShadows(BlindSet) - Method in class illumination.Surfacelnitializer
imposeBlindSlatShadows(BlindSet) - Method in class illumination.Workplanelnitializer
indecesOfNearAndFarReach a - Variable in class illumination.SurfaceInitializer
indecesOfNearAndFarReach b - Variable in class illumination. SurfaceInitializer
initialize(Surface, WindowSuite, BlindSet, String, boolean, ViewFactorSuite, SolarSuite)
- Method in class illumination.Facadelnitializer
initialize(Surface, WindowSuite, BlindSet, String, boolean, ViewFactorSuite, SolarSuite)
- Method in class illumination.FloorCeilingInitializer
initialize(Surface, WindowSuite, BlindSet, String, boolean, ViewFactorSuite, SolarSuite)
- Method in class illumination.SideWalllnitializer
initialize(Surface, WindowSuite, BlindSet, String, boolean, ViewFactorSuite, SolarSuite)
- Method in class illumination. SurfaceInitializer
initialize(Surface, WindowSuite, BlindSet, String, boolean, ViewFactorSuite, SolarSuite)
- Method in class illumination.WorkplaneInitializer
All arguments to oneWorkplanelnitializer must be from the same room object, except
for blindShadingScheme.
initializeHiResWorkplane(Map, WindowSuite, String, double, SolarSuite) - Method in
class illumination.Initializer
initializeMasksO - Method in class illumination.Surfacelnitializer
rowTemplate columnTemplate these arrays serve as masks: when pointwisemultiplied by the radiosity arrays of a surface, they introduce black (zero-valued)
bands where the shadow of a blind slat crosses that surface.
Initializer - class illumination.Initializer.
InitializerO - Constructor for class illumination.Initializer
initializeSurfaceVariables(Surface, BlindSet, WindowSuite, SolarSuite) - Method in class
illumination.Surfacelnitializer
Defines variables that are surface-specific, and therefore not covered by
"constructSurfacelnitializerInAbstract." Also initializes surface radiosity arrays to
zero.
Interpolator - class illumination.Interpolator.
Interpolator(doublel [1) - Constructor for class illumination.Interpolator
81
isFirstInitialization - Variable in class illumination.Map
isFirstlteration - Variable in class illumination.Map
isFirstWorkplanelnitialization - Variable in class illumination.Map
isFirstWorkplanelteration - Variable in class illumination.Map
iteratedRoom - Variable in class illumination.WorkplaneBay
iterateRadiosityCalc(Map) - Method in class illumination.Iterator
Establishes holding arrays for the view factors between one surface and another.
Iterator - class illumination.Iterator.
Device that can be used to perform reflections between the inside surfaces of a room.
Iteratoro - Constructor for class illumination.lterator
Initializes variables
J
iEndin2 - Variable in class illumination.Surfacelnitializer
iStarting - Variable in class illumination.Surfacelnitializer
L
left - Variable in class illumination.Surfacelnitializer
leftMargin - Variable in class illumination.WindowSuite
lightBandOnFloorStartEndDistances one - Variable in class illumination.Surfacelnitializer
li2htBandOnFloorStartEndDistances two - Variable in class illumination.Surfacelnitializer
li2htFractionPassingThroughBlinds - Variable in class illumination.Surfacelnitializer
lineOfSightFlag(int, int, int, BlindSet, double) - Method in class
illumination.Surfacelnitializer
lowResWorkplane - Variable in class illumination.Map
M
main(Strini[1) - Static method in class illumination.Azimuth
82
main(String[1) - Static method in class illumination.Box
main(String[1) - Static method in class illumination.PVTest
main(Strinffl) - Static method in class illumination.Quadrant
main(Strinell) - Static method in class illumination.WalI
makeBlindFactors 1D(int, int) - Method in class illumination.ViewFactorSuite
makeBlindFactors 2D(int, int, int) - Method in class illumination.ViewFactorSuite
Map - class illumination.Map.
Sets up a "room" by creating interior wall, floor, ceiling and window surfaces, plus a
set of blinds.
Map(Map, SettingSuite) - Constructor for class illumination.Map
Used for creating a duplicate copy of an existing Map object.
Map(SettingSuite) - Constructor for class illumination.Map
Base constructor for Map class.
N
name - Variable in class illumination.Surface
Name of the surface.
name - Variable in class illumination.Surfacelnitializer
nearAndFarDistances - Variable in class illumination.Surfacelnitializer
numberOfBlinds - Variable in class illumination.SettingSuite
numberOfSurfaces - Variable in class illumination.Map
0
obliqueIntensityFraction - Variable in class illumination.Surfacelnitializer
obstructionFactor(int, int, BlindSet, int, ViewFactorSuite) - Method in class
illumination.Workplanelnitializer
oneHourWorkplaneLightingEnergyv(double, double, double, double) - Method in class
illumination.llumination
ONEHOURWORKPLANELIGHTINGENERGY() Returns the required illuminance
by artificial means to maintain room brightness at minLightLevel, in Watts per
floor area.
oneInterpolator - Variable in class illumination.Bilinear
mA2
of
83
overhang!Depth - Variable in class illumination.WindowSuite
P
parallelDistance - Variable in class illumination.Surface
Magnitude of the distance across the surface in the direction of "a."
parallelDistance - Variable in class illumination.SurfaceInitializer
PerspectiveView - class illumination.PerspectiveView.
PerspectiveView(Map) - Constructor for class illumination.PerspectiveView
PerspectiveView(Map, double, double, double) - Constructor for class
illumination.PerspectiveView
PerspectiveView(Map, Map) - Constructor for class illumination.PerspectiveView
PerspectiveView(Map, Map, double, double, double) - Constructor for class
illumination.PerspectiveView
Platform - class illumination.Platform.
Populates some of the basic arrays for the surface and invokes methods in the
superclass to completely create the surface.
Platform(Platform) - Constructor for class illumination.Platform
Platform(String, int, int, double, double, double, double) - Constructor for class
illumination.Platform
PlatformInitializer - class illumination.Platformlnitializer.
PlatformInitializerO - Constructor for class illumination.Platformlnitializer
Point3D - class illumination.Point3D.
Point3DO - Constructor for class illumination.Point3D
populateArray(int, int, double) - Static method in class illumination.ArrayMaker
positionForflour(int, int) - Method in class illumination.SolarlnfoCalculator
PVTest - class illumination.PVTest.
PVTest() - Constructor for class illumination.PVTest
84
Q
Q - Variable
o
in class illumination.Surface
"Q" is the surface radiosity array that updates as the iterations proceed.
initial - Variable in class illumination.Surface
"Qinitial" is the surface radiosity array that records the initial radiosity of the surface,
after the surface has been initialized by illuminating it with sunlight, but before the
iterations (reflections) have begun.
Quadrant - class illumination.Quadrant.
Quadrant(double, double, double, double) - Constructor for class illumination.Quadrant
R
radToDed(double) - Method in class illumination.Surfacelnitializer
rapidFineRoom - Variable in class illumination.WorkplaneBay
read(String) - Method in class illumination.WeatherDataReader
refindexArray - Variable in class illumination.Resizer
removeSpaces(String) - Static method in class illumination. WeatherDataReader
replaceFloor(Surface, String) - Method in class illumination.Map
replaceSurface(Surface, String) - Method in class illumination.Surface
Accomodates different resolutions in the two surfaces involved in the exchange.
Resizer - class illumination.Resizer.
ResizerO - Constructor for class illumination.Resizer
resolutions - Variable in class illumination.Surface
right - Variable in class illumination.Surfacelnitializer
ri2htMargin - Variable in class illumination.WindowSuite
room - Variable in class illumination.WorkplaneBay
rowTemplate - Variable in class illumination.Surfacelnitializer
S
setAngle(double) - Method in class illumination.Blind
85
setCollectiveAnglle(double) - Method in class illumination.BlindSet
setCollectiveBlindAngle(double)
- Method in class illumination._Map
setHArrayTo(double) - Method in class illumination. Surface
setInitialLightLevels(Map, WindowSuite, String, double, SolarSuite) - Method in class
illumination.Initializer
setOO - Method in class illumination.Surface
Updates "Q" based on light reflected from another surface.
setRadiositv(double) - Method in class illumination.Blind
setRadiosity(double, double) - Method in class illumination.BlindSet
setRadiosity(int, double) - Method in class illumination.BlindSet
SettingSuite - class illumination.SettingSuite.
Stores illumination parameters.
SettingSuite(double, double, double, double, int, int, int, WindowSuite, int, double) Constructor for class illumination.SettingSuite
Base constructor for SettingSuite class.
SettingSuite(SettingSuite, int, int, int) - Constructor for class illumination.SettingSuite
Used for creating a copy of an existing SettingSuite object, with only the
resolution values changed.
shade - Variable in class illumination. Wall
showReflectionsOnLowResWorkplane(Map)
- Method in class illumination.Iterator
SideWall - class illumination.SideWall.
Populates some of the basic arrays for the surface and invokes methods in the
superclass to completely create the surface.
SideWall(String, int, int, double, double, double, double) - Constructor for class
illumination.SideWall
SideWalllnitializer - class illumination.SideWalllnitializer.
SideWallnitializer() - Constructor for class illumination.SideWalllnitializer
sill - Variable in class illumination.Surfacelnitializer
sillHei2ht - Variable in class illumination.WindowSuite
silllndex - Variable in class illumination.Surfacelnitializer
simulateOneRoom(double, double, double, double) - Method in class
illumination.Illumination
SIMULATEONEROOMO No-blinds version of the above.
86
simulateOneRoom(double, double, double, double, double) - Method in class
illumination.Illum ination
SIMULATEONEROOM() Runs a single daylighting calculation, for the purpose of
displaying the view of a room interior at a particular point in time.
slatAreaO - Method in class illumination.BlindSet
solarAngleHorizontal - Variable in class illumination. SolarSuite
solarAngleVertical - Variable in class illumination.SolarSuite
solarIncoming - Variable in class illumination.SolarSuite
solarincoming - Variable in class illumination.Surfacelnitializer
SolarInfoCalculator - class illumination.SolarlnfoCalculator.
By JIM GOULDSTONE
SolarlnfoCalculator(String, String) - Constructor for class illumination.SolarInfoCalculator
SolarSuite - class illumination.SolarSuite.
SolarSuite(double, double, double, double) - Constructor for class illumination.SolarSuite
sort(Map, int, double) - Method in class illumination.BinSorter
For one room
sort(Map, Map, int, double) - Method in class illumination.BinSorter
For two rooms
substituteQValues(doubleHl]H) - Method in class illumination.Surface
Puts a new array of radiosities in place of the existing Q and Qinitial arrays.
sumDefecitValues() - Method in class illumination.WorkplaneBay
Surface - class illumination.Surface.
The basic storage element of this package.
SurfaceO - Constructor for class illumination.Surface
SurfaceInitializer - class illumination.Surfacelnitializer.
SurfacelnitializerO - Constructor for class illumination.Surfacelnitializer
surfaces - Variable in class illumination.Map
surfaceToBlindPairings ID - Variable in class illumination.ViewFactorSuite
surfaceToBlindPairings 2D - Variable in class illumination.ViewFactorSuite
surfaceToSurfacePairings - Variable in class illumination.ViewFactorSuite
surfaceType - Variable in class illumination.Surface
Category in which the surface is classed.
87
T
thirdIsConstant - Variable in class illumination.Surface
toDegrees(double) - Static method in class illumination.Azimuth
toRadians(double) - Static method in class illumination.Azimuth
toStringO - Method in class illumination.Point3D
totalNumber - Variable in class illumination.BlindSet
totalNumberOfBlinds - Variable in class illumination.Surfacelnitializer
V
valuelndexArray - Variable in class illumination.Interpolator
verticalAngle - Variable in class illumination.Surfacelnitializer
viewFactorArray - Variable in class illumination.Map
ViewFactorSuite - class illumination.ViewFactorSuite.
ViewFactorSuiteO - Constructor for class illumination.ViewFactorSuite
ViewFactorSuite(int, int, int, int) - Constructor for class illumination.ViewFactorSuite
ViewFactory - class illumination.ViewFactory.
ViewFactoryO - Constructor for class illumination.ViewFactory
w
Wall - class illumination.Wall.
Wall(int[l[1, double, double) - Constructor for class illumination.Wall
WeatherDataReader - class illumination.WeatherDataReader.
WeatherDataReaderO - Constructor for class illumination.WeatherDataReader
widthMagnitude - Variable in class illumination.SettingSuite
widthResolution - Variable in class illumination.SettingSuite
88
windowSpecs - Variable in class illumination.SettingSuite
WindowSuite - class illumination.WindowSuite.
WindowSuite(double, double, double, double, double) - Constructor for class
illumination.WindowSuite
WorkplaneBay - class illumination. WorkplaneBay.
WorkplaneBay(SettingSuite, SettingSuite, Initializer, Iterator, double, double) Constructor for class illumination.WorkplaneBay
workplaneBlindViewFactorArray - Variable in class illumination.Map
WorkplaneInitializer - class illumination.Workplanelnitializer.
WorkplaneInitializer() - Constructor for class illumination. WorkplaneInitializer
workplaneViewFactorArray - Variable in class illumination.Map
x
x - Variable in class illumination.Point3D
x - Variable in class illumination.Surface
"x" (depth) is measured from the window surface in the direction of the back wall.
Y
y - Variable in class illumination.Point3D
y - Variable in class illumination.Surface
"y" (height) is measured from the floor in the direction of the ceiling.
z
z - Variable in class illumination.Point3D
z - Variable in class illumination.Surface
"z" (width) is measured from sideWalll in the direction of sideWall2.
89
90
C:\Documents and Settings\Administrator\Desktop\Project
Latest\Essential Projec
package illumination;
public class ArrayMaker
public static double[][] populateArray( int rows,
double[][] array = new double[rows] [columns];
for ( int i = 0; i
for ( int
< rows; i++
j = 0; j < columns; j++
array[i]Li] = elementValue;
return array;
91
int columns, double elementValue )
C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec
package illumination;
/7 ** A Solar Calculator class
-----------------------/ **
7/ ** Given a set of climate, location, orientation, and date parameters,
// ** this class will walk through a series of calculations, eventually
// ** resulting in a value for solarRadiationGain to the facade.
/7
//
//
//
/7
//
//
//
//
//
**
**
**
**
**
**
**
**
**
**
7/ **
7/ **
/7 **
/7 **
Latitude, facade orientation, and facade tilt remain constant
throughout one set of calculations. As such, they are passed
to through the constructor and never reset.
Date and radiation levels vary from calculation to calculation,
they are passed to the calculate() method, which handles all
calculations.
so
The calculate() method returns nothing, but instead sets instance
members to results produced throughout the calculations.
You may then use the get() methods to retrieve any of the results
of the most recent call to calculateO.
/7 Useful calculation resources:
/7 (Beware. None of them seem to agree about what happens when these
// equations are applied to latitude south of the equator.)
7*
http://aurora. crest. org/basics/solar/angle/index. htm
http://mach.usno.navy.mil/cgi-bin/aa altazw
http: //www. arch. gatech. edu/~tmessadi/courses/Arch3231/HANDOUT-SOLAR%20GEMETRY.
pdf
*7
public class Azimuth
double
double
double
double
latitude; 7/ radians?
dayOfYear, declination, hourAngle;
daysInAMonth = 365.25/12.0; // on average
tiltOfEarthAxis = toRadians(23.45);
double surfaceAzimuth, verticalSurfaceTilt;
double altitude, azimuth;
double surfaceSolarAzimuth, angleOfIncidence, solarRadiationGain,
public static void main (String[] args)
{
int m = Integer.parselnt(args[0]);
int h = Integer.parselnt(args[l]);
double dir = (Double. value0f(args[2])). doubleValue(;
92
directRadiationGain,
diffuseRadiationGain;
C:\Document-s and Settings\Administrator\Desktop\Project
Latest\Essential Projec
double dif = (Double. valueOf(args[3])). doubleValueo;
double lat = (Double. valueOf (args[4])). doubleValueo;
Azimuth az = new Azimuth(lat, args[5]);
az.calculate(m,
}
h, dir, dif);
// note month here is 0 = January, 1 = Feb, etc
public void calculate (int month, int hourOfDay,
double directNormalRadiation, double diffuseHorizontalRadiation)
{
dayOfYear = daysInAMonth * (month + 0. 5); // .5 is to pick day from middle of month
//System.out.println("dayOfYear: " + dayOfYear);
// assumes first hour of a day is 0 = midnight, noon = 12
declination = calculateDeclination(day0fYear);
//System. out. println("declination: " + toDegrees(declination));
hourAngle = calculateHourAngle(hourOfDay); // consider + .5 for halfway through hour?
//System. out. println("hourAngle: " + toDegrees(hourAngle));
altitude = calculateAltitude(latitude, declination, hourAngle);
//System.out.println("altitude: " + toDegrees(altitude));
azimuth = calculateAzimuth(latitude, declination, altitude, hourAngle);
//System.out.println("AZIMUTH: " + toDegrees(azimuth));
//System.out.println("SURFACEaZIMUTH: " + toDegrees(surfaceAzimuth));
surfaceSolarAzimuth = calculateSurfaceSolarAzimuth (azimuth, surfaceAzimuth);
" + toDegrees (surfaceSolarAzimuth));
//System. out. println("surfaceSolarAzimuth:
angleOf Incidence = calculateAngleOfIncidence (altitude, surfaceSolarAzimuth);
" + toDegrees(angleOfIncidence));
//System. out. println("angle0fIncidence:
solarRadiationGain = calculateSolarRadiationGain
(angleOfIncidence, verticalSurfaceTilt, directNormalRadiation,
diffuseHorizontalRadiation, altitude);
" + solarRadiationGain);
//System. out. println("solarRadiationGain:
//System. out. println("verticalSurfaceTilt:
"
+ verticalSurfaceTilt);
directRadiationGain = calculateDirectSolarGain( angleOfIncidence,
directNormalRadiation
diffuseRadiationGain = calculateDiffuseSolarGain( verticalSurfaceTilt,
diffuseHorizontalRadiation );
public double getAltitudeo
{ return altitude; }
93
C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec
public double getAzimuth()
I return azimuth; I
public double getSolarRadiationGain()
{ return solarRadiationGain; }
public double getSurfaceSolarAzimuthO
{ return surfaceSolarAzimuth; }
public double getDirectRadiationGaino
I return directRadiationGain; }
public double getDiffuseRadiationGain()
{ return diffuseRadiationGain; }
public Azimuth (double latitude,
7/ in degrees N+ SString orientation,
// north, east, south, west
double verticalSurfaceTilt) 7/ in degrees
7/ 90 degrees is straight up
// 45 leans away from orientaion direction
7/ 145 leans toward orientation direction
//(i.e. a 45 facade facing south leans north)
this.latitude = toRadians(latitude);
if (orientation.equals("north"))
{ this. surfaceAzimuth = toRadians(180. 0);
else if (orientation.equals("east"))
{ this. surfaceAzimuth = toRadians(90.0);
else if (orientation.equals("south"))
t this.surfaceAzimuth
toRadians(O.0);
else
{ this. surfaceAzimuth
toRadians(-90.0);
this.verticalSurfaceTilt
}
toRadians( verticalSurfaceTilt );
/7 shortcut constructor for vertical surface tilt
public Azimuth (double latitude,
/7 in degrees N+ SString orientation) /7 north, east, south, west
{
this(latitude, orientation, 90.0 );
}
/7 23. 45 accounts for the tilt
of the Earth's axis
public double calculateDeclination(double day0fYear)
{
return tilt~fEarthAxis * Math.sin( toRadians( (360.0/365.0) * (284 + day~fYear));
}
94
C:\Documents and Settings\Administrator\Desktop\Project
Latest\Essential Projec
// number of degrees away from noon (solar noon: i.e. Daylight Savings may apply)
// assume that the
// (before noon is
sun moves 15 degrees for every hour of the day
+, after noon is -, by convention)
/7 does not account for daylight savings time
/7 DST would be reflected in the calculation for hourAngle,
likely:
// hourAngle = (12 - hourOfDay - daylightSavings) * 180;
// where daylightSavings = 0 during the summer when 12pm is solar noon
//
and daylightSavings = 1 during the winter when 11am is solar noon
public double calculateHourAngle(double hourOfDay)
return toRadians(((12.0 - hourOfDay) / 12.0) * 180);
}
//azimuth;
...
problem if altitude or or latitude
90 degrees for math
//surfaceSolarAzi =diff between azi and ori
public static double toRadians(double degrees)
I
return (degrees/180) * Math.PI;
public static double toDegrees(double radians)
return (radians/Math.PI) * 180;
}
// arguments are in radians, result is in radians
private double calculateAltitude(double latitude, double declination, double hourAngle)
{
if (hourAngle
0.0)
//
special solar noon shortcut
return (toRadians(90) - latitude + declination);
}
double altitude
altitude +=
(Math.cos(latitude) * Math. cos(declination) * Math. cos(hourAngle));
(Math. sin(latitude) * Math. sin (declination));
return Math.asin(altitude);
I
95
C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec
7*
The altitude angle is the apparent angular height of the sun in the
sky if you are facing it. The azimuth angle is the surface angle
between a line on the ground pointing at the sun and a line
pointing toward the equator (due south or north depending on
which hemisphere you are in).
(positive appears to be clockwise)
At least in the N hemisphere
XX wrong
*/
/*
if dec= 0...
if latitude is n, always positive
if latitude is s, always negative
*/
private double calculateAzimuth(double latitude, double declination,
double altitude,
double hourAngle)
double divisor = (Math. cos(altitude) * Math. cos(latitude));
if (divisor == 0.0)
{
// defend against divide by zero
return 0.0;
}
double azimuth
(Math. sin(altitude) * Math. sin(latitude))
azimuth /= divisor;
if ( azimuth >
- Math. sin(declination);
1 ) // this piece of code added by Matt Lehar, 10/5/02
/*
System. out. println(
System. out. println(
System. out. println(
System.out.println(
"NaN appearing, line 272 of Azimuth. java" );
"latitude = " +toDegrees(latitude) );
"altitude = " +toDegrees(altitude) );
"declination
" +toDegrees(declination) );
*/
azimuth = 0;
}
else
azimuth = Math.acos(azimuth);
if (hourAngle < 0.0)
{ azimuth *= -1;
return azimuth;
}
77 azimuth returned seems to be South always 0
77 then azimuth should take on the sign of the hour angle
77 positive is east of south
96
C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec
/7 negative is west of south
// arecos should return between 0 and 180 always
// then modify result to share hour angle sign
/7 so, orientation should range between -180 and 180 similarly
// to determine the surfacesolarazimuth
7/ azimuth sign must match hour angle sign
7/ direct light is 0 deg
/7 opposite direct is 180 / -180 deg
/7 we're only taking the cosine, anyhoo
// this method can return anything from -360 to +360 (in radians, tho)
/7 ideally, it would return a value in the range 0 to 180,
// but it doesn't matter as it all falls out in the cosines later
public double calculateSurfaceSolarAzimuth(double azimuth,
{
double ssa = azimuth - surfaceAzimuth;
double surfaceAzimuth)
return ssa;
}
public double calculateAngleOfIncidence(double altitude,
double solarSurfaceAzimuth,
double verticalSurfaceTilt)
= Math. cos(altitude) * Math. cos(solarSurfaceAzimuth) *
Math.sin(verticalSurfaceTilt);
angle += Math. sin(altitude) * Math.cos(verticalSurfaceTilt);
double angle
return Math.acos(angle);
I
/7 assume vertical wall version
/7 note that I don't override the old calculation
/7 to save on unnecessary calculations
public double calculateAngleOfIncidence(double altitude, double solarSurfaceAzimuth)
I
double angle = Math. cos(altitude) * Math. cos(solarSurfaceAzimuth);
return Math.acos(angle);
}
97
C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec
7/ aoi
77 vst
77 dnr
77 dhr
angleOfIncidence
verticalSurfaceTilt
directNormalRadiation
diffuseHorizontalRadiation
public double calculateSolarRadiationGain
(double aoi, double vst, double dnr,
double dhr, double altitude)
if ((altitude < 0.0)
(aoi > toRadians(90. 0)))
{
// sun is beyond horizon, or facing backside of building,
/7 so eliminate direct radiation component
return Math.sin(vst) * dhr;
}
return (Math.cos(aoi) * dnr) + (Math. sin(vst) * dhr);
}
7/MATT LEHAR, 8/6/02: THE FOLLOWING TWO METHODS
7/ON cALCULATEsOLARrADIATIONgAIN, BUT ALLOW THE
7/SUNLIGHT COMPONENT TO BE REQUESTED SEPERATELY
public double calculateDirectSolarGain
if ((altitude < 0.0)
(aoi > toRadians(90.O)))
return 0;
else {
return ( Math.cos( aoi
) * dnr );
public double calculateDiffuseSolarGain
return ( Math.sin( vst
ARE BASED
DIRECT
FROM THE DIFFUSE
( double aoi, double dnr )
( double vst, double dhr
) * dhr );
7*
In old calculator,
solarEnergy[i] = Math. cos(anglelncidence)*(dirNormRad[i])
where:
Fw = (1 + Math.cos(verticalTilt))/2;
which doesn't make much sense to me.
I include it just in case.
*/
98
+ (Fw)*(diffHorRad[i])
C:\Documents and Settings\Administrator\Desktop\Project
Latest\Essential Projec
package illumination;
public class Bilinear {
private double
private double[][][]
array[] [];
outputArray;
// same as outputArray, without the second level
private doublet][]
unsmoothedArray;
private Fringer
public Interpolator
private Resizer
oneFringer;
oneInterpolator;
oneResizer;
Reads in input array, creates output buffer, assigns dimensions to the output
buffer, and puts a fringe on the output buffer
*/
public Bilinear( double[][] array,
int res_a, int resb )
I
this.array
array;
oneFringer
oneInterpolator
oneResizer
new Fringer(;
unsmoothedArray
new double[res a][res-b];
new Interpolator( array
new Resizer();
if ( array.length
resa && array[0].length == resb
)
{
outputArray
else f
outputArray
= oneResizer.getArrayAndIndeces( array
= oneResizer.getArrayAndIndeces( array, res-a,
resb )
fillUnsmoothedArray( ;
}
private void fillUnsmoothedArray()
{
for ( int row = 0; row
< unsmoothedArray.length; row++ )
{
for ( int column = 0; column
< unsmoothedArray[0]. length;
column++
)
unsmoothedArray [row] [column] = outputArray [row] [column] [0];
99
C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec
private void replaceUnsmoothedArray(
f
for ( int row = 0; row
double[][] replacementArray
)
< unsmoothedArray.length; row++
for ( int column = 0; column
< unsmoothedArray[0]. length;
column++
)
unsmoothedArray[row][column]
replacementArray[oneResizer. refIndexArray[row] [column] [0]]
[oneResizer.refIndexArray[row][column][1]];
}
}
I
public int getResolutionOfExistinglnputGrida()
return array.length;
public int getResolutionOfExistingInputGridb(
return array[0].length;
public double[][] getUnsmoothedArray()
public
return unsmoothedArray;
{
double[][]
getUnsmoothedArray(
double[][] replacementArray
)
replaceUnsmoothedArray( replacementArray );
return unsmoothedArray;
}
public double[][] bilinearInterpolateo
{
return
oneInterpolator. b iIi nearInterpo late( oneFringer.fringeArray(
100
C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec
outputArray ));
}
101
C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec
// Created 8/15/02 by Matthew Lehar
package illumination;
public class BinSorter
private double min, max;
private double[] bins;
private double[] cumDistArray;
7/ in
W/m^2: per-surface minimum, maximum
private double WORLDMINVALUE; // in Cd/m2: comprehensive minimum, maximum
private double WORLDMAXVALUE;
private double DEFAULTMINVALUE;// in Cd/m^2: lowest significant luminance for room
private double DISPLAY MINVALUE;// in Cd/m^2: luminance limits for computer monitor
private double DISPLAYMAXVALUE;
/* as a fraction of the total number of samples,
adjustment iteration *7
private double errorMargin;
sets tolerance for the bin-size
/* CONSTRUCTOR ------------------------------------------------------------------------public BinSorter(
/* the actual recorded minimum value may be 0, but the
lowest bin must correspond to the log of the
radiosity */
double defaultminValue,
double display minValue,
double display maxValue
WORLD MINVALUE
WORLD_MAXVALUE
DEFAULTMINVALUE
0;
= 0;
= defaultminValue;
DISPLAY MINVALUE
DISPLAYMAXVALUE
= displayminValue;
= displaymaxValue;
/* PUBLIC METHODS ----------------------------------------------------------------------
*/
For one room
*/
public void sort( Map singleRoom, int numberOfBins,
min
max
double errorMargin
)
0;
0;
findRoomMinMax( singleRoom );
System. out. println( "One room: max. luminance
" +WORLDMAXVALUE
+", min. luminance
" +WORLDMINVALUE );
createBins( numberOfBins );
addRoomSamplesToBins( singleRoom );
102
C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec
createCumDistArray(
errorMargin );
For two rooms
public void sort( Map room, Map otherRoom,
min
max
int numberOfBins,
double errorMargin
0;
0;
findTworoomMinMax( room, otherRoom );
+WORLDMAXVALUE
System.out.println( "Two room: max. luminance
+", min. luminance = " +WORLDMINVALUE );
createBins( numberOfBins );
addRoomSamplesToBins( room
addRoomSamplesToBins( otherRoom );
createCumDistArray( errorMargin );
}
public double cumulativeDistributionFunction(
double input
)
if ( WORLDMINVALUE >= WORLDMAXVALUE
// i.e. sorting hasn't occurred
return 0;
else if ( WORLDMINVALUE > DISPLAYMINVALUE &&WORLDMAXVALUE
< DISPLAYMAXVALUE )
Linear transfer
/* i. e. world luminances already within display range.
function used */
/
return ( Math. log(limitLows(convertToCandelasPerM2(input)))
(Math.log(WORLDMAXVALUE/WORLDMINVALUE)) );
else
return cumDistArray[findCorrectBin(
limitLows(convertToCandelasPerM2(input)))];
7*PRIVATE
METHODS ---------------------------------------------------------------------
private void findTworoomMinMax( Map northRoom, Map southRoom
double storageMIN,
storageMAX;
findRoomMinMax( northRoom );
storageMIN = WORLDMINVALUE;
storageMAX = WORLD MAXVALUE;
103
)
*/
C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec
findRoomMinMax( southRoom );
WORLDMINVALUE = Math.min( WORLD MINVALUE, storageMIN );
WORLDMAXVALUE = Math.nmax( WORLDMAXVALUE, storageMAX );
Map singleRoom )
private void findRoomMinMax(
for
( int surfaceCount = 0; surfaceCount < singleRoom.numberOfSurfaces;
surfaceCount++
)
m{
singleRoom. surfaces [surfaceCount]. Q[0] [0]
max = singleRoom. surfaces [surfaceCount]. Q[0] [0];
minMax
( singleRoom. surfaces [surfaceCount]. Q
if ( surfaceCount ==0 )
WORLDMJNVALUE
convertToCandelasPerM2( mn
WORLDMAXVALUE = convertToCandelasPerM2( max
} else {
WORLDMINVALUE = Math.min( WORLDMINVALUE,
convertToCandelasPerM2( min ));
WORLDMAXVALUE = Math. max( WORLDMAXVALUE,
convertToCandelasPerM2( max
I
if ( WORLDMINVALUE < DEFAULTMINVALUE )
{ WORLDMINVALUE = DEFAULTMINVALUE;
}
private void minMax( double[][] array
for ( int i
0; i
<
j
for ( int
)
array. length;
= 0;
j <
i++ )
array[O].length;
j++ )
min = Math.min( min, array[i][j] );
max = Math.max( max,
array[i][j]
}
private void createBins(
bins
int numberOfBins )
new double[numberOfBins];
for ( int i = 0; i
<
numberOfBins;
bins[i] = 0;
104
i++ )
);
C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec
7*
Organizes room radiosity data into bins for a histogram
private void addRoomSamplesToBins( Map singleRoom
for
)
( int surfaceCount = 0; surfaceCount < singleRoom.numberOfSurfaces;
surfaceCount++
for
( int i
0; i
)
< singleRoom. surfaces[surfaceCount].Q. length;
i++ )
for ( int
j = 0; j < singleRoom. surfaces [surfaceCount].
Q[0].length; j++
)
addOneSampleToBin( convertToCandelasPerM2(
singleRoom.
surfaces[surfaceCount].
Q[i][j] ));
}
}
Accepts a luminance value in candelas per m^2.
limited.
This value should not be lower-
*/
private void addOneSampleToBin(
double sample
)
7/any
value below the default minimum is excluded from the histogram
if ( sample >= DEFAULTMINVALUE )
if
( findCorrectBin( sample ) >= bins.length )
System. out.println( "problem with sample. value
bins[findCorrectBin( sample )] += 1;
"
+sample );}
private int findCorrectBin( double sample )
/* without this if-statement, an input equal to MAXVALUE would cause an
out-of-bounds exception. */
return (( sample > WORLDMAXVALUE - 1 ) ?
( bins.length - 1 :
( new Double( Math. floor( Math. log(sample/WORLDMINVALUE)
/ ( Math.log(WORLDMAXVALUE/WORLDMINVALUE)) *
bins. length )). intValue() ))
private void createCumDistArray( double errorMargin
int runningTotal = 0;
double originalTotal = getBinTotal();
105
C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec
double[] originalBins;
originalBins = new double[bins.length];
cumDistArray = new double[bins.length];
for ( int i = 0; i < bins.length; i++ )
{
originalBins[i] = bins[i];
}
/* The total number of samples varies because some bins may be truncated to
meet the "ceiling condition" */
truncateBins( errorMargin, WORLDMINVALUE );
if ( getBinTotal() < ( errorMargin * 0.01 * originalTotal ))
{
System.out.println(
"NOTICE 1: iteration did not converge. Trying again with artificial world-minimum."
for ( int i = 0; i
< bins.length; i++
bins[i] = originalBins[i];
truncateBins( errorMargin, DEFAULTMINVALUE );
if ( getBinTotal(
K ( errorMargin * 0.01 * originalTotal
System.out.println(
"NOTICE 2: iteration again failed to converge.
for ( int i = 0; i
))
Using linear transfer function."
< bins.length; i++ )
bins[i] = originalTotal / bins.length;
for ( int i = 0; i
< bins.length; i++
cumDistArray[i]
( bins[i] + runningTotal
runningTotal += bins[i];
) / getBinTotal()
/*
Applies the "ceiling condition" by performing an iteration
*/
private void truncateBins( double errorMargin,
double worldMin
double tolerance;
double ceiling;
double trimmings;
tolerance = errorMargin * 0.01 * getBinTotal();
do {
106
)
C:\Documents and Settings\Administrator\Desktop\Project
Latest\Essential Projec
trimmings = 0;
for
(int
i = 0; i
< bins.length; i++ )
ceiling = getBinTotal() / bins.length
* Math.log( WORLDMAXVALUE / worldMin )
/ Math.log( DISPLAYMAXVALUE /
DISPLAYMINVALUE );
if ( bins[i] > ceiling
trimmings += (bins[i]-ceiling);
bins[i]
ceiling;
while
( trimmings > tolerance )
private int getBinTotal()
int runningTotal = 0;
for ( int i = 0; i
< bins.length; i++ )
{
runningTotal += bins[i];
return runningTotal;
private double limitLows( double value
return (( value
)
< DEFAULTMINVALUE ) ? DEFAULTMINVALUE : value
7*
Assumes that each element of a surface radiates uniformly in all directions,
so that a sphere enclosing the element at a certain radius would experience
a uniform illumination.
"Candela: The luminous intensity in a specified direction, of a monochromatic
source which has a frequency of 540 x 1012 Hz and which has a radiant intensity,
in the specified direction, of (1/683) watt per steradian."
-
courtesy, www.atis.org
*/
private double convertToCandelasPerM2( double radiosity
{
return radiosity * 683 / (4*Math. PI);
107
)
C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec
package illumination;
public class Blind
private
private
private
private
double
double
double
double
width;
angle;
verticalPosition;
radiosity;
public Blind( double width,
double verticalPosition
)
this. width
this. angle
this.verticalPosition
= width;
= 0; // by default
= verticalPosition;
radiosity
= 0;
public double getVerticalPositiono
I
return verticalPosition;
public void setRadiosity( double radiosity
this.radiosity
radiosity;
public double getRadiosityO
return radiosity;
// added 8/19/02 by M. Lehar
public void setAngle( double angle
this. angle
)
angle;
108
// by default
C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec
package illumination;
public class BlindSet
width;
private double
private double
private double
private double
length;
spacing;
totalNumber;
collectiveAngle
private Blind[]
blindArray;
private double
emissivity;
public BlindSet(
int totalNumber,
double length,
public
int
0;
double spacing,
double sill,
double head,
double emissivity
{
double verticalHeight;
this.totalNumber
this.length
this.spacing
= totalNumber;
this.emissivity
= emissivity;
= length;
= spacing;
if ( totalNumber
0 )
{
else
width = 0;
i
width =(head - sill )/totalNumber
- spacing;
if ( width ==0 )
{
totalNumber = 0;
else {
blindArray = new Blind[ totalNumber ];
for ( int blindNumber = 1; blindNumber
<= totalNumber;
blindNumber++
verticalHeight
sill + ( spacing + width ) *
- 1 ) + ( spacing + 0.5
* width );
( blindNumber
blindArray[ blindNumber -
109
)
1]
new Blind( width,
C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec
verticalHeight);
}
}
}
public double getBlindWidth()
{
return width;
}
public double getBlindSpacing()
{
return spacing;
}
public int getNumBlinds()
return totalNumber;
public double getEquivalentDistance( int blindNumber, double incidenceAngle,
String startOrEnd
{
Blind
blindRef
= blindArray[ blindNumber - 1 ];
double centerlineHeight
= blindRef.getVerticalPositionO;
double distance;
if ( startOrEnd.equals( "start"
))
distance = centerlineHeight - Math. abs(( width / 2 ) *
( Math. tan( convertToRadians( incidenceAngle )) *
Math.cos( convertToRadians( collectiveAngle )) Math.sin( convertToRadians( collectiveAngle ))));
else if ( start0rEnd.equals( "end"
))
distance = centerlineHeight + Math.abs(( width / 2 ) *
( Math.tan( convertToRadians( incidenceAngle )) *
Math.cos( convertToRadians( collectiveAngle )) Math.sin( convertToRadians( collectiveAngle ))))
else
System.out.println(
"Error: neither start nor end of blind requested" );
distance = 0;
return distance;
public double getProjectedDistance( int blindNumber,
110
String startOrEnd
)
C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec
double
centerlineHeight
double
distance;
blindArray[ blindNumber -1 ].
getVerticalPosition();
if ( startOrEnd.equals( "start"
))
distance = centerlineHeight - Math. abs(( width / 2 ) *
Math.sin( convertToRadians( collectiveAngle
)))
))
else if ( startOrEnd.equals( "end"
distance = centerlineHeight + Math. abs(( width / 2 ) *
Math. sin( convertToRadians( collectiveAngle )));
else {
System.out.println(
"Error: neither start nor end of blind requested" );
distance = 0;
return distance;
}
private double convertToRadians( double degreeValue
{
return degreeValue*Math.PI/180;
}
public double getVerticalPosition( int blindNumber
)
)
].getVerticalPosition()
return blindArray[ blindNumber - 1
}
// added 8/19 by M. Lehar
public void setRadiosity( double solar, double sunAngle
for ( int blindNumber = 1; blindNumber <= totalNumber; blindNumber++
blindArray[ blindNumber -
)
1 ].setRadiosity( ( 1 - emissivity )
* solar
* Math.abs( Math.sin(
convertToRadians( sunAngle
- collectiveAngle ))));
public double getRadiosity( int blindNumber
return blindArray[ blindNumber - 1 ].getRadiosityO;
}
III
C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec
// added 8/19 by M. Lehar
public void setCollectiveAngle( double collectiveAngle )
this. collectiveAngle
collectiveAngle;
for ( int blindNumber
1; blindNumber
blindArray[ blindNumber
-
<= totalNumber; blindNumber++ )
1 ]. setAngle( collectiveAngle )
public double getCollectiveAngle()
return collectiveAngle;
public double centerInZO
return length / 2;
public double slatAreaO
return length * width;
public String findIlluminatedSide( double sunAngle )
if ( sunAngle >= collectiveAngle )
return "top";
} else
return "bottom";
public void setRadiosity( int blindNumber, double radiosity
blindArray[ blindNumber
-
1 ].setRadiosity( radiosity )
112
C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec
package illumination;
7*
This class does some calculations related to raytracing a rectangular room.
An observer stands behind the room (not inside the room).
When a line
is drawn from the eye of the observer through the rear wall of the room,
we want to know where this line intersects another surface (wall, ceiling,
or floor) of the room. This intersection is returned as a Point3D. From
the observer's perspective, the origin of the room is at the lower left
hand corner of the near (rear) wall.
*/
public class Box
private double w;
private double h;
private double d;
// room width (x direction)
// room height (y)
/7 room depth (z)
private double wO; 7/ observer distance from left wall
(x direction)
private double hO; 7/ observer distance from floor
(y)
private double dO; /7 observer distance from image plane (z)
private
private
private
private
Quadrant
Quadrant
Quadrant
Quadrant
upperLeftQuad;
upperRightQuad;
lowerLeftQuad;
lowerRightQuad;
public static void main (String[] args)
{
Box b = new Box(5.0, 5.0, 5.0, 2.5, 1.7, 5.0):
double x = Double. valueOf (args [0]). doubleValue(;
double y = Double. valueOf(args[1]). doubleValue(;
Point3D s = b.findStrike(x, y);
System.out.println(s.toString());
}
public Box (double w, double h, double d,
double wObserver, double hObserver, double dObserver)
{
this.w = w;
this.h = h;
this.d = d;
this.wO = wObserver;
this.hO = hObserver;
this.dO = dObserver;
upperLeftQuad = new Quadrant (wO,
upperRightQuad = new Quadrant (w - wO,
lowerLeftQuad
new Quadrant (wO,
lowerRightQuad
new Quadrant (w - wO,
I
h - hO, d, do);
h - hO, d, dO);
hO,
d, dO);
hO,
d, dO);
113
C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec
//for a given x,y
/return x,y,z of strike
public Point3D findStrike (double x, double y)
Point3D strike;
if (y >= ho)
if (x <= wO)
//System.out.println("UL Quad");
strike = upperLeftQuad.findStrike(wO
strike.x = w - strike.x;
strike.y = hO + strike.y;
}
else
- x, y
//System.out.println("UR Quad");
strike = upperRightQuad. findStrike(x
strike.x = w + strike.x;
strike.y = hO + strike.y;
wO, y
hO);
-
ho)
else
f
if (x <= wO)
//System.out.println("LL Quad");
strike = lowerLeftQuad.findStrike(wO
strike.x =w
strike.y =h
-
-
x, hO
y)
strike.x;
strike.y;
}
else
f
//System.out.println("LR Quad");
strike = lowerRightQuad.findStrike(x - wO, hO - y);
strike.x = w + strike.x;
strike.y = hO - strike.y;
return strike;
114
C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec
package illumination;
// CLASS FACADE
Populates some of the basic arrays for the surface and invokes methods
The "Facade"
in the superclass to completely create the surface.
class of surfaces includes the window.
public class Facade extends Surface
public Facade(
String name,
int parallelResolution,
int crossResolution,
double parallelMagnitude,
double crossMagnitude,
double emissivity,
double constantCoordinate
)
surfaceType = new String( "facade" );
constructSurface(
name,
parallelResolution,
crossResolution,
parallelMagnitude,
crossMagnitude,
emissivity,
constantCoordinate
//OBSOLETE VARIABLES:
resolutions[0] = 1;
resolutions[l] = 0;
resolutions[2] = 0;
/* thirdIsConstant is used later on in the program to orient
the surface grids properly before they are sent to the viewer
program
*/
thirdIsConstant = false;
/* For-loop: populates some of the basic arrays for the surface, including
arrays giving position in x, y, and z; alpha, beta, and gamma, each
of which has the value 1 if the normal vector to the surface points
in the x, y, and z directions, respectively, and has the value 0
otherwise; and A, the differential area of each element of the grid
surface.
'a' and 'b' are the lengthwise and widthwise resolutions of the
surface. 'parallelDistance' and 'crossDistance' are the length and
width of the surface */
for ( int rowCounter = 0; rowCounter < a; rowCounter++ )
f
for ( int columnCounter =
115
0; columnCounter <
b; columnCounter++)
C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec
I
x[rowCounter][columnCounter]
y[rowCounter][columnCounter]
z[rowCounter][columnCounter]
alpha[rowCounter][columnCountei
beta[rowCounter][columnCounter]
gamma[rowCounter][columnCounter
A[rowCounter][columnCounter]
constantCoordinate;
( parallelDistance / a )
* ( rowCounter + 0.5 );
( crossDistance / b )
* ( columnCounter + 0.5 );
]
=
0;
0;
parallelDistance
( a * b );
* crossDistance /
I
}
}
}
116
C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec
package illumination;
public class FacadeInitializer extends SurfaceInitializer
String blindShadingScheme;
public void initialize( Surface currentSurface,
WindowSuite windowSpecs,
BlindSet blinds,
String blindShadingScheme,
boolean isFirstInitialization,
ViewFactorSuite blindFactors_lD,
SolarSuite solarVars
)
{
this. blindShadingScheme = blindShadingScheme;
initializeSurfaceVariables(
currentSurface,
blinds,
windowSpecs,
solarVars
imposeBlindSlatShadows( blinds
public void imposeBlindSlatShadows(
rowTemplate
BlindSet blinds
new double[a];
rowTemplate
this array serves as a mask: when pointwise-multiplied
by the radiosity arrays of a surface, it introduces
black (zero-valued) bands where the shadow of a
blind slat crosses that surface.
in the case of the window (facade) surface, these
"shadows" are in fact the projected profiles of the
blinds in the window, as viewed by an observer at the
back of the room
for ( int i=
0; i < a; i++ )
rowTemplate[i] = 0;
}
117
C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec
Above, the entire mask is initialized to a value of 0
(black). Below, the middle region of the mask
corresponding to the transparent area of the window,
is set to a value of 1.
*/
nearAndFarDistances[0] = sill;
nearAndFarDistances[l] = head;
indeces0fNearAndFarReacha = findlndeces0fNearAndFarReach(
nearAndFarDistances, a, parallelDistance );
for
indecesOfNearAndFarReach a[0]; i <=
indecesOfNearAndFarReachba[l]; i++ )
( int i
rowTemplate[i]
for
( int blindNumber
1;
1; blindNumber
<= totalNumberOfBlinds;
blindNumber++
)
find indeces that mark the beginnings and endings
of blind shadows in the parallel (up/down) direction along
the facade
*7
blinds. getProjectedDistance(
blindNumber, "start" );
blinds. getProjectedDistance(
blindStartEndDistances[l]
blindNumber, "end" );
findlndecesOfNearAndFarReach(
blindStartEndIndeces
blindStartEndDistances, a,
parallelDistance );
blindStartEndDistances [0]
7*
create black spaces in the parallel (row) mask that
correspond to the positions of the blind shadows
*7
( int i
for
blindStartEndIndeces[0]; i <=
blindStartEndIndeces[l] ; i++
rowTemplate[i]
)
0;
/*
for the 0-degree blind angle, so that the blind doesn't completely
disappear when viewed side-on
*/
if
( blindStartEndIndeces[O] > blindStartEndlndeces[l] )
rowTemplate[blindStartEndlndeces[0]]=
for
( int il
0;
indecesOfNearAndFarReach-a[0]; il
<= indeces0fNearAndFarReach a[l]; il++ )
118
C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec
{
for ( int i2 = 0; i2
{
< b; i2++ )
/*
set the radiosity of the part of the window
surface that remains visible through the blinds
*/
if ( blindShadingScheme.equals( "focused"
))
currentSurface.Qinitial[il][i2] = diffIntensity *
rowTemplate[il];
else
/* Intensity of diffuse light depends on degree to
which blinds are open - ASSUMPTION: blinds
meet at the edges when closed
*7
currentSurface.Q initial[il][i2] = diffIntensity *
Math.cos( degToRad( blinds.
getCollectiveAngle());
currentSurface.Q[il][i2]
currentSurface.
Qinitial[il] [i2]
}
}
/*
the following methods must be included for
compatibility with the superclass,
but are not relevant to the facade case
public void calculateFirstReflectionFromBlinds(
BlindSet blinds,
boolean isFirstInitialization,
ViewFactorSuite blindFactors_lD,
Surface currentSurface ) {}
public void applyPatchOfSunlight(
String blindShadingScheme )
public double findAngleOnSurface(
double verticalAngle,
{
return
0;
}
}
119
{}
double horizontalAngle
)
C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec
package illumination;
import java.io.*;
public class FileOut
public static void createSurfaceFile( Surface currentSurface
)
try {
File outputFile = new File( currentSurface. name. concat( "Array.txt"
FileWriter out
= new FileWriter( outputFile );
outputValues( out, currentSurface );
out. close()
catch
( IOException e
System.err.println( e.toString()
private static void outputValues( FileWriter out, Surface currentSurface
try
/*if ( currentSurface.name.equals( "workplane" ))
{
System. out. println( "received at fileOut: Q[l][10]
"
+currentSur
face.Q[1][10] );
}*/
for ( int i = 0; i
for ( int
< currentSurface.a; i++ )
i = 0; j < currentSurface.b; j++ )
out.write(
( new Double( currentSurface. Q[i] [j] )).toString(
.));
out.write(""
out.write( "\n"
catch
( IOException e
System.err.println( e.toString()
public static void createSurfaceFile(
double[][]
)
currentArray
try
//System.out.println( "ANNONYMOUS" );
120
)
C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec
/*for ( int i = 0; i
< currentArray.length; i++ )
System.out.println( "--NONZERO: " +currentArray[i][i]
}*/
File outputFile = new File( "annonymousArray. txt" );
FileWriter out = new FileWriter( outputFile )
);
outputValues( out, currentArray );
out. close 0
catch
( IOException e
System.err.println( e.toString(
public static void createSurfaceFile( double[][] currentArray,
String name )
try
File outputFile = new File( name.concat("Array.txt") );
FileWriter out
= new FileWriter( outputFile )
outputValues( out, currentArray );
out. close 0
catch ( IOException e
System. err. println( e. toStringO );
public static void createSurfaceFile( double[][][]
currentArray
try
//System.out.println( "NONAME" );
/*for ( int i = 0; i
< currentArray.length; i++ )
System.out.println( "--NONZERO: " +currentArray[i][i]
);
}*/
double]
[] subArray = new double [currentArray. length] [currentArray[O
].length];
for ( int i
for ( int j
0; i
< currentArray.length; i++ )
0; j
< currentArray[O].length; j++ )
subArray[i][i] = currentArray[i][i][0];
File outputFile = new File( "nonameArray.txt" );
121
C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec
FileWriter out
= new FileWriter( outputFile
)
outputValues( out, subArray );
out. close()
catch
( IOException e
System.err.println( e.toString(
)
private static void outputValues( FileWriter out, double[][] currentArray
try
for ( int i = 0; i
< currentArray.length; i++ )
for ( int j = 0; j
< currentArray[0]. length; j++ )
{
out.write(
out.write(
( new Double( currentArray[i][j] )).toString(
out.write( "\n" );
catch
( IQException e )
System.err.println( e.toStringO
122
)
);
C:\Documents and Settings\Administrator\Desktop\Project
Latest\Essential Projec
package illumination;
public class FloorCeilingInitializer extends PlatformInitializer
public void initialize( Surface currentSurface,
WindowSuite windowSpecs,
BlindSet blinds,
String blindShadingScheme,
boolean isFirstlnitialization,
ViewFactorSuite blindFactors_lD,
SolarSuite solarVars
{
initializeSurfaceVariables( currentSurface,
blinds,
windowSpecs,
solarVars );
imposeBlindSlatShadows( blinds );
applyPatchOfSunlight(
blindShadingScheme );
calculateFirstReflectionFromBlinds(
blinds,
isFirstInitialization,
blindFactors -D,
currentSurface );
}
public void imposeBlindSlatShadows( BlindSet blinds
{
)
initializeMasksO;
for ( int blindNumber
1; blindNumber
<= totalNumberOfBlinds; blindNumber++
)
{
find indeces that mark the beginnings and endings
of blind shadows in the parallel direction along
the floor/ceiling
*/
blindStartEndIndeces = findlndecesOfNearAndFarReach(
findNearAndFarDistances(
blinds.getEquivalentDistance(
blindNumber, verticalAngle,
"start" ),
blinds.getEquivalentDistance(
123
C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec
blindNumber, verticalAngle,
"end" ),
verticalAngle ),
a, parallelDistance );
create black spaces in the parallel (column) mask that
correspond to the positions of the blind shadows
*7
for ( int i
blindStartEndIndeces[O]; i
<= blindStartEndIndeces[l]; i++
if ( i < 0 )
if ( i > columnTemplate. length columnTemplate[i] = 0;
{ i = 0;
{ break;
1)
public void applyPatchOfSunlight( String blindShadingScheme
)
)
/*
"sill" and "head" determine the limits in the DEPTH dimension
of the patch of sunlight projected onto the floor/ceiling
from the window
"blockl" and "block2" are here defined as the side margins of
the window area, and limit the patch of sunlight on the floor/
ceiling in the WIDTH dimension
*/
nearAndFarDistances
findNearAndFarDistances(
sill, head, verticalAngle
blockl = right;
block2 = left;
obliqueIntensityFraction
find0bliqueIntensityFraction( verticalAngle
illuminateWithSunlight( blindShadingScheme,
124
obliqueIntensityFraction
)
)
C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec
package illumination;
public class Fringer
private boolean foundStartingRow;
private boolean foundEndingRow;
private boolean foundStartingColumn;
private boolean foundEndingColumn;
public Fringer()
foundStartingRow
foundEndingRow
foundStartingColumn
foundEndingColumn
false;
= false;
= false;
= false;
Operates on an array consisting of two, 2-D arrays stacked one atop the other
(a 3-D array with only two elements in the third dimension).
One layer of this
array contains information, expanded to a large grid size from a small original
array. The second layer contains markers (ones) in a field of zeros, to indicate
the center of each data point.
The function of this method is to place a fringe
of "ones" around the edge of the second layer, so that the new "ones" on the
fringe are aligned with the pre-existing grid of "ones," and so that there is a
"one" on each corner of the fringed array.
The purpose of this fringe is to
provide a boundary condition for the bilinear interpolation scheme.
*/
public double[][][]
fringeArray( double[][][]
unfringedArray
double[][][] fringedArray;
fringedArray = new double[( unfringedArray. length + 2 )]
[( unfringedArray[O].length + 2)][2];
fringeColumnsAdjacentToStartingRow(
fringedArray,
if ( !foundStartingRow )
{ System. out.println( "ERROR:
unfringedArray );
no data detected in array" );
fringedArray, unfringedArray );
fringeColumnsAdjacentToEndingRow(
fringeRowsAdjacentToStartingColumn( fringedArray, unfringedArray );
fringeRowsAdjacentToEndingColumn(
fringedArray, unfringedArray );
fillInteriorOfFringedArray(
fringedArray, unfringedArray );
fillFringingColumns(
fringedArray, unfringedArray );
fillFringingRows(
fringedArray, unfringedArray );
125
C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec
fillCornersOfFringedArray(
fringedArray, unfringedArray );
return fringedArray;
I
private void fringeColumnsAdjacentToStartingRow(
double[][][] fringedArray,
double[][][] unfringedArray
)
I
for ( int row = 0; row
< unfringedArray.length; row++ )
for ( int column = 0; column
< unfringedArray[O]. length; column++ )
if ( unfringedArray[row][column][1]!
I
0
)
fringedArray[0][( column + 1 )][l]
foundStartingRow = true;
if ( foundStartingRow
1;
)
break;
}
}
}
private void fringeColumnsAdjacentToEndingRow(
double[] []] fringedArray,
double[][][] unfringedArray
for ( int row = unfringedArray. length - 1; row >= 0; row--for ( int column = 0; column
)
)
< unfringedArray[O]. length; column++
if ( unfringedArray[row][column][1]
!= 0
)
fringedArray[( fringedArray.length -- 1 )]
[(column + 1 )][1]
1;
foundEndingRow = true;
if ( foundEndingRow
)
break;
}
}
}
private void fringeRowsAdjacentToStartingColumn(
126
double[][][] fringedArray,
double[][][] unfringedArray
)
C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec
for
( int column = 0; column < unfringedArray[0]. length; column++ )
for ( int row = 0; row
< unfringedArray.length; row++ )
if ( unfringedArray[row][column][1]
!= 0
fringedArray[( row + 1 )][0][1]
foundStartingColumn = true;
if
)
1;
( foundStartingColumn )
break;
private void fringeRowsAdjacentToEndingColumn(
for
double[] [] fringedArray,
double[][][] unfringedArray
)
( int column = unfringedArray[O]. length - 1; column >= 0; column-- )
)
for ( int row = 0; row K unfringedArray.length; row++
if ( unfringedArray[row][column][1]
!=0 )
fringedArray[( row + 1)]
[( fringedArray[O].length
foundEndingColumn = true;
if
-
1 )][1]
( foundEndingColumn
break;
private void filllnteriorOfFringedArray(
for
double[][][] fringedArray,
double[][][] unfringedArray
)
( int row = 0; row < unfringedArray.length; row++
for ( int column = 0; column
< unfringedArray[0]. length; column++
fringedArray[( row + 1 )][( column + 1
127
)]
1;
C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec
unfringedArray[row][column];
fringedArray[( row + 1 )][( column + 1 )] =
unfringedArray[row][column];
}
}
}
private void fillFringingColumns( double[][][] fringedArray,
double[][][] unfringedArray
for ( int row = 0; row
{
<
)
unfringedArray.length; row++
fringedArray[( row + 1 )][0][0] = unfringedArray[row][0][0];
fringedArray[( row + 1 )][( fringedArray[O]. length - 1 )][0] =
unfringedArray [row] [(unfringedArray [0]. length - 1 )][0];
}
}
private void fillFringingRows( double[][][]
fringedArray,
double[][][] unfringedArray
for ( int column = 0; column
<
unfringedArray[O].
fringedArray[0][( column + 1 )][0]
fringedArray[( fringedArray. length
unfringedArray[(
)
length; column++
)
unfringedArray[0] [column] [0];
1 )][( column + 1 )][0] =
unfringedArray. length - 1 )][column][0];
}
}
private void fillCornersOfFringedArray(
double[][][]
fringedArray,
double[][][] unfringedArray
)
fringedArray[0][0][1]
fringedArray[0][( fringedArray[0].length - 1 )][1]
fringedArray[( fringedArray.length - 1 )][0][1]
fringedArray[( fringedArray.length - 1 )]
[( fringedArray[0].length - 1 )][l]
=1
=1;
=1
=1
fringedArray[0][0][0] = unfringedArray[0][0][0];
fringedArray[0][( fringedArray[0].length - 1 )][0]
unfringedArray[0] [( unfringedArray[0]. length - 1 )] [0];
fringedArray[( fringedArray.length - 1 )][0][0] =
unfringedArray[( unfringedArray. length fringedArray[(
1 )] [0] [0];
fringedArray. length - 1 )][( fringedArray[0]. length - 1 )][0]=
128
Latest\Essential Projec
C:\Documents and Settings\Administrator\Desktop\Project
1 )][( unfringedArray[0]. length - 1 )][0];
unfringedArray[( unfringedArray. length }
}
//
Driver for BinSorter. java.
Created 8/16/02 by Matthew Lehar
package illumination;
public class GrayScaleConverter
// in candelas/m^2 (this is the lowest intensity percep tible by the human eye)
= 0.0001;
private double RADIOSITYMINVALUE
private double DISPLAYMINVALUE
private double DISPLAYMAXVALUE
= 1;
= 200;
// in units of gray levels (0-255)
private double GRAYSCALEMINVALUE
=
private double GRAYSCALEMAXVALUE
= 255;
private double errorMargin
= 2.5; // perce nt
1;
private BinSorter sorter;
public GrayScaleConverter(
I
Map room,
int number0fBins
sorter = new BinSorter( RADIOSITYMINVALUE,
sorter.sort( room, number0fBins,
)
DISPLAYMINVALUE,
DISPLAYMAXVALUE );
errorMargin );
}
public GrayScaleConverter( Map room, Map otherRoom, int numberOfBins
sorter = new BinSorter( RADIOSITYMINVALUE,
DISPLAYMINVALUE,
DISPLAYMAXVALUE );
sorter. sort( room, otherRoom, number0fBins,
errorMargin );
public double convertRadiosityToGrayScale(
double radiosity
)
return trim( scaleToGrayLevels( Math. log( DISPLAY MINVALUE ) +
Math.log( DISPLAYMAXVALUE/
DISPLAYMINVALUE
)
* sorter.
cuinulativeDistributionFunction( radiosity
129
)))
C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec
}
// used for direct mapping of world luminances to gray levels
public double convertRadiosityToGrayScale( double radiosity, double gain )
I
return trim( radiosity * gain
}
/* PRIVATE METHODS -----------------------
----------------------------
private double scaleToGrayLevels( double brightness
return GRAYSCALEMINVALUE + ( brightness - Math. log(DISPLAYMINVALUE)
/ ( Math.log(DISPLAYMAXVALUE / DISPLAYMINVALUE))
* ( GRAYSCALEMAXVALUE - GRAYSCALEMINVALUE );
}
private double trim( double output
if ( output
<= 0
return GRAYSCALEMINVALUE;
else if ( output > GRAYSCALEMAXVALUE )
return GRAYSCALEMAXVALUE;
else { return output; }
130
C:\Documents and Settings\Administrator\Desktop\Project
Latest\Essential Projec
package illumination;
import qhqc.RoomDescription;
/* Modified, August 20, by Matthew Lehar. Drivers for new display software written-in.
Program overhauled and cleaned up.
/* Modified, August 9, by Matthew Lehar. Lighting-energy averaging methods complete
/* Modified, January 28, by Matthew Lehar.
Comments added for JavaDoc
/* Modified, January 20, by Matthew Lehar. Structural improvements to pace Jim
Gouldstone' s update of the display classes
/* Modified, January 11, 2002 by Matthew Lehar. Package redisigned for greater readability
/* Modified, September 18 by Matthew Lehar. New instructions for linearizing lowresolution surface radiosity output arrays with "Bilinear. java" (may soon be moved
to a separate class)
/* Modified, June 14 by Matthew Lehar.
Methods added to calculate which parts of the
inside surfaces are lit by the sun for different sun angles
/* Modified, May 15 by Matthew Lehar. Array casting routines, public methods added to
Illumination. java
/* Modified, April 19-25 by Matthew Lehar.
Project simplified, compiled, and tested.
/* Modified, March 9 and March 14 by Matthew Lehar, to recast the program in an objectoriented form
/* Created February, 2001 by Matthew Lehar, based on the original program written by Leon
--
Glicksman in MathCAD
-----------------------------------------------------------
77 CLASS ILLUMINATION
Creates Map objects (representing
to produce one final "room. " The
resolution and iterated rapidly.
this time at high resolution, and
"rooms") and combines them together
Map object is created at low
first
Then, a second Map object is created,
this one is not iterated, the time
The low-res Map
necessary for a high-res iteration being prohibitive.
is then combined with the high-res to produce a hybrid that is finely
resolved in respect to the boundaries between sunlight and shadow, but
also shows a crude reflection pattern on the interior surfaces not
directly illuminated by the sun.
*/
public class Illumination {
//
Class Variables
private int
NUMITERATIONS;
private double
tempBlindAngle
//
0;
total number of elements on all surfaces of crude room models
private int
CRUDECELLCOUNT
= new Double(5 * Math.pow(7,2)).intValueo;
131
--------
C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec
private int
private int
FINECELLCOUNT
= new Double(5 * Math.pow(100,2)).intValueo;
RAPID CELLCOUNT
= new Double(5 * Math.pow(10,2)).intValueo;
private double
private double
rl;
r2;
private int
private int
private int
MONTHSINYEAR
DAYSINMONTH
HOURSINDAY
= 12;
= 30;
= 24;
private double
private double
WATTSINKILOWATT
WATTSPERLUMEN
= 1000;
= 0.0015;
// "0" is the first hour of the day (12-1 am)
BEGINHOUR
private int
ENDHOUR
private int
timeStep
private int
private WorkplaneBay
currentWorkplaneBay;
private SettingSuite
settings,
fineRoomSettings,
rapidFineRoomSettings;
8;
18;
1; // in hours
private RoomDescription entireRoomDesc;
private Initializer
private Iterator
onelnitializer;
onelterator;
private double ][]
monthAveragedWorkplane
private int
private int
selectedMonth
selectedHour
2
13;
7/ Public Methods
SIMULATE0NERO0M() Runs a single daylighting calculation, for
the purpose of displaying the view of a room interior at a particular
point in time. Returns the high-resolution map in its present state.
solarAngleVertical
solarAngleHorizontal
qSolarIncoming,
qDiffuse
angle of elevation of sun in sky, measured from horizon
upward
angle of azimuth of sun in sky, measured from facade's
outward-pointing normal vector to rightward
sunlight intensity (W/m^2)
diffuse light intensity (W/m^2)
*/
public Map simulate0neRoom( double solarAngleHorizontal,
double solarAngleVertical,
132
C:\Documents and Settings\Administrator\Desktop\Project
Latest\Essential Projec
double solarIncoming,
double diffIntensity,
double collectiveBlindAngle
t
// Create instance of Map object ("room")
new Map( settings
Map room
new Map( settings
Map iteratedRoom
)
)
/* Since fineRoom is the output, it must be reassigned each time the method
is called, so that the user is given exclusive control over any old
versions */
- new Map( fineRoomSettings
Map fineRoom
// Group the sun-related variables into a single object for convenience
SolarSuite solarVars
= new SolarSuite( solarAngleHorizontal,
solarAngleVertical,
solarIncoming,
diffIntensity
// Perform one simulation
setDaylighting( fineRoom,
room,
iteratedRoom,
solarVars,
"bilinear",
"highRes",
collectiveBlindAngle
7/Deliver
)
finished Map to user
return fineRoom;
}
SIMULATEONEROOM() No-blinds version
of the above.
*/
public Map simulateOneRoom( double
double
double
double
solarAngleHorizontal,
solarAngleVertical,
solarIncoming,
diffIntensity
)
return simulateOneRoom( solarAngleHorizontal,
solarAngleVertical,
solarIncoming,
diffIntensity,
0
}
ONEHOURWORKPLANELIGHTINGENERGY(
Returns the required illuminance
by artificial means to maintain room brightness at minLightLevel,
in Watts per m_2 of floor area.
*/
public double oneHourWorkplaneLightingEnergy(
133
double azimuth,
double altitude,
double direct,
C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec
double diffuse
)
double blindAngle;
double tempTotal;
direct *= .0015;
diffuse *= .0015;
// convert from lux to W/m^2
SolarSuite solarVars = new SolarSuite( azimuth,
altitude,
direct,
diffuse );
if
( entireRoomDesc.getWindowUnit ( != null
&&entireRoomDesc. getWindowUnit(). getBlinds 0
blindAngle
}
else
blindAngle
entireRoomDesc. getWindowUnit
0.getBlinds (.
null)
getAngle(;
tempBlindAngle;
setDaylighting ( currentWorkplaneBay. rapidFineRoom,
currentWorkplaneBay.room,
currentWorkplaneBay.iteratedRoom,
solarVars,
"none",
"highRes",
blindAngle )
currentWorkplaneBay. calculateWorkplaneLightLevels ( solarVars,
settings.windowSpecs,
blindAngle );
tempTotal
currentWorkplaneBay.sumDefecitValues();
return tempTotal;
GETCOLLECTIVEBLINDANGLE(
Returns current blind angle.
public double getCollectiveBlindAngle()
if ( entireRoomDesc.getWindowUnit(
null
&& entireRoomDesc. getWindowUnito. getBlinds()
null)
return entireRoomDesc. getWindowUnito. getBlinds(. getAngle(
else
return tempBlindAngle;
134
C:\Documents and Settings\Administrator\Desktop\Project
Latest\Essential Projec
The following method is only for testing purposes:
FINDREQUIREDLIGHTINGENERGY0
Runs many daylighting calculations
at different times of the day and during different months of the
year. Produces statistics on average lighting energy requirements
to keep room adequately illuminated during work hours.
public double[]
findRequiredLightingEnergy(
7/ VARIABLE
String
String
weatherFile,
orient,
double
workplaneHeight,
double
minimumLightLevel
DECLARATIONS ----------------------------------------------
//
Tally of total use of electrical lighting energy for
monthlyLightingReq;
double[]
1
month (KWh/m^2)
/* Amounts by which sunlight falls short of lighting requirement at
different locations on workplane: values are in units of EXTRA
light intensity required (W/m-2) *7
double[][]
defecitArray;
/* Object for storing information about sunlight for one particular
configuration of the room */
solarInfo;
SolarInfoCalculator
// 1. Print out city name and building orientation
System.out.println("weatherFile: " +weatherFile +" orient: " +orient );
7/VARIABLE
77
DEFINITIONS ----------------------------------------------
2. Create storage objects
monthlyLightingReq
new double[MONTHSINYEAR];
solarInfo
new SolarlnfoCalculator( weatherFile, orient
//
BODY ----------------
/*
3.
for
-------------
------------------------------
For each month, find the average hourly demand for electrical
lighting energy */
( int month = 0; month < MONTHSINYEAR; month++ )
monthlyLightingReq[month] = 0;
if ( month == selectedMonth
initializeAverageArray(
currentWorkplaneBay.rapidFineRoom.hiResWorkplane );
for ( int hour = BEGINHOUR; hour
< ENDHOUR; hour += timeStep
solarlnfo.positionForHour( month, hour );
135
C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec
monthlyLightingReq[month] +=
oneHourWorkplaneLightingEnergy(
toDegrees( solarInfo. getAzimuth (),
toDegrees( solarlnfo. getAltitude(),
solarlnfo. getDirectlntensity(,
solarInfo. getDiffuselntensity()
if
(
month
selectedMonth
incrementAverageArray (
currentWorkplaneBay. rapidFineRoom. hiResWorkplane );
/7 Find total electrical energy per workplane area for each month
monthlyLightingReq[month]
= monthlyLightingReq[month]
* DAYSINMONTH;
if ( month == selectedMonth
)
averageAverageArray 0;
return monthlyLightingReq;
The following method is only for testing purposes:
GETMONTHAVERAGEDWORKPLANE 0
*/
public double[][] getMonthAveragedWorkplane()
return monthAveragedWorkplane;
//
Constructors
/7
Constructor No.1
<B>Base
-
base constructor
constructor for Illumination class.</B>
Explanations of the input
variables are as follows:<BR>
<BR>
nameOfJob
RESOLUTIONx
RESOLUTIONFINEx
sillHeight
only for your reference<BR>
low-res Map resolutionKBR>
high-res Map resolutionKBR>
height, measured from floor,
headHeight
transparent part of facadeKBR>
height, measured from floor, of top of transparent
part of facade<BR>
*/
136
of bottom of
C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec
public Illumination(
int NUMITERATIONS,
double emissivity,
double sillHeight,
double headHeight,
int numberOfBlinds,
RoomDescription entireRoomDese
)
{
double
if
blindSpacing;
( numberOfBlinds ==0 )
{ blindSpacing = .6; }
else
{ blindSpacing = 0;
this.NUM_ITERATIONS
this.entireRoomDesc
this.rl
this.r2
1
= NUMITERATIONS;
= entireRoomDesc;
entireRoomDesc.getDeptho
/ entireRoomDesc.getHeight();
entireRoomDesc.getHeight()
/ entireRoomDesc.getWidtho;
Define "settings" object to store all parameters for the illumination
procedure */
settings
new SettingSuite( emissivity,
entireRoomDesc.getDepth(),
entireRoomDesc.getHeight(),
entireRoomDesc.getWidth(),
/*
depthRes ( CRUDE CELLCOUNT ),
heightRes( CRUDECELLCOUNT ),
widthRes ( CRUDECELLCOUNT ),
new WindowSuite( sillHeight,
headHeight,
entireRoomDese.getWidth(),
0,
entireRoomDesc.getOverhangDeptho
numberOfBlinds,
)
blindSpacing
System. out. println( "Crude total cellcount:
+depthRes
"
( CRUDECELLCOUNT )
+" by "
+heightRes
( CRUDECELLCOUNT
+" by "
+widthRes
( CRUDECELLCOUNT )
);
System. out. println( "Fine total cellcount: "
+depthRes ( FINECELLCOUNT
+" by "
+heightRes
( FINECELLCOUNT )
+" by "
+widthRes
( FINECELLCOUNT )
System. out. println( "Rapid total cellcount:
"
+depthRes ( RAPIDCELLCOUNT
137
);
)
),
C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec
+" by "
)
+heightRes ( RAPIDCELLCOUNT
+" by "
)
+widthRes ( RAPIDCELLCOUNT
);
// Define settings for hi-res version of room
fineRoomSettings
new SettingSuite( settings,
depthRes ( FINECELLCOUNT ),
heightRes( FINECELLCOUNT ),
widthRes ( FINECELLCOUNT ));
rapidFineRoomSettings
= new SettingSuite(
settings,
depthRes ( RAPIDCELLCOUNT ),
heightRes( RAPIDCELLCOUNT ),
widthRes ( RAPIDCELLCOUNT ));
oneInitializer
onelterator
new Initializer()
new Iterator();
currentWorkplaneBay
new WorkplaneBay( settings,
rapidFineRoomSettings,
oneInitializer,
oneIterator,
entireRoomDesc.getWorkplaneHeight(),
convertToWM2(
entireRoomDesc.getMinimumLightLevel()
) );
if ( entireRoomDesc.getWorkplaneHeight(
> currentWorkplaneBay.rapidFineRoom.getHeight())
{
System.out.println(
"please enter a workplane height that is less than the total height of the room."
}
}
// Constructor No.2
<B>"Pre-constructor" (2) for constructor No. 1 - NO BLINDS.</B>
NUMITERATIONS,
public Illumination( int
double
double
double
double
double
double
double
double
double
this
emissivity,
sillHeight,
headHeight,
depth,
height,
width,
workplaneHeight,
minLightLevel,
)
overhangDepth
( NUMITERATIONS,
emissivity,
138
// floor to sill (m)
//
floor to head (m)
7/ depth into room (m)
// height of room (m)
7/ width of window wall (m)
/in
lux
C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec
sillHeight,
headHeight,
0,
new RoomDescription( depth, width, height,
null,
overhangDepth,
0.0,
minLightLevel,
0.0,
0.0
}
/
Constructor No.3
<B>"Pre-constructor" (3) for constructor No.1 - INCLUDES BLINDS.</B>
public Illumination( int
double
double
double
double
double
double
int
double
double
double
{
this (
NUM_ITERATIONS,
emissivity,
sillHeight,
headHeight,
depth,
height,
width,
number0fBlinds,
workplaneHeight,
minLightLevel,
overhangDepth
)
// floor to sill (m)
//7 floor to head (m)
//7 depth into room (m)
//7 height of room (m)
//7 width of window wall
NUMITERATIONS,
emissivity,
sillHeight,
headHeight,
20,
new RoomDescription( depth, width, height,
null,
overhangDepth,
0.0,
minLightLevel,
0.0,
0.0
}
Constructor No.4 for
Jim
139
(m)
C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec
<B>"Pre-constructor" (4) for constructor No.1
-
INCLUDES BLINDS.
</B>
public Illumination( RoomDescription newDese
this ( 5,
0.3,
newDesc.getSillHeight(),
/7 wall
emissivity (0.3 = approx. white)
newDesc.getHeadHeight(),
// number
0,
of blinds =
0
newDesc
}
// Constructor No.5
<B>"Pre-constructor" (5) for constructor No.3 - INCLUDES BLINDS.</B>
Use this FOR TESTING ONLY if you want to specify the blind angle 11/20/02
*7
NUMITERATIONS,
public Illumination( int
emissivity,
double
sillHeight,
double
//floor to sill (i)
headHeight,
double
floor to head ()
//7
depth,
double
depth into room (i)
//7
//7
height of room (n)
height,
double
width,
width of window wall
double
//7
double
workplaneHeight,
minLightLevel,
double
overhangDepth,
double
int
double
numberOfBlinds,
blindAngle
this ( NUMITERATIONS,
emissivity,
sillHeight,
headHeight,
depth,
height,
width,
number0fBlinds,
workplaneHeight,
minLightLevel,
overhangDepth
);
tempBlindAngle = blindAngle;
7/ Private Methods
7/ 10/7/02
private double convertToWM2(
double lux
return ( lux * WATTSPERLUMEN );
140
)
()
C:\Documents and Settings\Administrator\Desktop\Project
Latest\Essential Projec
In
SETDAYLIGHTING() is the principal engine for illuminating a room with daylight.
the first section, a crude room is created and reflections (iterations) are
performed. Optionally, a second section can then he invoked, in which a second
crude, un-iterated room is created, along with an un-iterated fine room. The uniterated room image is subtracted from the fine room, and finally the iterated
version of the crude room is added back in, resulting in a fine room with added
reflections
*/
private void setDaylighting( /* "oneFineRoom" can be a reference to either
"fineRoom" or "rapidFineRoom" */
Map
oneFineRoom,
Map
room,
Map
iteratedRoom,
SolarSuite solarVars,
String
smoothing,
String
lightingResolution,
double
collectiveBlindAngle
)
// BASIC, LOW-RES SIMULATION ------onelnitializer.setInitialLightLevels(
---------------------------/* Cast sunlight upon the inside
surfaces of the to-beiterated room
iteratedRoom,
settings.windowSpecs,
"distributed",
collectiveBlindAngle,
)
solarVars
/7 Allow light to reflect among inside surfaces of the to-be-iterated room
doDiffuseReflections( iteratedRoom, NUMITERATIONS );
// OPTIONAL, HI-RES SIMULATION -----------------------------------------if ( lightingResolution.equals( "highRes" ))
oneInitializer.setInitialLightLevels( room,
settings.windowSpecs,
"distributed",
collectiveBlindAngle,
solarVars
onelnitializer.setlnitialLightLevels( oneFineRoom,
settings.windowSpecs,
"focused",
collectiveBlindAngle,
solarVars
/* The net effect of subtracting the radiosities of the UN-iterated
"room, " then adding the radiosities of "iteratedRoom, " is to add
REFLECTED LIGHT ONLY to the high-resolution "fineRoom." *7
oneFineRoom.addRadiositiesFrom( room, "-,
smoothing );
oneFineRoom. addRadiositiesFrom( iteratedRoom, "+", smoothing )
141
C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec
}
DODIFFUSEREFLECTIONSO
of the input Map.
Performs iterations (reflections of light) between surfaces
private void doDiffuseReflections( Map aRoom,
int numIterations
for ( int iteration = 0; iteration < numIterations;
I
oneIterator.iterateRadiosityCalc( aRoom );
private void initializeAverageArray( Surface workplane
)
iteration±+
)
monthAveragedWorkplane = new double[workplane. a] [workplane. b];
for ( int i
for ( int
0; i
j
< monthAveragedWorkplane.length; i++ )
0; j
<
monthAveragedWorkplane[0].
length;
j++
inonthAveragedWorkplane[i][j] = 0;
private void incrementAverageArray( Surface workplane
for
( mt i
for (int
0; i K monthAveragedWorkplane.length;
0; i
< monthAveragedWorkplane[.
nonthAveragedWorkplane[i]
Li]
i+
length; j++
)
+= workplane. Q~i]
Li];
private void averageAverageArrayo(
for (
t i =0; i K onthAveragedWorkplane.length; i++
for ( int
j = 0; j < monthAveragedWorkplane[0]. length; j++
monthAveragedWorkplane[i] [j] /= (ENDHOUR-BEGINHOUR);
TODEGREES 0I
142
)
C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec
private double toDegrees( double radianValue
)
return ( radianValue * 180 / Math.PI );
DEPTHRESO decides how many cells deep the room should be, based on a maximum cellcount for the whole room and on the principle that the number of cells along each
edge of the room should be roughly proportional to the length of that edge
*7
private int depthRes( int totalcellcount
double factor
( 2/rl + 2/(rl*r2) + I/(Math.pow(rl,2)*r2) );
return solveForDimension( totalcellcount, factor );
HEIGHTRES()
decides how many cells high the room should be
*/
private int heightRes( int totalcellcount )
double factor
( 2*rl + 2*rl/r2 + l/r2
return solveForDimension( totalcellcount, factor );
WIDTHRESO decides how many cells wide the room should be
*/
private int widthRes( int totalcellcount )
double factor
( 2*rl*Math. pow(r2, 2) + 2*rl*r2 + r2 );
return solveForDimension( totalcellcount, factor );
private int solveForDimension( int totalcellcount, double factor )
return (
new Double(
Math.ceil(
Math.pow(
new Integer(totalcellcount). doubleValue(
) / factor
), 0.5
)
)
).intValue()
7/
class Illumination
143
C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec
package illumination;
public class Initializer
FloorCeilingInitializer oneFloorCeilingInitializer;
oneSideWallInitializer;
SideWalllnitializer
oneFacadeInitializer;
FacadeInitializer
oneWorkplanelnitializer;
Workplanelnitializer
public InitializerO
oneFloorCeilingInitializer
oneSideWalllnitializer
oneFacadelnitializer
oneWorkplanelnitializer
//
=
=
=
=
new
new
new
new
FloorCeilinglnitializer();
SideWalllnitializer()
FacadeInitializer 0;
Workplanelnitializer(;
PUBLIC METHODS
public void setInitialLightLevels( Map room,
WindowSuite windowSpecs,
String blindShadingScheme,
double collectiveBlindAngle,
SolarSuite solarVars
{
initializeBlinds( room, collectiveBlindAngle,
solarVars
if ( noDirectSun(solarVars.solarAngleHorizontal)
I
initializeForNoDirectSun( room,
)
)
)
windowSpecs,
blindShadingScheme,
collectiveBlindAngle,
solarVars );
}
else
initializeWholeRoom( room,
windowSpecs,
blindShadingScheme,
collectiveBlindAngle,
solarVars );
}
public void initializeHiResWorkplane(
Map room,
WindowSuite windowSpecs,
String blindShadingScheme,
double collectiveBlindAngle,
SolarSuite solarVars
144
)
C:\Documents and Settings\Administrator\Desktop\Project
initializeBlinds( room, collectiveBlindAngle,
if
Latest\Essential Projec
solarVars );
( noDirectSun(solarVars.solarAngleHorizontal) )
surfaceToZero( room.hiResWorkplane );
else
oneWorkplanelnitializer.initialize( room.hiResWorkplane,
windowSpecs,
room.blinds,
blindShadingScheme,
room.isFirstWorkplanelnitialization,
room.workplaneBlindViewFactorArray,
solarVars );
room.isFirstWorkplanelnitialization = false;
7/
PRIVATE METHODS ----
---------------
------------------------
private void initializeBlinds( Map room, double collectiveBlindAngle,
SolarSuite solarVars
)
room.blinds.setCollectiveAngle( collectiveBlindAngle );
room. blinds. setRadiosity( solarVars.solarIncoming,
solarVars.solarAngleVertical );
private boolean noDirectSun( double solarAngleHorizontal
return ( solarAngleHorizontal >= 90
)
solarAngleHorizontal
<= -90 );
}
private void initializeForNoDirectSun( Map room,
WindowSuite windowSpecs,
String blindShadingScheme,
double collectiveAngle,
SolarSuite solarVars
for ( int surfaceIndex = 0; surfaceIndex
)
< room. number0fSurfaces;
surfaceIndex++
)
surfaceToZero( room.surfaces[surfaceIndex] );
}
oneFacadelnitializer.initialize( room.surfaces[room.
getNumberCorrespondingToSurfaceName(
"window" ) - 1],
windowSpecs,
room.blinds,
blindShadingScheme,
room.isFirstInitialization,
room.blindViewFactorArray[room.
145
C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec
getNumberCorrespondingToSurfaceName(
"window" ) 1],
solarVars
private void initializeWholeRoom( Map room,
WindowSuite windowSpecs,
String blindShadingScheme,
double collectiveAngle,
SolarSuite solarVars
)
if ( room.isFirstInitialization )
{ createBlindViewFactorArray( room
for ( int surfaceIndex = 0; surfaceIndex
< room. number0fSurfaces;
surfacelndex++
initializeSurface( room.surfaces[surfacelndex],
windowSpecs,
room.blinds,
blindShadingScheme,
room.isFirstInitialization,
room.blindViewFactorArray[surfacelndex],
solarVars
room.isFirstInitialization = false;
private void createBlindViewFactorArray(
Map room
for ( int i = 0; i < room.number0fSurfaces; i++
f
room. blindViewFactorArray[i] = new ViewFactorSuiteO;
private void surfaceToZero( Surface aSurface
for ( int i = 0; i
< aSurface.Q.length; i++ )
for ( int j = 0; j
< aSurface.Q[0].length; j++ )
aSurface.Q-initial[i][j]
aSurface.Q[i][j]
= 0;
= 0;
private void initializeSurface( Surface currentSurface,
WindowSuite windowSpecs,
BlindSet blinds,
146
)
C:\Documents and Settings\Administrator\Desktop\Project
Latest\Essential Projec
String blindShadingScheme,
boolean isFirstInitialization,
ViewFactorSuite blindFactors,
SolarSuite solarVars
)
if
( currentSurface.surfaceType.equals(
"platform"
))
oneFloorCeilinglnitializer. initialize( currentSurface,
windowSpecs,
blinds,
blindShadingScheme,
isFirstlnitialization,
blindFactors,
solarVars );
else if ( currentSurface.surfaceType.equals(
"sideWall"
))
oneSideWallInitializer.initialize( currentSurface,
windowSpecs,
blinds,
blindShadingScheme,
isFirstInitialization,
blindFactors,
solarVars )
else if ( currentSurface.surfaceType.equals(
"facade"
))
oneFacadeInitializer.initialize( currentSurface,
windowSpecs,
blinds,
blindShadingScheme,
isFirstlnitialization,
blindFactors,
solarVars );
else {}
147
C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec
package illumination;
.
public class Interpolator
public int[][][]
private double[][]
valueIndexArray;
outputArrayFinal;
public Interpolator( double[][] array )
/* The valueIndexArray contains the coordinates of the
node-points. A "node-point" is the center of each
field of identical numbers in the expanded version of
"array."
The row coordinate is stored in the first
level of valueIndexArray, and the column coordinate is
stored in the second level.
valueIndexArray = new int[( array. length + 2 )]
[( array[0]. length + 2 )][2];
public double[][] bilinearlnterpolate( double[][][] outputArrayFringed
)
int rowCounter = 0;
int colCounter = 0;
int rowCounterIncremented;
int colCounterIncremented;
double t;
double u;
fillValueIndexArray( outputArrayFringed );
for ( int row = 0; row
< outputArrayFringed. length; row++
/* The "checker" variable is used to find out if the current
values of "row" and "column" correspond to a node-point.
If so, "rowCounter" and "colCounter" are incremented
accordingly. */
for ( int checker = 0; checker < valueIndexArray. length;
checker++
148
)
C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec
0)
if ( valueIndexArray[checker] [0] [0] == row &&row
rowCounter++;
for
( int column = 0; column < outputArrayFringed[O]. length;
column++
if
)
( outputArrayFringed[row] [column] [1] == 0
for ( int checker = 0; checker <
valuelndexArray[0].length; checker++
)
if ( valuelndexArray[O][checker][1]
column && column
0)
colCounter++;
/* rowCounterIncremented is not necessarily the
next point over in the positive-row
dimension. As you approach the far side of
the array, you run out of "next points" in
that direction, and must reverse the
direction in which your coordinate point is
incremented. */
rowCounterIncremented = rowCounter + 1;
colCounterIncremented = colCounter + 1;
if
( outputArrayFringed. length - 1 ))
( row
rowCounterlncremented = rowCounter - 1;
if
( column
( outputArrayFringed[0].
length - 1))
colCounterIncremented = colCounter - 1;
/* u is the distance between the node-point
(rowCounter,colCounter) and the present
position (row,column) in the "row"
direction, divided by the distance between
(rowCounter,colCounter) and the next nodepoint over (rowCounterIncremented,
colCounterIncremented). */
u
( new Integer( row - valueIndexArray
[rowCounter][colCounter][0] ).doubleValue 0)
/ ( new Integer( valueIndexArray[
( rowCounterIncremented )]
[colCounter][0]
149
C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec
- valuelndexArray[
rowCounter]
[colCounter][0] ).
doubleValueO)
/* t is the distance between the node-point
(rowCounter,colCounter) and the present
position (row,column) in the "column"
direction, divided by the distance between
(rowCounter,colCounter) and the next nodepoint over (rowCounterIncremented,
colCounterIncremented). */
t
( new Integer( column - valuelndexArray[
rowCounter]
[colCounter][1] ).
doubleValue 0)
/ ( new Integer( valueIndexArray[
rowCounter]
[( colCounterIncremented )][1]
--
valueIndexArrayL
rowCounter]
[colCounter] [1] ).
doubleValue()
outputArrayFringed[row][column][0]
getPositionAveragedPointValue( u, t,
rowCounter, colCounter,
rowCounterIncremented,
colCounterIncremented,
outputArrayFringed );
}/ end if-statement
else
if ( column =0 )
{ colCounter++; }
}/ end for-loop for columns
colCounter = 0;
} // end for-loop for rows
return fillOutputArrayFinal( outputArrayFringed );
// end bilinearInterpolate(
See explanation of variable "valueIndexArray,"
above.
*7
private void fillValueIndexArray(
double[][][] outputArrayFringed )
int rowCounter = 0;
int colCounter = 0;
boolean rowEmpty
true;
150
C:\Documents and Settings\Administrator\Desktop\Project
for
(
int row = 0; row
<
Latest\Essential Projec
outputArrayFringed.length; row++
)
{
for
(
int column = 0; column
if
<
outputArrayFringed[O].
length;
column++ )
( outputArrayFringed[row][column][1] != 0 )
value{ndexArray[rowCounter][colCounter][0]
valuelndexArray[rowCounter][colCounter][
row;
=
column;
colCounter++;
rowEmpty
colCounter
false;
0;
if ( !rowEmpty )
rowCounter++;
rowEmpty = true;
The core of the bilinear interpolation.
Takes a grid position
in column-and-row coordinates u and t and calculates the
appropriate value at that point, as a function of the values
at the surrounding node-points.
*/
private double getPositionAveragedPointValue(
double u, double t,
int rowCounter, int colCounter,
int rowCounterIncremented,
int colCounterIncremented,
double[][][] outputArrayFringed
return ((
*
1(
t ) * (
1 - u)
outputArrayFringed[(
valueIndexArray[rowCounter][colCounter][0]
)]
[(
valuelndexArray[rowCounter][colCounter]
[1] )][0] )
(1-u)
t*
*
(
outputArrayFringed[(
valuelndexArray[rowCounter][colCounter][0]
[(
valueIndexArray[rowCounter]
[( colCounterIncremented )][1] )][0] )
t *u
151
C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec
*
(
valueIndexArray[(
outputArrayFringed[(
[(
(1l
*
t ) * u
outputArrayFringed[(
rowCounterIncremented
valueIndexArray[(
rowCounterIncremented
)]
[colCounter][0] )]
valueIndexArray[rowCounter][colCounter]
[1] )][0]
)
private double[][] fillOutputArrayFinal( double[][][]
outputArrayFringed
outputArrayFinal = new double[( outputArrayFringed. length - 2
[(
(
)
-
(
[(
for
)]
[colCounter][0] )]
valueIndexArray[rowCounter]
[( colCounterIncremented )][1] )][0]
)]
outputArrayFringed[0]. length
-
2 )];
int row = 0; row < outputArrayFinal. length; row++
for
(
int column = 0; column < outputArrayFinal[O].
length;
column++
)
outputArrayFinal[row][column]
outputArrayFringed[(
return outputArrayFinal;
152
row + 1
)][(
column + 1 )][0];
C:\Documents and Settings\Administrator\Desktop\Project
Latest\Essential Projec
package illumination;
// CLASS ITERATOR
Device that can be used to perform reflections between the inside surfaces of a room.
public class Iterator {
private ViewFactory
oneViewFactory;
Initializes variables
*/
public Iterator()
{
new ViewFactory();
oneViewFactory
}
Establishes holding arrays for the view factors between one surface and another.
Runs one iteration (one series of reflections involving all the surfaces in
a room)
*/
public void iterateRadiosityCalc( Map room
if
)
( room. isFirstIteration )
for {nt i
for r(
0; i < room.numberfSurfaces; i+)
t
= 0;
j
<j
room.numberfSurfaces; j++
room.viewFactorArray[i][j]=
new ViewFactorSuite( room.surfaces[i].a,
room.surfaces[i].b,
room.surfaces[j].a,
room.surfaces[j].b
);
I}
// Reset H arrays
for ( int surfaceIndex = 0; surfaceIndex
< room. numberOfSurfaces;
surfaceIndex++
{
initializeHArray( room, surfacelndex,
153
0 );
)
C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec
7/ Run iteration
for ( int surfaceIndex = 0; surfaceIndex
< room. number0fSurfaces;
surfacelndex++
)
radiosityCalc( room, surfaceIndex );
// Update Q arrays
for ( int surfaceIndex = 0; surfaceIndex
< room. numberOfSurfaces;
surfacelndex++
setQ( room, surfaceIndex
)
)
room.isFirstlteration = false;
public void showReflectionsOnLowResWorkplane(
Map room
)
// Create storage for view factors of workplane w.r.t. rest of room
if ( room. isFirstWorkplanelteration )
for ( int i
0; i
< room. numberOfSurfaces; i++ )
room. workplaneViewFactorArray[i]
new ViewFactorSuite( room. lowResWorkplane. a,
room.lowResWorkplane.b,
room. surfaces[i]. a,
room.surfaces[i].b
7/ Reset H array
room. lowResWorkplane. setHArrayTo( 0 );
7/
Do one set of reflections onto workplane
lowResWorkplaneRadiosityCalc( room
7/
Update workplane Q array
room.lowResWorkplane.setQo;
room. isFirstWorkplanelteration
/*-------------------------
false;
*/
----------------
--------------
private void initializeHArray( Map room, int surfaceIndex,
room. surfaces [surfaceIndex]. setHArrayTo( Hinitial
154
double H initial
)
)
C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec
private void radiosityCalc( Map room, int surfaceIndex
)
for ( int otherSurfaceNumber = 1; otherSurfaceNumber
< room.numberOfSurfaces; otherSurfaceNumber++
)
updateVariables( room, surfaceIndex, getOtherSurfaceIndex(
surfaceIndex, otherSurfaceNumber ));
private void lowResWorkplaneRadiosityCalc( Map room
)
for ( int otherSurfaceIndex = 0; otherSurfaceIndex < room. number0fSurfaces;
otherSurfaceIndex++ )
updateWorkplaneVariables( room, otherSurfaceIndex
)
private void setQ( Map room, int surfaceIndex
{
room. surfaces[ surfaceIndex]. setQO;
}
/*---------an "index" is on the
-----------------
---------------------------------------*/
0-upwards scale, and a "number" is on the 1-upwards scale
*/
private int getOtherSurfaceIndex( int surfaceIndex,
if ( otherSurfaceNumber
int otherSurfaceNumber )
<= surfaceIndex )
return otherSurfaceNumber - 1;
else {
return otherSurfaceNumber;
private void updateVariables( Map room, int surfaceIndex,
int otherSurfaceIndex
{room.surfaces[surfacelndex];
Surface surface
= room.surfaces[otherSurfaceIndex];
Surface otherSurface
int a = surface.a;
int b = surface.b;
int other a = otherSurface.a;
int otherb = otherSurface.b;
155
C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec
for ( int il = 0; il
for
for
( int i2
( int ji
for ( int j2
if
< a; il++ )
0; i2
< b; i2++ )
0; il
0; j2
< other-a; jl++
< other_b; j2++
( room. isFirstIteration )
room. viewFactorArray[surfacelndex] [otherSurfaceIndex].
surfaceToSurfacePairings[il][i2][jl][j2]
oneViewFactory.computeViewFactor(
otherSurface.alpha[jl][j2],
otherSurface.beta[jl][j2],
otherSurface. gamma[jl] [j2],
surface.alpha[il][i2],
surface. beta[il] [i2],
surface.gamma[ill[i2],
otherSurface.x[jl][j2],
surface. x[il] [i2],
otherSurface.y[jl][j2],
surface. y[il] [i2],
otherSurface.z[jl][j2],
surface. z[il] [i2],
surface. A[il] [i2]
)
surface.H[il][i2] + otherSurface.Q[jl][j2]
* otherSurface.A[jl][j2]
private void updateWorkplaneVariables(
Surface otherSurface
*
room.
/
viewFactorArray[surfacelndex]
[otherSurfaceIndex].
surfaceToSurfacePairings[il][i2]
[jl][j2]
surface. A[il] [i2];
Map room, int otherSurfaceIndex
room. surfaces [otherSurfaceIndex];
156
)
C:\Documents and Settings\Administrator\Desktop\Project
Latest\Essential Projec
int a = room.lowResWorkplane.a;
int b = room.lowResWorkplane.b;
int othera = otherSurface.a;
int otherb = otherSurface.b;
for ( int il
for
for
( int i2
( int j
0; il
0; i2
< b; i2++ )
0; jl
for ( int j2
if
< a; il++ )
0; j2
< othera; jl++
< otherb; j2++ )
( room.isFirstWorkplanelteration )
if
( otherSurface. y[jl] [j2] > room. lowResWorkplane.
constantCoordinate
)
room.workplaneViewFactorArray[otherSurfacelndex].
surfaceToSurfacePairings[il][i2][ji][j2]
oneViewFactory.computeViewFactor(
otherSurface.alpha[jl][j2],
otherSurface.beta[jl][j2],
otherSurface.gamma[jl][j2],
room.lowResWorkplane.alpha[il][i2],
room.lowResWorkplane.beta[il][i2],
room.lowResWorkplane.gamma[il][i2],
otherSurface.x[jl][j2],
room.lowResWorkplane.x[il][i2],
otherSurface.y[jl][j2],
room.lowResWorkplane.y[il][i2],
otherSurface. z[jI] [j2],
room.lowResWorkplane.z[il][i2],
room.lowResWorkplane.A[il][i2]
);
} else {
room.workplaneViewFactorArray[otherSurfacelndex].
surfaceToSurfacePairings[il][i2][jl][j2] = 0;
room.lowResWorkplane.H[il][i2] +=
otherSurface.Q[jl][j2]
* otherSurface.A[jl][j2]
* room.
157
C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec
/
workplaneViewFactorArray[otherSurfacelndex].
surfaceToSurfacePairings[il][i2][jl][j2]
room. lowResWorkplane. A[il][i2];
}
158
C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec
package illumination;
// CLASS MAP
Sets up a "room" by creating interior wall, floor, ceiling and window
surfaces, plus a set of blinds. It also declares an array to contain
view factors for every possible pairing of the discrete elements that
make up the areas of the interior surfaces.
Note that a new copy of
"settings" is created and associated permanently with each instance of
"Map."
public class Map {
public int
numberOfSurfaces = 5;
//private SettingSuite
settings;
public ViewFactorSuite[]L]
public ViewFactorSuite
viewFactorArray;
workplaneViewFactorArray;
blindViewFactorArray;
workplaneBlindViewFactorArray;
public BlindSet
public Surface[]
blinds;
surfaces;
public ViewFactorSuiteL]
public ViewFactorSuite[]
the 2 workplanes will eventually be combined into
//
public Platform
lowResWorkplane,
hiResWorkplane;
private
private
private
private
//
double
double
double
double
1
depth;
height;
width;
emissivity;
public boolean
public boolean
isFirstInitialization;
isFirstWorkplaneInitialization;
public boolean
public boolean
isFirstIteration;
isFirstWorkplaneIteration;
CONSTRUCTOR No.1
<B>Base constructor for Map class.</B>
*/
159
C:\Documents and Settings\Administrator\Desktop\Project
Latest\Essential Projec
public Map( SettingSuite settings
/* Settings are read in from a SettingSuite object, where they are all
defined *7
width
= settings.depthMagnitude;
= settings.heightMagnitude;
= settings.widthMagnitude;
emissivity
= settings.emissivity;
depth
height
new Surface[numberOfSurfaces];
surfaces
viewFactorArray
workplaneViewFactorArray
blindViewFactorArray
workplaneBlindViewFactorArray
= new ViewFactorSuite[numberOfSurfaces]
[numberOfSurfaces];
= new ViewFactorSuite[numberOfSurfaces];
= new ViewFactorSuite[numberOfSurfaces];
= new ViewFactorSuiteO;
isFirstInitialization
isFirstWorkplaneInitialization
= true;
isFirstIteration
isFirstWorkplanelteration
= true;
= true;
blinds
surfaces[0]
= true;
new BlindSet( settings.numberOfBlinds,
settings.widthMagnitude,
settings.blindSpacing,
settings.windowSpecs.sillHeight,
settings.windowSpecs.headHeight,
settings.emissivity
= new Platform( "floor",
settings.depthResolution,
settings.widthResolution,
settings.depthMagnitude,
settings.widthMagnitude,
settings.emissivity,
0
)
surfaces[1]
new SideWall( "sideWalll",
settings.depthResolution,
settings.heightResolution,
settings.depthMagnitude,
settings.heightMagnitude,
settings.emissivity,
0
surfaces[2]
new SideWall( "sideWall2",
settings.depthResolution,
settings.heightResolution,
settings.depthMagnitude,
settings.heightMagnitude,
settings.emissivity,
settings.widthMagnitude )
160
C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec
surfaces[3]
new Platform( "ceiling",
settings.depthResolution,
settings.widthResolution,
settings.depthMagnitude,
settings.widthMagnitude,
settings.emissivity,
settings.heightMagnitude )
surfaces[4]
new Facade( "window",
settings.heightResolution,
settings.widthResolution,
settings.heightMagnitude,
settings.widthMagnitude,
settings.emissivity,
0
}//
constructor No.1
----------------------------------
CONSTRUCTOR No.2 ------------------------
<B>Used for creating a duplicate copy of an existing Map object.
</B>
*/
public Map( Map room, SettingSuite settings
this( settings
for ( int i = 0; i
< numberOfSurfaces; i++ )
surfaces[i]. substituteQValues(
}
}//
constructor No.2
Returns the in-out dimension of the room
public double getDeptho
return depth;
Returns the up-down dimension of the room
*/
public double getHeighto
return height;
Returns the left-right dimension of the room
*/
161
room. surfaces[i].Q );
C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec
public double getWidtho
return width;
Returns a value between 0 and 255 corresponding to the
radiosity levels at the specified coordinates. <BR>
The following conventions apply when using this method:<BR>
<BR>
"x" corresponds to the depth (in-out) dimension<BR>
y" corresponds to the height (up-down) dimension<BR>
"z" corresponds to the width (left-right) dimension<BR>
<BR>
All coordinates are measured from an origin at the lower,
right-hand corner of the window surface,
assuming the window is viewed from inside the room. <BR>
Surface numbers run as follows:<BR>
<BR>
0: floor<BR>
1: sideWalll (right-hand side)<BR>
2: sideWall2 (left-hand side, looking toward window from inside)<BR>
3: ceiling<BR>
4: window
public double findRadiosityAtPoint( double x, double y, double z,
GrayScaleConverter grayValues
int surfaceNumber;
if ( x == 0 )
//
surface must therefore be a window
surfaceNumber = 4;
return getRadiosity( surfaceNumber, grayValues, y,
if ( y == 0 )
//
z );
surface must therefore be a floor
surfaceNumber = 0;
return getRadiosity( surfaceNumber, grayValues, x, z );
if ( y == height )
// surface must therefore be a ceiling
surfaceNumber = 3;
return getRadiosity( surfaceNumber, grayValues, x, z );
if
} ( z == 0 )
//
surface must therefore be a sideWalll
surfaceNumber = 1;
return getRadiosity( surfaceNumber, grayValues, x, y );
if
I
z == width )
// surface must therefore be a sideWall2
surfaceNumber = 2;
162
)
C:\Documents and Settings\Administrator\Desktop\Project
Latest\Essential Projec
return getRadiosity( surfaceNumber, grayValues, x, y
)
}
System.out.println(
"point requested does not lie on a surface of this room" );
return 0;
7*
Given a surface index ("N," the number from 0 to 4 corresponding
to one of the surfaces in the room - see definitions under
"findRadiosityAtPoint"), uses the "GrayScaleConverter" class
to return a value between 0 and 255 corresponding to the
radiosity level at the specified coordinates on the surface.
*/
private double getRadiosity( int N, GrayScaleConverter grayValues,
double surfaceCoordinatel,
double surfaceCoordinate2
return grayValues.convertRadiosityToGrayScale(
surfaces[N].Q[ findlndex0fReach(
surfaceCoordinatel,
surfaces [N]. a,
surfaces[N].parallelDistance )]
[ findlndexOfReach(
surfaceCoordinate2,
surfaces [N]. b,
surfaces[N].crossDistance )]
private int findlndex0fReach( double distance, int resolutionInDirection0fReach,
double totalDistance
double returnValue_D;
int indexOfReach;
returnValueD = distance / totalDistance * resolutionInDirectionOfReach;
/* the ceiling value of (returnValueD
1) is taken instead of the floor
of returnValue_D, in case returnValueD is a whole number. */
indexOfReach = new Double( Math. ceil( returnValueD - 1 )). intValue()
if (indexOfReach
< 0) { return 0; }
return indexOfReach;
163
)
C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec
Adds or subtracts the radiosity values of the input Map from
the dereferenced Map. The two Map objects may have different
resolutions, but in that case, the resolution of the output
will be that of the dereferenced Map. The input string
"smoothing" provides the option of using bilinear
interpolation to smooth the data points of the input Map
before it is added or subtracted.
public void addRadiositiesFrom( Map addedRoom, String operation, String smoothing
for ( int i = 0; i
f
< numberOfSurfaces; i++ )
surfaces[i]. addRadiositiesFrom( addedRoom. surfaces[i],
operation,
smoothing );
}
}
public void createWorkplanes( double workplaneHeight,
lowResWorkplane
int lowRes a, int lowRes_b,
int hiResa, int hiRes-b
new Platform( "workplane",
lowRes_a,
lowResb,
depth,
width,
emissivity,
workplaneHeight
hiResWorkplane
new Platform( "workplane",
hiRes a,
hiResa,
depth,
width,
emissivity,
workplaneHeight
}
public int getFloorResolutiona()
{
return surfaces[0].a;
}
public int getFloorResolutionb()
return surfaces[0].b;
164
C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec
public void replaceFloor( Surface workplane, String smoothing
)
I
surfaces[0].replaceSurface( workplane, smoothing );
}
public String getSurfaceNameCorrespondingToNumber(
int number
)
switch ( number )
case 1:
return "floor";
case 2:
return "sideWalll";
case 3:
return "sideWall2";
case 4:
return "ceiling";
case 5:
return "window";
default:
return null;
public int getNumberCorrespondingToSurfaceName(
if ( surfaceName.equals(
"floor"
String surfaceName
))
return 1;
else if ( surfaceName.eequals(
"sideWalll"
))
"sideWall2"
))
return 2;
}
else if ( surfaceName.equals(
return 3;
else if ( surfaceName.equals(
"ceiling"
))
return 4;
else if ( surfaceName.equals(
"window" ))
return 5;
} else I
return 0;
165
)
C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec
public void cleanUpo
// Resets Map to its virgin state
clearBilinearGrids (;
clearViewFactorArrays
0;
private void clearBilinearGrids(
for
( int i = 0; i < number0fSurfaces; i++ )
surfaces[i]. clearBilinearGrid();
private void clearViewFactorArrays()
isFirstInitialization
isFirstWorkplanelnitialization
= true;
= true;
public void setCollectiveBlindAngle( double newBlindAngle
blinds.setCollectiveAngle( newBlindAngle
public double getCollectiveBlindAngleo
return blinds.getCollectiveAngle(;
166
)
)
C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec
package illumination;
public class PerspectiveView
I
int fullPixelWidth;
int fullPixelHeight;
int roomPixelWidth;
int roomPixelHeight;
int marginPixelHeight;
int marginPixelWidth;
boolean preserveAspectRatio = true;
double roomWidth;
double roomHeight;
double roomDepth;
double observerWidth; 7/ from left wall
double observerHeight; // from floor
double observerDepth; /7 from near wall
Wall
Wall
Wall
Wall
Wall
farWall;
leftWall;
rightWall;
ceiling;
floor;
*/
Map room;
// Added 8/22/02 by Matthew Lehar
Map otherRoom;
boolean accountFor0therViewInHistogram = false;
/*
public PerspectiveView (double roomWidth, double roomHeight, double roomDepth,
double observerWidth, double observerHeight, double observerDepth,
Wall farWall,
Wall leftWall,
Wall rightWall,
Wall ceiling,
Wall floor)
167
C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec
{
this.roomWidth = roomWidth;
this.roomHeight = roomHeight;
this.roomDepth = roomDepth;
this.observerWidth = observerWidth;
this.observerHeight = observerHeight;
this.observerDepth = observerDepth;
this.farWall
= farWall;
this.leftWall = leftWall;
this.rightWall = rightWall;
= ceiling;
this.ceiling
= floor;
this.floor
I
public PerspectiveView (double roomWidth,
Wall farWall,
Wall leftWall,
Wall rightWall,
Wall ceiling,
Wall floor)
double roomHeight, double roomDepth,
roomWidth;
roomHeight;
roomDepth;
this.roomWidth
this.roomHeight
this.roomDepth
this.observerWidth = 0.5 * roomWidth;
this.observerHeight = 0.5 * roomHeight;
this.observerDepth = roomDepth;
this.farWall
= farWall;
this.leftWall = leftWall;
this.rightWall = rightWall;
= ceiling;
this.ceiling
= floor;
this.floor
}
public PerspectiveView (Map room,
double observerWidth,
double observerHeight,
double observerDepth)
I
this.room = room;
this.roomWidth
= room.getWidth();
this.roomHeight = room.getHeight();
this.roomDepth = room.getDepth(;
//System.out.println( roomDepth );
this.observerWidth = observerWidth;
this.observerHeight = observerHeight;
this.observerDepth = observerDepth;
}
168
C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec
// ADDED 8/22/02 by Matthew Lehar
// for the case in which both rooms are to b
public PerspectiveView (Map room,
e included in the brightness histogram
Map otherRoom,
double observerWidth,
double observerHeight,
double observerDepth)
this( room,
observerWidth,
observerHeight,
observerDepth
);
//System. out. println( "using 2-room cons tructor for perspectiveView" );
this.otherRoom = otherRoom;
accountForOtherViewInHistogram = true;
public PerspectiveView (Map room)
this.room = room;
this.roomWidth = room.getWidth(;
this.roomHeight = room.getHeight();
this.roomDepth = room.getDepth(;
this.observerWidth = 0.5 * this.roomWidth;
this.observerHeight = 0.5 * this.roomHeight;
this.observerDepth = this.roomDepth;
}
/7 ADDED 10/6/02 by Matt-hew Lehar
public PerspectiveView (Map room,
Map otherRoom)
{
this( room,
otherRoom,
0.5 * room.getWidth(,
0.5 * room.getHeighto,
room.getDepth(
)
I
private void setPixelDimensions(int pixelWidth, int pixelHeight)
{
fullPixelWidth = pixelWidth;
fullPixelHeight = pixelHeight;
if
(!
preserveAspectRatio)
roomPixelWidth
= fullPixelWidth;
roomPixelHeight = fullPixelHeight;
marginPixelWidth = 0;
marginPixelHeight = 0;
169
C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec
}
else
{
if ((double) fullPixelWidth / (double) fullPixelHeight >= roomWidth / roomHeight)
{
// side margins
roomPixelWidth
= (int) Math.round(fullPixelHeight * (roomWidth / roomHeight));
roomPixelHeight
= fullPixelHeight;
marginPixelWidth = (fullPixelWidth - roomPixelWidth) / 2;
marginPixelHeight = 0;
else
{
// top/bottom margins
roomPixelWidth
= fullPixelWidth;
roomPixelHeight
= (int) Math.round(fullPixelWidth * (roomHeight / roomWidth));
marginPixelWidth = 0;
marginPixelHeight = (fullPixelHeight roomPixelHeight) / 2;
System.out.println("roomPixelWidth: "
System.out.println("roomPixelHeight:
System. out. println("marginPixelWidth:
System. out. println("marginPixelHeight:
roomPixelWidth);
+ roomPixelHeight);
+ marginPixelWidth);
+ marginPixelHeight);
public int[][] drawImage(int pixelWidth, int pixelHeight,
int number0fBins
setPixelDimensions (pixelWidth, pixelHeight)
Box box = new Box (roomWidth, roomHeight, roomDepth,
observerWidth, observerHeight, observerDepth);
Point3D strike;
int shade;
double x, y;
GrayScaleConverter grayScale = createGrayScaleConverter(
number0fBins );
int[][] image = new int[fullPixelWidth][fullPixelHeight];
for (int px=0; px
< roomPixelWidth; px++)
x = (((double) px + 0.5) / roomPixelWidth) * roomWidth;
for (int py=O; py
< roomPixelHeight; py++)
y = (((double) py + 0.5)
/ roomPixelHeight) * roomHeight;
//System. out.println("px:" + px + " py:" + py);
//System. out.println("x:" + x + " y:" + y);
170
C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec
strike = box.findStrike(x, y);
//System. out. printin (strike. toString());
77
Note that the origin is in a different position in the room (Map)
/7 Note also that depth and width are switched
shade = (int) room. findRadiosityAtPoint(roomDepth - strike. z,
strike.y,
roomWidth - strike.x,
grayScale);
/if
(shade > 20)
{System.out.println( "halleluja" );}
/*
if (strike.z == roomDepth)
{
// struck far wall
shade = farWall. getShade (strike. x, strike. y)
}
else if (strike.x == roomWidth)
{
// struck right wall
shade = rightWall. getShade(roomDepth - strike. z, roomHeight
}
else if (strike.y == roomHeight)
strike. y)
7/ struck ceiling
shade = ceiling. getShade (strike. x, strike. z)
}
else if (strike.x == 0.0)
f
// struck left wall
/7 shade = leftWall.getShade(strike.z, strike.y);
shade = leftWall. getShade (strike. z, roomHeight - strike. y)
}
else // (strike.y == 0.0)
{
// struck floor
shade = floor. getShade(strike.x, roomDepth - strike. z);
*/
1
image[marginPixelWidth + px][marginPixelHeight + (roomPixelHeight
return image;
private GrayScaleConverter createGrayScaleConverter(
I
if ( accountFor~therViewInHistogram)
171
int number0fBins
)
py)]
shade
C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec
{ return new GrayScaleConverter( room, otherRoom, numberOfBins );
else
{ return new GrayScaleConverter( room, numberOfBins );
}
}
package illumination;
// CLASS PLATFORM
Populates some of the basic arrays for the surface and invokes methods
in the superclass to completely create the surface.
The "Platform"
class of surfaces includes floor and ceiling.
*/
public class Platform extends Surface
public Platform( Platform onePlatform
this(
)
onePlatform.name,
onePlatform.a,
onePlatform.b,
onePlatform.parallelDistance,
onePlatform.crossDistance,
onePlatform.emissivity,
onePlatform.constantCoordinate );
substituteQValues( onePlatform.Q );
}
public Platform(
String name,
int parallelResolution,
int crossResolution,
double parallelMagnitude,
double crossMagnitude,
double emissivity,
double constantCoordinate
I
surfaceType = new String( "platform" );
constructSurface(
name,
parallelResolution,
crossResolution,
parallelMagnitude,
crossMagnitude,
emissivity,
constantCoordinate
172
)
C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec
//OBSOLETE VARIABLES:
resolutions[O] = 0;
resolutions[1] = 1;
resolutions[2] = 0;
/* thirdIsConstant is used later on in the program to orient
the surface grids properly before they are sent to the viewer
program
thirdIsConstant = false;
'a' and 'b' are the lengthwise and widthwise resolutions of the surface.
'parallelDistance' and 'crossDistance' are the length and width of the
surface */
for ( int rowCounter = 0; rowCounter < a; rowCounter++ )
for
( int columnCounter = 0; columnCounter < b; columnCounter++
x[rowCounter][columnCounter]
*
= constantCoordinate;
= ( crossDistance / b )
* ( columnCounter + 0.5 );
y[rowCounter][columnCounter]
z[rowCounter][columnCounter]
alpha[rowCounter][columnCounter]
beta[rowCounter][columnCounter]
gamma[rowCounter][columnCounter]
A[rowCounter][columnCounter]
173
( parallelDistance / a )
( rowCounter + 0.5 );
= 0;
= 1;
= 0;
= parallelDistance
* crossDistance / ( a * b );
C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec
package illumination;
public abstract class PlatformInitializer extends SurfaceInitializer
class contains initialization instructions specific to "platform" surfaces
(i.e. floors or ceilings)
Only one view factor is computed between each blind slat and
each element of the platform (i. e. floor or ceiling) grid.
The center of the blind slat
is the reference position, but in order to avoid making it
appear as though the center of the slat is the origin of
all refelcted light, the view factors between the slat and all
the floor elements in a horizontal (widthwise) row are averaged.
The resulting average view factor is then used for all floor
elements in that row.<BR>
<BR>
The radiosity of each blind surface is applied to each platform element,
attenuated by the average view factor and also by a flag ("lineOfSightFlag").
This flag takes the value 0 if there is an obstruction between the lit surface
of the blind and the platform element in question.
public void calculateFirstReflectionFromBlinds(
if ( isFirstInitialization
BlindSet blinds,
boolean isFirstInitialization,
ViewFactorSuite blindFactorslD,
Surface currentSurface )
)
//System.out.println( "done!" );
blindFactors_lD.makeBlindFactors
lD( currentSurface. a,
blinds. totalNumber );
for ( int i
if
0; i
< currentSurface.a; i++ )
( isFirstInitialization )
for
( int blindIndex = 0; blindIndex < blinds. totalNumber;
blindlndex++
for ( int j = 0; j
)
< currentSurface. b; j++ )
blindViewFactorSum[i] [blindIndex] +=
lineOfSightFlag( i, j, ( blindIndex +
174
1 ),
C:\Documents and Settings\Adininistrator\Desktop\Project
Latest\Essential Projec
blinds, verticalAngle
)
* oneViewFactory.
computeViewFactorWithBlinds(
currentSurface,
i,
j,
( blindlndex + 1 ),
blinds,
verticalAngle );
blindFactorsiD.surfaceToBlindPairings_lD[i][blindlndex]
blindViewFactorSum[i][blindIndex] / currentSurface.b;
}
for
( int j
j < currentSurface.b; j++ )
0;
{
for ( int blindNumber = 1; blindNumber
<= blinds.totalNumber; blindNumber++
)
currentSurface.Q initial[i][j] +=
blinds. getRadiosity( blindNumber ) * blinds. slatAreaO
* blindFactors lD.surfaceToBlindPairingslD[i][blindNumber - 1]
/* * lineOfSightFlag( i, j, blindNumber, blinds, verticalAngle )
* ( 1 - emissivity ) / currentSurface.A[i][i];
*/
currentSurface.Q[i][j] = currentSurface.
Q-initial[i][j];
public double findAngleOnSurface(
double verticalAngle,
double horizontalAngle
7*
the "angleOnSurface" is the angle defining the amount of diagonal
slant of the sides of the patch of sunlight that resides on the
platform surface
*7
return horizontalAngle;
175
)
C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec
package illumination;
A simple point in 3D space. (x, y, z)
public class Point3D
I
public double x;
public double y;
public double z;
public Point3D()
f
}
public String toString()
r
return ("(
+ x +
"
,"+
z + ""
176
C:\Documents and Settings\Administrator\Desktop\Project
Latest\Essential Projec
package illumination;
This class does some calculations related to raytracing a rectangular room.
Specifically,
this class is used by Box to simplify calculations.
Basically, we have an observer standing behind a box at some distance away.
From the
The observer always stands "in line" with the origin of the box.
observer's perspective, the origin (0,0,0) is at the lower left corner of
the near face of the box. He stands at (0,0, some-depth).
When a line
is drawn from the eye of the observer through the
rear wall of the room,
we want to know where this line intersects another surface (wall, ceiling,
or floor) of the room. This intersection is returned as a Point3D.
public class Quadrant
I
private double w;
private double h;
// quad width (x direction)
/7 quad height (y)
private double d;
/7
private double dO;
quad depth
7/ observer
(z)
distance from image plane (z direction)
public static void main (String[] args)
f
Quadrant q = new Quadrant (10. 0, 10. 0,
10. 0,
10. 0);
double x = Double. valueof (args[0]). doubleValue(;
double y = Double. valueOf(args[]). doubleValueo;
Point3D s = q.findStrike(x, y);
System.out.println(s.toStringo);
}
public Quadrant (double w, double h, double d, double observerDistance)
f
this.w
w;
this.h
h;
this.d
d;
this.dO = observerDistance;
}
//for a given x,y
//return x, y, z of strike
public Point3D findStrike (double x,
double y)
{
177
C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec
Point3D strike = new Point3DO;
7/ fwx:
x of where ray strikes plane of far wall
(far wall y) y of where ray strikes plane of far wall
// Both are measured from where the observer's
(far wall x)
7/ fwy:
7/ direct
line of sight intersects the far wall.
double fwx = x * (do + d) / dO;
double fwy = y * (dO + d) / dO;
//System.out.println("fwx: " + fwx);
//System.out.println("fwy: " + fwy);
if (fwx <= w && fwy <= h)
I
// strikes far wall
strike.x = fwx;
strike.y = fwy;
strike.z = d;
}
else
I
7/awz:
7/ cgz:
(adj wall z) z of where ray strikes plane of adjacent wall
(ceilling z) z of where ray strikes plane of ceiling
double awz = dO * (w
double cgz = dO * (h
-
x) / x;
y) / y;
// x coord of where ray strikes adjacent wall
77
y coord of where ray strikes adjacent wall
//System. out.println("awz: " + awz);
//System.out.println("cgz: " + cgz);
if (awz == cgz)
77
strikes edge between adjacent wall and ceiling
// note that if this case is not included the
77
77
calculation of strike.y may wind up very slightly
greater than the height (incorrectly) due to
77 problems with large decimal math.
strike.x = w;
strike.y = h;
strike.z = awz;
I
else if (awz
{
// strikes
strike.x =
strike.y =
strike.z =
<
cgz)
adjacent wall
W;
(awz + do) * y / dO;
awz;
else
7/ strikes ceiling/floor
strike.x = (cgz + do) * x / dO;
strike.y = h;
strike.z = cgz;
}
178
C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec
}
return strike;
I
}
package illumination;
public class Resizer
private double
public int[][][]
temporary;
refIndexArray;
public Resizer()
public double[][][]
{
getArrayAndlndeces( double[][] array
double outputArray[][] []
new double[array.length][array[O].length]
[2];
new int[array.length][array[0].length]
[2];
refIndexArray
for ( int rowlndex = 0; rowIndex
{
for ( int collndex =
{
0;
< array.length; rowIndex++ )
collndex
<
array[0].
length;
collndex++)
outputArray[rowIndex][collndex][0]
array[rowlndex]
outputArray[rowlndex][collndex][1]
1;
[collndex];
refIndexArray[rowIndex][collndex][0]
reflndexArray[rowIndex][colIndex][1]
= rowlndex;
= colIndex;
return outputArray;
Takes a pair of resolutions and returns a 2-D array of two layers (actually a 3-D
array).
On the first
layer, the data from the array called "array" has
been stretched out to the grid size specified by "surfaceWidth" and
"surfaceHeight."
The second layer is a grid of the same size as the first,
but filled with zeros. Ones are placed among the zeros to indicate, in
parallel with the first layer, the center of a region that has been scaled
up
from a single data point in the original array
179
("array").
C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec
*7
public double[][][] getArrayAndlndeces( double[][] array, int a, int b )
double outputArray[][][];
double
double
double
double
double
double
numRows double;
numCols-double;
a_double;
b_double;
i_double;
j-double;
double rowIndex-nought;
double colIndex-nought;
int rowIndex
int colIndex
0;
0;
int lastRowValue
int lastColValue
0;
0;
int rowCounter
0;
int colCounter
0;
refIndexArray
new int[a][b][2];
numRowsdouble
numColsdouble
new Integer (array. length). doubleValue()
new Integer(array[0]. length). doubleValueO;
a double
b double
new Integer(a).doubleValueo;
new Integer(b).doubleValueo;
outputArray
new double[a] [b] [2];
//
for an explanation of the "+ 1,"
for ( int i = 0; i
colCounter
for ( int
{
see comment at "rowlndexnought,"
below
< a + 1; i++ )
0;
j
0; j
i_double
jdouble
< b + 1; j++ )
new Integer(i). doubleValue() ;
new Integer(j). doubleValueo;
/* The first value taken by rowIndex_nought is 0, and the
last is the length of the array minus 1, just as
usual for array indexing. There is a different
number (generally more) of values of
rowIndex_nought than elements in the original
array. The "adjustIndex" method is used to
"stretch out" the crushed-together rowIndex nought
values, so that the first aligns with the front
180
C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec
edge of the first cell of the original array, the
last with the back edge of the last cell, and the
others are spaced equally in-between, except that
there is only a half-measure space between the
first and second, and penultimate and last, cells.
i double / a-double ) *
( numRowsdouble - 1 );
colIndex nought =( jdouble / b double ) *
( numColsdouble - 1)
rowIndex nought =
rowIndex = new Double( adjustIndex( rowIndex
numRowsdouble
colIndex = new Double( adjustlndex( collndex
numColsdouble
nought,
)).intValue();
nought,
)).intValue();
if ( rowIndex != lastRowValue &&colIndex != lastColValue )
/* Each time a new row is reached, places a "1"
among the zeros of the 2nd layer of the
"outputArray" array. The "1" corresponds
to the point positioned in the center of
the field of numbers that each single
element of the original array has been
expanded to fill.
*/
outputArray
[( i
-
[( j
-
new Double( Math.ceil( new
Integer( rowCounter ).
doubleValueo / 2 )).
intValue 0)]
new Double( Math.ceil( new
Integer( colCounter ).
doubleValue( / 2 )).
intValue())]
[1]
=
lastColValue
colCounter
1;
= colIndex;
= 0;
}
if ( i
I
< a &&j < b )
outputArray[i][j][0]
= array[rowlndex]
[collndex];
refIndexArray[i][j][0]
refIndexArray[i][j][1]
colCounter++;
}
if ( rowlndex != lastRowValue )
{
181
= rowIndex;
= collndex;
C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec
= rowIndex;
= 0;
lastRowValue
rowCounter
lastColValue = 0;
rowCounter++;
return outputArray;
If the indeces represent the centers of cell-elements, then
the following method re-distributes those indeces so that the
first index is aligned with the front edge of the first cell,
the last index with the back edge of the last cell, and all
These indeces are
the other indeces evenly spaced in-between.
then rounded, and any negative results made zero.
*/
private double adjustIndex( double index_nought,
double inputResolution
( inputResolution - 1
temporary = Math.round(( indexnought
( inputResolution / ( inputResolution
( inputResolution - 1 ) / 2 )
if ( temporary
< 1
temporary
0;
return temporary;
182
)
) / 2) *
- 1 )) +
C:\Documents and Settings\Administrator\Desktop\Project
Latest\Essential Projec
package illumination;
//
CLASS SETTINGSUITE
Stores illumination parameters.
public class SettingSuite
public double
emissivity;
public double
public double
public double
depthMagnitude;
heightMagnitude;
widthMagnitude;
public int
public int
public int
depthResolution;
heightResolution;
widthResolution;
public WindowSuite
windowSpecs;
public int
public double
numberOfBlinds;
blindSpacing;
// Constructor No.1 - base constructor
<B>Base constructor for SettingSuite class.</B>
public SettingSuite(
double emissivity,
double depth,
double height,
double width,
int RESOLUTION_i,
int RESOLUTION j,
int RESOLUTION_k,
WindowSuite windowSpecs,
int numberOfBlinds,
double blindSpacing
183
)
C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec
this.emissivity
= emissivity;
this.depthMagnitude
this.heightMagnitude
= depth;
= height;
= width;
this.widthMagnitude
this.widthResolution
= RESOLUTIONi;
= RESOLUTIONj;
= RESOLUTION-k;
this.windowSpecs
= windowSpecs;
this.numberOfBlinds
this.blindSpacing
= numberOfBlinds;
= blindSpacing;
this.depthResolution
this.heightResolution
}
//
Constructor No.2
<B>Usec
for creating a copy of an existing SettingSuite object, with only the
resolution values changed.</B>
public SettingSuite( SettingSuite
int
int
int
settings,
RESOLUTION_i,
RESOLUTION-j,
RESOLUTION k )
f
this(
settings.emissivity,
settings.depthMagnitude,
settings.heightMagnitude,
settings.widthMagnitude,
RESOLUTION-i,
RESOLUTION-j,
RESOLUTION-k,
settings.windowSpecs,
settings.numberOfBlinds,
settings.blindSpacing
}
}
184
C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec
package illumination;
// CLASS SIDEWALL
Populates some of the basic arrays for the surface and invokes methods
in the superclass to completely create the surface.
The "SideWall"
class of surfaces includes sideWalll and sideWall2.
*7
public class SideWall extends Surface{
public SideWall(
String name,
int parallelResolution,
int crossResolution,
double parallelMagnitude,
double crossMagnitude,
double emissivity,
double constantCoordinate
)
{
surfaceType = new String( "sideWall" );
constructSurface(
name,
parallelResolution,
crossResolution,
parallelMagnitude,
crossMagnitude,
emissivity,
constantCoordinate
//OBSOLETE VARIABLES:
resolutions[0] = 0;
resolutions[l] = 0;
resolutions[2] = 1;
/* thirdIsConstant is used later on in the program to orient
the surface grids properly before they are sent to the viewer
program
*/
thirdIsConstant = true;
/* For-loop: populates some of the basic arrays for the surface, including
arrays giving position in x, y, and z; alpha, beta, and gamma, each of
which has the value 1 if the normal vector to the surface points in the x,
y, and z directions, respectively, and has the value 0 otherwise; and A,
the differential area of each element of the grid surface.
185
C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec
a' and 'b' are the lengthwise and widthwise resolutions of the surface.
parallelDistance' and 'crossDistance' are the length and width of the
surface
*/
for ( int rowCounter = 0; rowCounter
< a; rowCounter++ )
for ( int columnCounter = 0; columnCounter < b; columnCounter++ )
I
x[rowCounter][columnCounter]
( parallelDistance / a )
* ( rowCounter + 0.5);
( crossDistance / b )
y[rowCounter][columnCounter]
* ( columnCounter + 0.5 );
z[rowCounter][columnCounter]
= constantCoordinate;
alpha[rowCounter][columnCounter
beta[rowCounter][columnCounter]
gamma[rowCounter][columnCounter
A[rowCounter][columnCounter]
=
]
0;
1;
parallelDistance
* crossDistance /
}
I
}
}
186
( a * b );
C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec
package illumination;
public class SideWallInitializer extends SurfaceInitializer
public SideWallInitializero
public void initialize( Surface currentSurface,
WindowSuite windowSpecs,
BlindSet blinds,
String blindShadingScheme,
boolean isFirstInitialization,
ViewFactorSuite blindFactors_2D,
SolarSuite solarVars
)
initializeSurfaceVariables(
currentSurface,
blinds,
windowSpecs,
solarVars );
imposeBlindSlatShadows( blinds );
applyPatchOfSunlight( blindShadingScheme );
calculateFirstReflectionFromBlinds(
blinds,
isFirstInitialization,
blindFactors_2D,
currentSurface )
public void calculateFirstReflectionFromBlinds(
BlindSet blinds,
boolean isFirstInitialization,
ViewFactorSuite blindFactors_2D,
Surface currentSurface
if ( isFirstInitialization
)
blindFactors_2D.makeBlindFactors_2D( currentSurface.a,
currentSurface.b,
blinds. totalNumber
for ( int i
<
0; i
for ( int
j
currentSurface.a;
= 0;
j<
i++ )
currentSurface.b;
187
j++ )
)
C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec
if
( isFirstInitialization )
for ( int blindIndex = 0; blindIndex
< blinds. totalNumber; blindIndex++
)
blindFactors_2D. surfaceToBlindPairings_2D[i] [j]
[blindIndex]
lineOfSightFlag( i, j, ( blindlndex + 1 ),
blinds, verticalAngle )
* oneViewFactory.
computeViewFactorWithBlinds (
currentSurface,
i,
( blindIndex + 1 ),
blinds,
verticalAngle );
for ( int blindNumber
1; blindNumber
<= blinds.totalNumber; blindNumber++
)
/*
The radiosity of each blind surface is applied to
each platform element, attenuated by the average
view factor and also by a flag ("lineOfSightFlag").
This flag takes the value 0 if there is an
obstruction between the lit surface of the blind
and the platform element in question.
currentSurface.Q initial [i] [i] +=
blinds. getRadiosity( blindNumber ) * blinds. slatArea()
* blindFactors_2D. surfaceToBlindPairings_2D[i] [j] [blindNumber
/* * lineOfSightFlag( i, j, blindNumber, blinds, verticalAngle
* ( 1 emissivity ) / currentSurface.A[i][i];
currentSurface. Q[i] [j]
public void imposeBlindSlatShadows(
BlindSet blinds
1]
) */
currentSurface.
Q initial[i][j];
)
initializeMaskso;
for ( int blindNumber = 1; blindNumber
<= totalNumber0fBlinds;
blindNumber++
188
)
Latest\Essential Projec
C:\Documents and Settings\Administrator\Desktop\Project
find indeces that mark the beginnings and endings
of blind shadows in the crosswise direction along
the sideWall
= blinds. getEquivalentDistance(
blindNumber, verticalAngle,
"start" );
blindStartEndDistances[I] = blinds. getEquivalentDistance(
blindNumber, verticalAngle,
"end" );
blindStartEndDistances[0]
blindStartEndIndeces = findIndecesOfNearAndFarReach(
blindStartEndDistances, b, crossDistance
)
/*
create black spaces in the crosswise (row) mask that
correspond to the positions of the blind shadows
*7
for ( int i
blindStartEndIndeces[O]; i
<= blindStartEndIndeces[1]; i++
if ( i < 0 )
if ( i > rowTemplate.length rowTemplate[i] =
public void applyPatchOfSunlight(
)
{ i = 0;
1)
{ break; }
0;
String blindShadingScheme
/*
"right" and "left" determine the limits in the DEPTH dimension
of the patch of sunlight projected onto the sideWall
from the window
"blockl" and "block2" are here defined as the sill and head of
the window area, and limit the patch of sunlight on the sideWall
in the HEIGHT dimension
*/
nearAndFarDistances = findNearAndFarDistances(
right,
left,
horizontalAngle
)
blockl = sill;
block2 = head;
obliqueIntensityFraction = find0bliqueIntensityFraction(
illuminateWithSunlight( blindShadingScheme,
public double findAngleOnSurface(
obliqueIntensityFraction );
double verticalAngle,
189
horizontalAngle );
double horizontalAngle
C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec
the "angleOnSurface" is the angle defining the amount of diagonal
slant of the sides of the patch of sunlight that resides on the
sideWall surface
return -verticalAngle;
The minus sign is a necessary correction: vertical angle is defined as the
angle from the horizon upward to the sun' s position, but to make
this angle compatible with the definition of the horizontal angle
(to the right as you look out of the window), so that they will
work interchangably as the angles of light cast on the surfaces of
the room, we need to reverse the sign.
190
C:\Documents and Settings\Administrator\Desktop\Project
Latest\Essential Projec
package illumination;
import java.io.*;
By JIM GOULDSTONE
public class SolarInfoCalculator {
private
private
private
private
double
double
double
double
dnr
dhr
altitude
azimuth
=
=
=
=
0;
0;
0;
0;
private double directIntensity = 0;
private double diffuselntensity = 0;
private WeatherDataReader weather;
private Azimuth azCalc;
public double getAltitude(
{ return altitude; }
public double getAzimuth()
{ return azimuth; }
public double getDirectlntensityo
{ return directIntensity; }
public double getDiffuselntensityo
{ return diffuseIntensity; }
public SolarlnfoCalculator( String weatherFile,
String orientation
try
//
First create and initialize the weather reader
weather = new WeatherDataReader 0;
weather.read(weatherFile);
// then, the azimuth calculator
azCalc = new Azimuth( weather.getLatitude(), orientation );
System. out. println( "LATITUDE READ: " +weather. getLatitude 0);
191
C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec
catch (IOException iox)
System.out.println(iox.toString());
public void positionForHour( int month,
int hourOfDay
dnr
weather.getDirectNormalRadiation(month, hourOfDay);
dhr = weather. getDiffuseHorizontalRadiation(month, hourOfDay);
System.out.println("dnr: " + dnr);
System.out.println("dhr:
"
+ dhr);
*/
7/ Call calculate method of Azimuth.
// This will not return answers. Instead, it stores
// several relevant values within Azimuth to be
// accessed by other methods.
azCalc.calculate (month, hourOfDay, dnr, dhr);
// Grab solar angle info from azimuth.
altitude = azCalc.getAltitudeO;
/7 MATT LEHAR, 8/6/02: I TAKE THE NEGATIVE OF THE
77 sURFACEsOLARaZIUMTH TO MAKE IT CONSISTENT WITH
/7 THE WAY IN WHICH AN AZIMUTH IS DEFINED IN THE
// REST OF THE ILLUMINATION PACKAGE
azimuth = -1 * azCalc.getSurfaceSolarAzimutho;
directIntensity
azCalc.getDirectRadiationGaino;
diffuseIntensity
azCalc.getDiffuseRadiationGain(;
//System. out. println("alt:
//System. out. println("azi:
"
"
+ Azimuth. toDegrees (altitude))
+ Azimuth. toDegrees (azimuth))
/*
System.out.println( "dir: " +directIntensity );
System.out.println( "diff: "+diffuselntensity );
*/
/7 Regarding altitude:
7/ 0'
77 90'
77 < 0'
77 > 90'
sun is
sun is
sun is
should
on horizon
overhead
below horizon
never happen.
/7 Regarding azimuth (surface solar azimuth):
77
77
77
77
77
77
This is the horizontal position of the sun w/ respect to
the facade surface.
0'
sun is striking surface head on (horizontally, anyway)
-90' thru 90' means sun is striking surface
(Sorry, when this was written we weren't concerned with
which side was which. I'll check into this soon.)
192
C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec
/7
-
7/
MY CODE.
SIDE NOTE: I JUST CHECKED INTO THIS AND CHANGED THE CONVENTION
IN SOLARINFOCALCULATOR (SEE ABOVE) TO AGREE WITH THE REST OF
AZIMUTH IS NOW
//
POSITIVE IF MEASURED TO THE RIGHT OF DEAD-AHEAD,
77
IFMEASURED TO THE LEFT. - MATT LEHAR, 8/5/02
77 If the angle is greater than 90' or less than -90',
// the sun is striking the back of the facade.
// the facade is in shadow.
Effectively,
77 While I discuss DEGREES here, all values returned by
77 Azimuth are in RADIANS. Use static method Azimuth.toDegrees()
77 to convert.
193
NEGATIVE
C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec
package illumination;
public class SolarSuite
public
public
public
public
double
double
double
double
solarAngleHorizontal;
solarAngleVertical;
solarIncoming;
diffIntensity;
public SolarSuite( double
solarAngleHorizontal,
ouble solarAngleVertical,
ouble
ouble
{
solarIncoming,
diffIntensity
this.solarAngleHorizontal
this.solarAngleVertical
this.solarIncoming
this.diffIntensity
)
solarAngleHorizontal;
solarAngleVertical;
solarIncoming;
diffIntensity;
}
}
194
C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec
package illumination;
//
ABSTRACT CLASS SURFACE
Conisists of grids of
The basic storage element of this package.
information representing properties across the span of the surface,
including position coordinates,
direction of orientation, and
radiosities for each differential area of the surface.
public abstract class Surface
Name of the surface.
public String
name;
This will depend on
Category in which the surface is classed.
the particular subclass of "Surface. java" that was called in
the creation of this surface.
public String
surfaceType;
Resolution in the <B>principalK/B> dimension of the surface.
of the surface's two dimensions
principal dimension is first
as they appear in the following list:<BR>
The
<BR>
1. Depth<BR>
2. HeightKBR>
3. Width
public int
a;
Resolution in the <B>second</B> dimension of the surface.
The
second dimension is second of the surface's two dimensions
as they appear in the following list:<BR>
<BR>
1. Depth<BR>
2. HeightKBR>
3. Width
public int
b;
195
C:\Documents and Settings\Administrator\Desktop\Project
public double
Latest\Essential Projec
emissivity;
Magnitude of the distance across the
surface in the direction of "a."
*/
public double
parallelDistance;
Magnitude of the distance across the
surface in the direction of "b."
*7
public double
crossDistance;
Position of the surface in the dimension normal to the
surface. For example, a floor would have
constantCoordinate = 0, whereas a ceiling would have
constantCoordinate = (height of the room).
*/
public double
7/
constantCoordinate;
GRID VALUES---------------------------------------
"x" (depth) is measured from the window surface in the
direction of the back wall.
*7
public double
x[][];
"y" (height) is measured from the floor in the direction of
the ceiling.
*7
public double
y[][];
"z" (width) is measured from sideWalll in the direction of
sideWall2. That is, from the left to the right as you look
towards the window from inside the room.
*/
public double
z[][];
"alpha," "beta," and "gamma" take values of either 1 or 0. A
value of 1 for alpha, beta or gamma indicates that the normal
to the surface is oriented in the x, y, or z directions,
respectively. A value of 0 indicates that the normal vector
has no component in the corresponding direction.
*/
public double
alpha[][],
beta[][],
gamma[][;
Array of differential areas of each element that makes up the
surface.
196
C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec
*7
public double
A[][];
"Q initial" is the surface radiosity array that records the
initial radiosity of the surface, after the surface has been
initialized by illuminating it with sunlight, but before the
iterations (reflections) have begun.
*/
public double
Q-initial[][];
"Q" is the surface radiosity array that updates as the
iterations proceed.
*7
public double
Q[][];
"H" is the array of values of the intensity of light that is
reflected from a surface.
*/
public double
H[][];
private Bilinear bilinearGrid;
private boolean bilinearInstantiated;
// OBSOLETE VARIABLES
resolutions = new int[3];
public int[]
public boolean thirdIsConstant;
Defines surface variables and allocates space for the surface's data arrays.
*/
public void constructSurface(
String name,
int parallelResolution,
int crossResolution,
double parallelMagnitude,
double crossMagnitude,
double emissivity,
double constantCoordinate
this.name
= name;
this.emissivity = emissivity;
a
parallelResolution;
b
crossResolution;
this.parallelDistance
= parallelMagnitude;
this.crossDistance
= crossMagnitude;
this.constantCoordinate = constantCoordinate;
x
= new double[a][b];
y
= new double[a][b];
z
= new double[a][b];
197
)
C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec
alpha
beta
gamma
new double[a][b];
new double[a] [b];
new double[a][b];
A
new double[a][b];
Q
Q-initial
H
new double[a][b];
= new double[a][b];
= new double[a] [b];
bilinearInstantiated = false;
//System. out. println( name +" parallel magnitude: " +parallelMagnitude
// ARRAY FORMATTING METHODS ----------------public void setHArrayTo( double H initial
for ( int il
for
0; il
K a; il++
-------
--------------
)
( int i2 = 0; i2 < b; i2±+ )
H[il][i2] = H initial;
Updates "Q" based on light reflected from another surface.
public void setQ()
for ( int i =0; i
for ( int j
< a; i++ )
0; j
< b; j++ )
Q[i] [j] = Q_initial [i] [j] + Hil [j]
//if ( name.equals( "sideWalll"
//System. out. println( "Q0] [4]:
*
)
"
+Q[0] [4]
Puts a new array of radiosities in place of the existing Q and
Q initial arrays.
*/
public void substituteQValues( double[][]
for ( int i =0; i
< a; i++ )
198
qSizedArray
)
( 1
-
emissivity )
C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec
for ( int j = 0; j
< b; j++ )
Q initial[i][i] = qSizedArray[i][i];
Q[i][j] = qSizedArray[i][j];
}
}
}
7*
Pointwise-adds or pointwise-subtracts an input array from
the surface's radiosity grid.
private void addQValues(
I
for ( int i
double[][]
0; i
String operation
)
< a; i++ )
for ( int j
if
qSizedArray,
0; j
< b; j++ )
( operation.equals( "+" ))
{
Q[i][j] =
Q[i][j] + qSizedArray[i][i];
}
else if ( operation.equals(
Q[i][j] = Q[i][j] - qSizedArray[i][j];
else
I
System.out.println(
"Invalid operator passed to addQValues:
only permissible operators are \"+\" and \"\"."
}
}
}
}
// Unit conversion methods ------------------private double degToRad( double angleInDegrees
return ( Math.
PI/180 )*angleInDegrees;
}
private double radToDeg( double angleInRadians
{
return ( 180/Math. PI )*angle InRadians;
}
//
//
Methods included for backwards-compatibility with obsolete versions of the software
199
C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec
public int getSurfaceDimension(
String dimension
if ( dimension.equals( "a" ))
return a;
}
else if ( dimension.equals( "b" ))
return b;
}
else if ( dimension.equals( "width2D"
))
if ( thirdIsConstant )
return a;
else {
return b;
}
else if ( dimension.equals( "height2D"
{
if ( thirdIsConstant ){
return b;
else {
return a;
))
I
else if
( dimension.equals( "thirdIsConstant"
))
{
if ( thirdIsConstant
return 1;
else I
return 0;
)
}
else { return 0; }
}
public int getSurfaceNewResolution(
String dimension,
int new a, newb;
if ( resolutions[O] ==0
)
newa = newResj;
new b = newResk;
}
else if ( resolutions[L]
0
newa = newResi;
newb = newResk;
else
newa
newb
newResi;
newRes-j;
200
int newRes-i,
int newResj,
int newRes_k )
C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec
}
if ( dimension. equals( "width2D"
))
if ( thirdIsConstant )
return new-a;
} else {
return newb;
else if
( dimension. equals( "height2D" ))
if ( thirdIsConstant )
return newb;
else {
return new a;
else
{ return 0;
Accomodates different resolutions in the two surfaces involved in the exchange.
<BR>
<BR>
Ups resolution of input surface to the level of the replaced surface.
Follows pattern of "Map. addRadiositiesFrom".
public void replaceSurface(
if
( smoothing.
Surface replacementSurface,
equals(
"bilinear"
)
String smoothing )
!sameResolution(
replacementSurface )
bilinearGrid = new Bilinear( replacementSurface.Q,
a,
b );
if ( smoothing.equals( "bilinear" ))
substituteQValues(
else {
substituteQValues(
bilinearGrid. bilinearInterpolate();
bilinearGrid. getUnsmoothedArrayo)
bilinearInstantiated = true;
else
substituteQValues( bilinearGrid. getUnsmoothedArray(
replacementSurface.Q ));
201
C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec
public void addRadiositiesFrom( Surface addedSurface,
if
( smoothing. equals( "bilinear" )
String operation,
String smoothing
!sameResolution( addedSurface
))
( smoothing.equals( "bilinear" )
&& !bilinearInstantiated )
!resolutionOfExistingSurfaceEquals(
addedSurface
//System.out.println( "USING A..." );
bilinearGrid = new Bilinear( addedSurface.Q,
if ( smoothing.equals( "bilinear"
a, b
)
)
))
addQValues( bilinearGrid. bilinearInterpolate(,
operation );
} else
addQValues ( bilinearGrid. getUnsmoothedArray(),
operation );
bilinearInstantiated = true;
else
addQValues( bilinearGrid. getUnsmoothedArray( addedSurface.Q ),
operation
private boolean sameResolution( Surface newSurface
if
)
( bilinearInstantiated )
( newSurface.a
return
bilinearGrid.
getResolutionOfExistinglnputGrida()
bilinearGrid.
getResolutionOfExistinglnputGridb 0);
&& newSurface.b
else
return
alse;
public void clearBilinearGrid(
if ( bilinearInstantiated
)
bilinearGrid = null;
bilinearInstantiated = false;
202
C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec
I//class
package illumination;
// CLASS SURFACEINITIALIZER
public abstract class SurfaceInitializer
// Variables transferred from room
currentSurface;
public Surface
public String
name;
public int
public int
public double
public double
a
b;
crossDistance;
parallelDistance;
public double
solarIncoming;
diffIntensity;
verticalAngle;
horizontalAngle;
emissivity;
public
public
public
public
double
double
double
double
public double
public double
public double
sill, head, left, right;
blockl
block2
=
=
0;
0;
// Variables specific to the initialization process
// 1. Sunlight variables:
angle0nSurface;
public double
public double[]
nearAndFarDistances
public int[]
indecesOfNearAndFarReacha,
ndeces0fNearAndFarReach_b;
public int
Starting, jEnding;
public int
illIndex;
public int
eadIndex;
public double
bliqueIntensityFraction;
// 2. Blind variables:
public int
public double[]
public int[]
public double
public double
public double[][]
= new double[2];
otalNumber0fBlinds;
lindStartEndDistances
lindStartEndIndeces
lindWidth;
lindSpacing;
lindViewFactorSum;
203
= new double[2];
= new int[2];
C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec
//public double[][]
public double[]
public double[]
public double
blindViewFactorAverage;
lightBandOnFloorStartEndDistances_one;
lightBandOnFloorStartEndDistances_two;
lightFractionPassingThroughBlinds;
// 3. Templates:
public double[]
public double[]
rowTemplate;
columnTemplate;
ViewFactory
//BlindSet
oneViewFactory
blinds;
//
ABSTRACT METHODS -----
new ViewFactory();;
------------------------------
-----
public abstract void initialize( Surface currentSurface,
WindowSuite windowSpecs,
BlindSet blinds,
String blindShadingScheme,
boolean isFirstInitialization,
ViewFactorSuite blindFactors_lD,
SolarSuite solarVars );
public abstract void calculateFirstReflectionFromBlinds( BlindSet blinds,
boolean isFirstInitialization,
ViewFactorSuite blindFactors lD,
Surface currentSurface );
public abstract void imposeBlindSlatShadows(
BlindSet blinds );
public abstract void applyPatchOfSunlight( String blindShadingScheme
)
public abstract double findAngleOnSurface( double verticalAngle,
double horizontalAngle );
Defines variables that are surface-specific, and therefore not
covered by "constructSurfaceInitializerInAbstract."
Also
initializes surface radiosity arrays to zero.
*/
public void initializeSurfaceVariables( Surface
BlindSet
WindowSuite
SolarSuite
this.solarIncoming
this.diffIntensity
this.verticalAngle
this.horizontalAngle
sill
head
currentSurface,
blinds,
windowSpecs,
solarVars
solarVars.solarIncoming;
solarVars.diffIntensity;
solarVars.solarAngleVertical;
solarVars.solarAngleHorizontal;
= windowSpecs.sillHeight;
= windowSpecs.headHeight;
204
)
C:\Documents and Settings\Administrator\Desktop\Project
Latest\Essential Projec
// modified over Flemish telephone
if (! currentSurface.name.equals("window"))
= windowSpecs.headHeight - shadowLength(
head
windowSpecs.overhangDepth,
(90-verticalAngle) ); }
if
( head < sill
sill; }
head
left
right
windowSpecs.leftMargin;
windowSpecs.rightMargin;
totalNumberOfBlinds
blindWidth
blindSpacing
blinds. getNumBlinds();
blinds. getBlindWidthO
blinds.getBlindSpacing();
lightBandOnFloorStartEndDistancesone = new double[2];
lightBandOnFloorStartEndDistances two = new double[2];
=
=
=
=
=
=
=
this.currentSurface
name
this.emissivity
a
b
crossDistance
parallelDistance
blindViewFactorSum
currentSurface;
currentSurface.name;
currentSurface.emissivity;
currentSurface.a;
currentSurface.b;
currentSurface.crossDistance;
currentSurface.parallelDistance;
new double[a][totalNumberOfBlinds];
if ( totalNumberOfBlinds ==
0
lightFractionPassingThroughBlinds = 1;
else
calculateLightFractionPassingThroughBlinds( blinds
for ( int i = 0; i < a; i++ )
I
for ( int blindNumber = 1; blindNumber
)
<= totalNumber0fBlinds;
blindNumber++
blindViewFactorSum[i][blindNumber - 1] = 0;
}
}
for ( int i = 0; i
< a; i++ )
for ( int j
0; j
< b; j++ )
currentSurface.Qinitial[i][j] = 0;
currentSurface.Q[i][j] = 0;
205
)
C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec
For use by low-resolution Map objects: calculates the dimming
factor to be applied to sunlight on interior surfaces, so that
a sunlit area broken up by blinds can be displayed as a solid
region of a uniform, but lower, equivalent brightness.
*/
private void calculateLightFractionPassingThroughBlinds( BlindSet blinds
lightBandOnFloorStartEndDistancesone
findNearAndFarDistances(
blinds. getEquivalentDistance(
blinds. getEquivalentDistance(
verticalAngle );
lightBandOnFloorStartEndDistancestwo
verticalAngle,
verticalAngle,
"start"
"end" ),
2, verticalAngle,
2, verticalAngle,
"start" ),
"end" ),
(
1
lightBandOnFloorStartEndDistances_one [1]
lightBandOnFloorStartEndDistancesone[0] ) /
( lightBand0nFloorStartEndDistances_two[0] lightBand0nFloorStartEndDistancesone [0] );
if
( lightBand0nFloorStartEndDistances one[l] >
lightBand0nFloorStartEndDistances two[0]
lightFractionPassingThroughBlinds
if
0;
( Math. abs( blinds. getCollectiveAngle(
- verticalAngle ) < 1
lightFractionPassingThroughBlinds > 1
lightFractionPassingThroughBlinds
1;
else {}
rowTemplate
columnTemplate
these arrays serve as masks: when pointwise-multiplied
by the radiosity arrays of a surface, they introduce
black (zero-valued) bands where the shadow of a
blind slat crosses that surface.
*/
206
),
findNearAndFarDistances(
blinds. getEquivalentDistance(
blinds. getEquivalentDistance(
verticalAngle );
lightFractionPassingThroughBlinds
1,
1,
)
C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec
public void initializeMasks()
rowTe{plate
columnTemplate
new doubleEb];
= new double[a];
for ( int i = 0; i
< a; i++)
columnTemplate[i] = 1;
}
for ( int i =0; i
< b; i++ )
rowTemplate[i] = 1;
Applies brightness to selected elements of the surface grid,
according to a calculation of which parts of the surface would
be reached by the sunlight.
*/
public void illuminateWithSunlight(
String blindShadingScheme,
double obliqueIntensityFraction
indecesOfNearAndFarReacha = findlndeces0fNearAndFarReach(
nearAndFarDistances, a, parallelDistance );
if
( nearAndFarDistances[0] < parallelDistance )
angleOnSurface = findAngleOnSurface(
verticalAngle,
horizontalAngle );
silllndex = findColumnlndexInRow( "starting", angleOnSurface,
indecesOfNearAndFarReach a[0],
blockl, block2, crossDistance
headIndex = findColumnlndexInRow( "ending", angleOnSurface,
indeces0fNearAndFarReach a[0],
blockl, block2, crossDistance
if
( silllndex == -1)
sillIndex = 0;
if ( headlndex ==b )
headIndex = b - 1;
for ( int i = indecesOfNearAndFarReacha[0]; i <=
indecesOfNearAndFarReach-a[l]; i++
jStarting = findColumnIndexInRow( "starting",
207
)
C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec
angleOnSurface, i,
jEnding = findColumnIndexInRow(
if (( iStarting == -1
blocki, block2,
crossDistance )
"ending",
angleOnSurface, i,
blocki, block2,
crossDistance )
&&jEnding == -1 ) II
( jStarting
b && jEnding
b ))
else
if ( iStarting == -1
)
jStarting = 0;
else if ( jStarting ==b
jStarting
)
b - 1;
else
{}
if ( jEnding == -1 )
jEnding = 0;
else if ( jEnding == b
jEnding = b - 1;
else
{}
for
( int j
if
jStarting; j
<= jEnding; j++ )
( blindShadingScheme.equals( "focused"))
currentSurface.Q initial[i][j]
solarIncoming
* obliqueIntensityFraction
* ( 1 - emissivity )
* rowTemplate[ j ( jEnding headIndex )]
* columnTemplate[i];
else
currentSurface.Qinitial[i][j]
solarIncoming
208
C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec
* obliqueIntensityFraction
* ( 1 - emissivity )
* lightFractionPassingThroughBlinds;
}
currentSurface.Q[i][j] =
currentSurface.Q initial[i][i];
}
}
}
}
}
Returns a 2-element array containing the near and far extent,
in the surface's <B>principalK/B> direction, of the patch of
sunlight projected from the window upon the walls or floor.
public double[]
findNearAndFarDistances(
double nearAndFarDistances[]
if ( sunAngle
!=
double sillHeight,
= new double[2];
0 && surfacelsIlluminated(
nearAndFarDistances[0
nearAndFarDistances[l]
double headHeight,
double sunAngle
name,
sunAngle ))
shadowLength( sillHeight, sunAngle )
= shadowLength(
headHeight,
if ( nearAndFarDistances[0] > parallelDistance
sunAngle );
)
/* assigns a value that will fail the
test in initializeQandJArrays().
Incident solar energy on surface
will be initialized to 0. */
nearAndFarDistances[0] = parallelDistance + 1;
if
nearAndFarDistances[l] > parallelDistance
nearAndFarDistances[1]
= parallelDistance;
else
nearAndFarDistances[0]
parallelDistance + 1;
nearAndFarDistances[l] = parallelDistance;
}
return nearAndFarDistances;
}
private double
shadowLength( double perpendicularDistance,
double sunAngle )
return ( perpendicularDistance / Math.abs( Math. tan( degToRad(sunAngle))));
209
C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec
Returns a 2-element array containing the indeces of the
elements on the surface grid corresponding to the near and far
extent, in the surface's <B>principal</B> direction, of the
projection of sunlight.
public int[] findlndecesOfNearAndFarReach(
double[] nearAndFarDistances,
int resolutionInDirectionOfReach,
double totalDistance
)
double returnValue_D;
int indecesOfNearAndFarReach[] = new int[2];
returnValueD = nearAndFarDistances[0]
indecesOfNearAndFarReach[O]
/ totalDistance *
resolutionlnDirectionOfReach;
= new Double( Math. floor( returnValueD )).
intValue ()
returnValueD = nearAndFarDistances[1]
/ totalDistance *
resolutionInDirectionOfReach;
/* the ceiling value of (returnValue__D
- 1) is taken instead of the floor
of returnValue_D, in case
returnValueD is a whole number. */
indecesOfNearAndFarReach[l] = new Double( Math. ceil( returnValueD - 1 )).
intValue (
return indecesOfNearAndFarReach;
Returns an index corresponding to the near or far extent, in
the surface' s <B>secondary(/B> direction, and within a
particular row of elements specified by "presentIndex,"
patch of sunlight on a surface.
*/
public int findColumnlndexInRow( String which,
double angleOnSurface,
int presentIndex,
double sillHeight,
double headHeight,
double totalHeight )
double presentIndex D
double aresolution D
double b resolutionD
of the
= new Integer( presentIndex ).doubleValueo;
= new Double( a ). doubleValue();
= new Double( b ). doubleValue()
double returnValue_D;
int indexValue;
210
C:\Documents and Settings\Administrator\Desktop\Project
Latest\Essential Projec
(((( presentIndexD + 0.5 ) / a-resolutionD )
returnVa lue D
* parallelDistance )
* Math.abs( Math.tan( degToRad( angleOnSurface ))));
if ( whi ch.equals( "starting" ))
if ( angleOnSurface > 0 )
indexValue
{
=
} else
indexValue
else if
{
new Double( Math.floor(
( sillHeight + returnValueD )
/ crossDistance * b_resolutionD ))
intValue()
new Double( Math.floor(
( sillHeight - returnValueD )
/ crossDistance * bresolutionD ))
intValueO
( which.equals( "ending" ))
if ( angleOnSurface > 0 )
{
indexValue
( - 1
) - new Double( Math. floor(
((totalHeight - headHeight )
-
returnValueD
)
/ crossDistance * bresolution D )
).intValue();
} else I
indexValue
}
}
else I indexValue
if ( indexValue >
indexValue
if ( indexValue
(b - 1 )
0;
1))
(b
b;
<0 )
indexValue
-1
return indexValue;
}
//
Unit conversion methods -------------------
public double degToRad( double angleInDegrees )
211
-
new Double( Math.floor(
(( totalHeight - headHeight )
+ returnValueD )
/ crossDistance * bresolution D )
).intValueO;
C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec
{
return ( Math.PI/180 )*angleInDegrees;
}
public double radToDeg( double angleInRadians
{
return ( 180/Math.PI )*angleInRadians;
}
private boolean surfaceIsIlluminated( String name,
if ( name. equals( "floor" )
if ( sunAngle > 0
double sunAngle
)
name. equals( "workplane" )
name.equals( "sideWall2"
))
)
return true;
else {
return false;
else if
( name.equals( "ceiling" )
if ( sunAngle
name. equals( "sideWalll"
))
<0 )
return true;
else {
return false;
else if
{
( name.equals( "window" ))
return true;
}
else
{ return false;
public double lineOfSightFlag( int cl,
int c2, int blindNumber,
BlindSet blinds,
double sunAngle
double angle = angleToBlind( cl, c2, blindNumber, blinds );
// TEST WHETHER ILLUMINATED SIDE IS EXPOSED TO VIEW (return 0 if not)if ( angle > blinds.getCollectiveAngle()
&& blinds.findIlluminatedSide( sunAngle ).equals( "top"
))
return 0;
else if ( angle < blinds.getCollectiveAngleo
&&blinds. findIlluminatedSide( sunAngle ).equals( "bottom"
{
return 0;
212
))
C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec
} else {}
/* TEST FOR FIRST OR LAST BLIND (no obstructions from below or above,
respectively) ----------------------------------------------if (( angle >= 0 && blindNumber == 1
( angle < 0 &&blindNumber == blinds. getNumBlindso
))
return 1;
//
if
TEST FOR OBSTRUCTIONS FROM BELOW OR ABOVE -----------------------( angle >= 0 &&blinds.getEquivalentDistance(( blindNumber - 1 ),
angle, "end"
< blinds.getVerticalPosition( blindNumber ))
{
return 1;
}
else if ( angle
<
),
0 && blinds.getEquivalentDistaice(( blindNumber + 1
angle, "start"
> blinds.getVerticalPosition( blindNumber ))
f
return 1;
else {
return 0;
//
"z" does not come into it.
private double angleToBlind(
{
int cl,
int c2,
int blindNumber, BlindSet blinds )
double yBlind = blinds.getVerticalPosition( blindNumber );
return radToDeg( Math.acos( currentSurface.x[cl][c2] / Math.pow(
( Math.pow( currentSurface.x[cl][c2], 2 )
+ Math.pow(( yBlind - currentSurface.y[cl][c2] ), 2 )),
* ( yBlind - currentSurface.y[cl][c2] )
/ Math.abs( yBlind - currentSurface.y[cl][c2] ));
public double findObliqueIntensityFraction(
return Math.abs( Math.sin(
double angle
degToRad( angle )));
}
}
213
)
0.5
))
C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec
package illumination;
public class ViewFactorSuite
public double[][][][] surfaceToSurfacePairings;
public double[][] surfaceToBlindPairingslD;
public double[][][] surfaceToBlindPairings_2D;
public ViewFactorSuite( int first a, int firstb, int second_a,
int secondb )
surfaceToSurfacePairings = new double[first a] [f irst b] [second-a] [second b];
public ViewFactorSuite()
public void makeBlindFactors lD( int first-a, int numberOfBlinds )
surfaceToBlindPairingslD = new double[first-a] [numberOfBlinds];
public void makeBlindFactors2D(
int firsta, int firstb,
int numberOfBlinds
surfaceToBlindPairings_2D = new double [firsta] [f irst b] [numberOfBlinds];
}
214
Latest\Essential Projec
C:\Documents and Settings\Administrator\Desktop\Project
package illumination;
public class ViewFactory
public ViewFactory()
double
double
double
double
double
double
double
double
double
double
double
double
double
public double computeViewFactor(
return Math.abs(( alphal *
*
( alpha2
alphal,
betal,
gammal,
alpha2,
beta2,
gamma2,
xl,
x2,
yl,
y2,
zl,
z2,
A2
)
( x1 -
x2 ) + betal
yI - y2) + gammal
Zl z2 ))
*
*
*
( x - x2 ) + beta2
( y- y2 ) + gamma2
( l z2 )) * A2
/ ( Math.pow( computeRVector( xl, x2, yl, y2, zl, z2 ), 2 )
* MathPI ));
Computes the SQUARE of the R-vector
private double computeRVector( double xl, double x2, double yl, double y2,
double zl, double z2
return Math.pow((xl - x2),
2) + Math.pow((yl
- y2),
)
2)
+ Math.pow((zl - z2), 2);
215
C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec
/* -------------------------------------------------------- */
public double computeViewFactorWithBlinds(
Surface thisSurface, int cl, int c2,
int blindNumber, BlindSet blinds,
double sunAngle )
int oneIfIlluminatedSideUp;
if
( blinds. findllluminatedSide( sunAngle ).equals( "top" ))
onelfIlluminatedSideUp = 1;
else if ( blinds. findIlluminatedSide(
sunAngle ).equals( "bottom"
))
oneIfllluminatedSideUp = -1;
}
else
onelfIlluminatedSideUp = 0;
if ((Math. sin( degToRad( blinds. getCollectiveAngle())
* ( thisSurface.x[cl][c2] - 0 )
+ Math. cos( degToRad( blinds. getCollectiveAngle())
* ( thisSurface.y[cl][c2] - blinds.
getVerticalPosition( blindNumber
* onelfIlluminatedSideUp
)))
<0 )
return 0;
return computeViewFactor (
Math.sin( degToRad( blinds. getCollectiveAngle()),
Math.cos( degToRad( blinds. getCollectiveAngle 0)),
0,
thisSurface. alpha[ci] [c2],
thisSurface. beta[cl] [c2],
thisSurface. gamma[ci] [c2],
0,
thisSurface. x[cl] [c2],
blinds.getVerticalPosition( blindNumber
thisSurface. y[cl] [c2],
),
blinds. centerInZ(,
thisSurface. z[ci] [c2],
thisSurface. A[ci] [c2]
216
)
C:\Documents and Settings\Administrator\Desktop\Project
private double degToRad( double angleInDegrees
return ( Math.PI/180 )*angleInDegrees;
private double radToDeg( double angleInRadians
return ( 180/Math.PI )*angleInRadians;
217
Latest\Essential Projec
C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec
package illumination;
public class Wall
{
private double width;
private double height;
//private int pixelWidth;
//private int pixelHeight;
public int[][] shade;
public Wall (int[][] shade, double width, double height)
{
this.shade
shade;
this.width
width;
this.height
height;
/*
public Wall (int[][] shade)
{
this.shade = shade;
this.width = shade.length;
this.height = shade[O].length;
}
public int getShade (double x, double y)
{
int xTile = (int) ((x/width) * shade.length);
int yTile = (int) ((y/height) * shade[0].length);
{ xTile--; }
shade.length)
shade[O].length) { yTile---;
//System.out.println("x:" + x + " xTile:" + xTile);
if (xTile
if (yTile
//
System.out.println("y:" + y + " yTile:" + yTile);
return shade[xTile][yTile];
}
private int
I
int xTile
int yTile
if (xTile
if (yTile
getShade (int[][] surface, double x,
= (int) (x * surface. length);
= (int) (y * surface[]. length);
surface. length) { xTile--; }
==surface.length) {yTile-;
218
double y)
C:\Documents and Settings\Administrator\Desktop\Project
return surface[xTile][yTile];
public static void main (String[] args)
I
int a = 4;
int b = 1;
System.out. println (b/a);
double c = b/a;
System.out. println (c);
}
}
219
Latest\Essential Projec
C:\Documents and Settings\Administrator\Desktop\Project
Latest\Essential Projec
package illumination;
//import java.util.*;
//import java.lang.*;
import java.io.*;
public class WeatherDataReader
double latitude;
double[][] dirNormRad = new double[12][24];
double[][] diffHorRad = new double[12][24];
double[][] dryBulbTemp = new double[12][24];
public double getLatitudeo
{
return latitude;
I
public double getDirectNormalRadiation(int month, int hour0fDay)
{
return dirNormRad[month][hourOfDay];
public double getDiffuseHorizontalRadiation(int month,
int hourofDay)
return diffHorRad[month][hour0fDay];
}
public double getDryBulbTemperature(int month,
f
return dryBulbTemp[month][hourOfDay];
}
int hour0fDay)
/* A few sample lines from the weather file
263
Los Angeles
-8 N 33 56 W 118 11 10
95010101000000000000?40000?40000?40000140000I40000I49999?001E701E70118E70062E7068E71012E729
3E7011E79999?099999?099999999?0014E7999?0999?099?0
95010102000000000000?40000?40000?40000140000I40000I49999?001E701E70118E70062E7068E71012E729
3E7008E79999?099999?099999999?0014E7999?0999?099?0
95010103000000000000?40000?40000?40000140000I40000I49999?001E701E70114E70062E7070E71012E729
3E7007E79999?099999?099999999?0014E7999?0999?099?0
95010104000000000000?40000?40000?40000I40000I40000I49999?001E701E70113E70062E7071E71012E729
3E7008E79999?099999?099999999?0014E7999?0999?099?0
220
C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec
95010105000000000000?40000?40000?40000I40000140000I49999?001E701E70111E70062E7072E71012E729
3E7008E79999?099999?099999999?0014E7999?0999?099?0
95010106000000000000?40000?40000?40000I40000I40000149999?001E701E70113E70062E7071E71012E729
3E7009E79999?099999?099999999?0014E7999?0999?099?0
95010107000000000000?40000?40000?40000140000I40000149999?001E701E70109E70062E7072E71012E729
3E7007E79999?099999?099999999?0014E7999?0999?099?0
95010108141201240060?40208?40042?40061I40051I40057149999?001E701E70121E70063E7067E71012E729
3E7011E79999?099999?099999999?0014E7999?0999?099?0
95010109141203660156?40192?40107?40166140128I40133I49999?006E703E70137E70064E7061E71012E729
3E7011E79999?099999?099999999?0015E7999?0999?099?0
95010110141205610262?40209?40179?40287140194I40210I49999?006E703E70150E70065E7056E71012E729
3E7029E79999?099999?099999999?0015E7999?0999?099?0
95010111141206980431?40534?40167?40463140489140221149999?003E701E70157E70066E7055E71012E729
3E7031E79999?099999?099999999?0015E7999?0999?099?0
95010112141207660407?40298?40245?40438I40269140292149999?005E703E70170E70067E7050E71012E729
3E7034E79999?099999?099999999?0015E7999?0999?099?0
//
//
//
//
//
//
//
//
//
//
//
//
//
**
**
**
**
**
**
**
**
**
**
**
**
**
Ok, supposedly there were some speed issues with this calculation
code. It used to perform individual calculations for every hour
of every day of the year. To cut down on the number of calculations,
this was reduced to performing one calc for:
Every hour of one representative day for each month.
All weather data is still read in, however it is averaged on the
fly and only 24 values are stored per month.
(i.e. we read in a
month of data, take the weather values at lam Jan 1, lam Jan 2,
etc up to lam Jan 30- average those values, and store the result
in January, lam. We then do this for 2am, 3am, 4am etc. Then
we move on to Feb and repeat.
public void read (String filename)
throws IOException
{
// open the weather data file
BufferedReader br = new BufferedReader (new FileReader(filename));
// parse unique first line
String data = br.readLineo;
7/ ** NOTE: the following are unused by this code, and so I've
7/
nixed reading them in:
//
7/ lstm (hours behind GMT, I believe)
7/ longitude (degrees and minutes)
/7 eastV (direction of longitude)
7/ lstm = (Double. valueOf(firstLine. substring(32, 36))). doubleValueo;
/7 eastV = firstLine. substring( 45, 46);
7/ longitudD = (Double. valueOf(firstLine. substring(47, 50))). doubleValue()
221
C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec
/7 longitudM
7/ latitude
(Double. value0f (firstLine. substring(51,
here is in degrees North is +, South is
53))). doubleValue(
-
String latitudeDirection = data. substring(37, 38);
double latitudeDegrees
= (Double. value0f (data. substring (39,
double latitudeMinutes
= (Double. value0f (data. substring (42,
latitude = latitudeDegrees + (latitudeMinutes
if (! latitudeDirection. equals ("N"))
latitude *= -1; }
41))). doubleValue (
44))). doubleValue 0
/ 60. 0)
int month, day, hour; // loop counters
// arrays to store information to be averaged over each month
double[] dnr = new double[24];
double[] dhr = new double[24];
double[] dbt = new double[24];
for (month
0; month
< 12; month++)
/7 beginning of a new month, initialise monthly values to 0
for (hour = 0; hour < 24; hour++)
dnr[hour]
0;
dhr[hour] = 0;
dbt[hour] = 0;
}
for (day = 0; day
< 30; day++)
for (hour = 0; hour
< 24; hour++)
data = br. readLine()
7/DryBulbTemp
values are expressed in Celcius in the file,
/7 taking the form 0146. This means 14.6 degrees Celcius.
7/DirectNormalRadiation and DiffuseNormalRadiation values
7/are read in as 4 digit numbers (no decimal point)
/7 the leading digit is usually a 0, and both values
/7 drop to 0 at night (predictably).
ux
dnr[hour] += (Double. valueOf(data. substring(41, 45))). doubleValue() * 100;
//23, 27))).doubleValue(;
dhr[hour] += (Double. value0f (data. substring(47, 51))). doubleValue( * 100;
//29, 33))). doubleValue (;
dbt[hour] += (Double. valueOf(data. substring(67, 71))).doubleValue( / 10;
222
/7 1
C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec
}
77 CHANGED BY MATT LEHAR, 8/5/02:
7/ end of a month, calculate and store values
for (hour = 0; hour < 24; hour++)
{
dirNormRad [month][hour] += dnr[hour]/30;
diffHorRad [month][hour] += dhr[hour]/30;
dryBulbTemp[month][hour] += dht[hour]/30;
}
}
br.
}
close();
four letters in that string
/7 Given a string, returns the first
7/ Case is maintained. If less than four letters exist, less are returned.
7/ e.g. Los Angeles -> LosA
-- > NY
NY
//
7/
Brussels
-- > Brus
public static String removeSpaces(String city)
{
char[] s = new char[4];
int j = 0;
char c;
for (int i = 0; i
< city. length() ; i++)
{
c = city.charAt(i);
if ((c >= 'a' && c <= 'z')
I s[j++] = c; }
(c >= 'A'
&&c <= 'Z'))
if (j >= 4)
i = city.lengtho; }
return new String(s, 0,
}
j);
}
223
C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec
package illumination;
public class WindowSuite{
public
public
public
public
public
double
double
double
double
double
sillHeight;
headHeight;
leftMargin;
rightMargin;
overhangDepth;
public WindowSuite( double
double
double
double
double
this.sillHeight
this.headHeight
this.leftMargin
this.rightMargin
this.overhangDepth
sillHeight,
headHeight,
leftMargin,
rightMargin,
overhangDepth
= sillHeight;
= headHeight;
= leftMargin;
= rightMargin;
= overhangDepth;
}
I
224
C:\Documents and Settings\Administrator\Desktop\Project
Latest\Essential Projec
package illumination;
public class WorkplaneBay
private final double
private final double
INCANDESCENTLIGHTEFFICIENCY = 0.0189;
FLUORESCENTLIGHTEFFICIENCY = 0.135;
private Initializer
private Iterator
private double
oneInitializer;
onelterator;
minLightLevel;
Map
room,
iteratedRoom,
rapidFineRoom;
public
public WorkplaneBay( SettingSuite
SettingSuite
Initializer
coarseSettings,
fineSettings,
oneInitializer,
onelterator,
workplaneHeight,
minLightLevel
)
Iterator
double
double
{
this.oneInitializer
this.oneIterator
this.minLightLevel
//
1.
= oneInitializer;
= onelterator;
= minLightLevel;
Create instance of Map object ("room").
room
iteratedRoom
new Map( coarseSettings );
new Map( coarseSettings )
// 2. Create rapidFineRoom, a lower--resolution version of fineRoom
rapidFineRoom
= new Map( fineSettings );
225
C:\Documents and Settings\Administrator\Desktop\Project
Latest\Essential Projec
/* 3. Create both high- and low-resolution workplanes at the resolutions of
the high- and low-res floor surfaces */
rapidFineRoom.createWorkplanes( workplaneHeight,
room.getFloorResolutiona(,
room.getFloorResolutionbo,
rapidFineRoom.getFloorResolution_ao,
rapidFineRoom.getFloorResolution bO
);
}
CALCULATEWORKPLANELIGHTLEVELS()
*/
public void calculateWorkplaneLightLevels(
SolarSuite solarVars,
WindowSuite windowSpecs,
double collectiveBlindAngle
)
7/ Initialize
"hiResWorkplane."
(Essential for re-zero-ing the workplane)
onelnitializer.initializeHiResWorkplane( rapidFineRoom,
windowSpecs,
"focused",
collectiveBlindAngle,
solarVars
)
/* Cast reflections from room onto low-res workplane NOTE: the reason why
the high- and low-res workplanes are both housed in the same hi-res
room is that if the two workplanes were in different rooms, it
would be harder to reflect the hi-res light onto the low-res
workplane */
onelterator. showReflectionsOnLowResWorkplane ( rapidFineRoom
)
rapidFineRoom.hiResWorkplane.addRadiositiesFrom(
// Add only reflections to hi- res workplane
rapidFineRoom.lowResWorkplane,
"n+
none
}
public double sumDefecitValues()
double defecit;
double total = 0;
for ( int i = 0; i
< rapidFineRoom.hiResWorkplane.a; i++ )
f
for ( int j = 0; j < rapidFineRoom.hiResWorkplane.b; j++)
{
defecit
( minLightLevel rapidFineRoom.hiResWorkplane.Q[i][j] /
( 1 rapidFineRoom.hiResWorkplane.emissivity ));
total += (( defecit > 0 ) ? defecit : 0
total
/= ( rapidFineRoom. hiResWorkplane. a
226
)
* rapidFineRoom.
C:\Documents and Settings\Administrator\Desktop\Project
Latest\Essential Projec
hiResWorkplane.b );
return ( total / FLUORESCENT LIGHTEFFICIENCY ); // units of W/m"2
// or INCANDESCENTLIGHTEFFICIENCY );
package illumination;
public class WorkplaneInitializer extends PlatformInitializer
All arguments to oneWorkplaneInitializer must be from the same room object, except
for blindShadingScheme.
public void initialize( Surface workplane,
WindowSuite windowSpecs,
BlindSet blinds,
String blindShadingScheme,
boolean isFirstWorkplaneInitialization,
ViewFactorSuite blindFactors_lD,
SolarSuite solarVars
)
t
This method, contained in the superclass, reads address of input
Surface "workplane" into "currentSurface"
initializeSurfaceVariables( workplane,
blinds,
windowSpecs,
solarVars );
calculateFirstReflectionFromBlinds(
blinds,
isFirstWorkplaneInitialization,
blindFactors lD,
currentSurface );
imposeBlindSlatShadows( blinds );
applyPatchOfSunlight( blindShadingScheme
227
)
C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec
}
public double obstructionFactor( int i,
return
int
j, BlindSet blinds, int blindNumber,
ViewFactorSuite blindFactors )
( 1 - emissivity )
* lineOfSightFlag( i, j, blindNumber, blinds, verticalAngle )
* blindFactors. surfaceToBlindPairings lD[i] [blindNumber - 1]
* blindSlatAboveLevelOfWorkplaneFlag( blinds, blindNumber );
Prevents light reflected off the top surface of blinds that
are BELOW the workplane from illuminating the workplane FROM
BENEATH.
private double blindSlatAboveLevelOfWorkplaneFlag(
BlindSet blinds,
int blindNumber )
if ( blinds.findllluminatedSide( verticalAngle ).equals( "top"
{
return 0;
}
else
return 1;
))
public void imposeBlindSlatShadows( BlindSet blinds )
double startingEquivalentDistance;
double endingEquivalentDistance;
initializeMaskso;
for
( int blindNumber = 1; blindNumber <= totalNumberOfBlinds;
blindNumber++
find indeces that mark the beginnings and endings
of blind shadows in the parallel direction along
the workplane.
This is different from the floor/ceiling case
only in the sense that a certain distance must
be subtracted from the "equivalentDistance" of
the starting or ending points of the blinds
across the surface of the window in the
vertical direction.
228
)
C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec
startingEquivalentDistance
= b linds.getEquivalentDistance(
blindNumber,
verticalAngle,
"start" )
- currentSurface.
constantCoordinate;
endingEquivalentDistance
= b linds.getEquivalentDistance(
blindNumber,
verticalAngle,
"end" )
- currentSurface.
constantCoordinate;
if ( endingEquivalentDistance > 0 )
I
if ( startingEquivalentDistance
<
0
)
0
0;
startingEquivalentDistance =
I
blindStartEndIndeces = findlndecesOfNearAndFarReach(
findNearAndFarDistances(
startingEquivalentDistance,
endingEquivalentDistance,
verticalAngle ),
a, parallelDistance )
create black spaces in the parallel (column) mask that
correspond to the positions of the blind shadows
for ( int i = blindStartEndIndeces[0]; i
<= blindStartEndIndeces[l]; i++
columnTemplate[i] = 0;
I
}
}
}
public void applyPatchOfSunlight( String blindShadingScheme
)
double normalizedSill;
double normalizedHead;
"sill" and "head" determine the limits in the DEPTH dimension
of the patch of sunlight projected onto the floor/ceiling
from the window
229
)
C:\Documents and Settings\Administrator\Desktop\Project Latest\Essential Projec
"blockl" and "block2" are here defined as the side margins of
the window area, and limit the patch of sunlight on the floor/
ceiling in the WIDTH dimension
As in the case of "imposeBlindSlatShadowso," above,
to make the standard shadowing algorthithms work for
an elevated workplane, the sill and head heights must
be adjusted by an amount equal to the distance between
the workplane and the floor.
normalizedSill
sill
normalizedHead = hea
if
-
currentSurface. constantCoordinate;
currentSurface.constantCoordinate;
( normalizedHead > 0 )
if ( normalizedSill K 0
)
normalizedSill
0;
nearAndFarDistances = findNearAndFarDistances(
normalizedSill,
normalizedHead,
verticalAngle );
blockl = right;
block2 = left;
obliquelntensityFraction = find0bliqueIntensityFraction(
verticalAngle );
illuminateWithSunlight( blindShadingScheme,
obliquelntensityFraction
}
230
)
Download