Skip to content

Commit

Permalink
Merge pull request #158 from WISDEM/release-v2.3.2
Browse files Browse the repository at this point in the history
Release v2.3.2
  • Loading branch information
akey7 authored Aug 18, 2020
2 parents 0e1e1f8 + a601003 commit 458333f
Show file tree
Hide file tree
Showing 7 changed files with 63 additions and 52 deletions.
5 changes: 2 additions & 3 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,9 @@ python:

# command to install dependencies
install:
- pip install pandas==0.25.2
- pip install pandas
- pip install numpy
- pip install sympy
- pip install shapely
- pip install scipy
- pip install xlsxwriter
- pip install xlrd
- pip install psycopg2-binary
Expand Down
4 changes: 2 additions & 2 deletions installation_instructions/macos_developer.md
Original file line number Diff line number Diff line change
Expand Up @@ -131,8 +131,8 @@ The file named `projects_list.xlsx` must keep the same name. The names of the pr
Suppose that you have created the directory structure on your desktop as mentioned above in step 2 "Create a folder structure". You can set the environment variables and execute LandBOSSE with a couple easy commands:

```
cd ~/Desktop/landbosse
LANDBOSSE_INPUT_DIR=~/Desktop/landbosse/input LANDBOSSE_OUTPUT_DIR=~/Desktop/landbosse/output python LandBOSSE/main.py
cd ~/Desktop/landbosse/LandBOSSE
python main.py -i ~/Desktop/landbosse/input -o ~/Desktop/landbosse/output
```

The file will be produced with a filename like:
Expand Down
2 changes: 1 addition & 1 deletion landbosse/excelio/XlsxReader.py
Original file line number Diff line number Diff line change
Expand Up @@ -592,7 +592,7 @@ def apply_cost_and_scaling_modifications_to_project_parameters(self, project_par

number_of_access_roads = 0.0 if project_size_MW <= 20 else ceil(0.0052 * project_size_MW + 0.7917)
number_of_highway_permits = ceil(0.2 * project_parameters['Number of turbines'])
if flag_use_user_homerun is 1:
if flag_use_user_homerun == 1:
project_parameters['Combined Homerun Trench Length to Substation (km)'] = 0.1776 * project_size_MW - 2.551

# 10 deliveries per week for 1.5 MW machines
Expand Down
40 changes: 36 additions & 4 deletions landbosse/model/ErectionCost.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
import pandas as pd
import numpy as np
from shapely.geometry import Point
from shapely.geometry.polygon import Polygon
from math import ceil

from .CostModule import CostModule
Expand All @@ -15,6 +13,40 @@
m_per_ft = 0.3048


class Point(object):
def __init__(self, x, y):
if type(x) == type(pd.Series()):
self.x = float(x.values[0])
self.y = float(y.values[0])
elif type(x) == type(np.array([])):
self.x = float(x[0])
self.y = float(y[0])
elif type(x) == type(int(0)):
self.x = float(x)
self.y = float(y)
elif type(x) == type(float(0.0)):
self.x = x
self.y = y
else:
raise ValueError(type(x))

def ccw(A,B,C):
return (C.y-A.y) * (B.x-A.x) > (B.y-A.y) * (C.x-A.x)

# Return true if line segments AB and CD intersect
def intersect(A,B,C,D):
return ccw(A,C,D) != ccw(B,C,D) and ccw(A,B,C) != ccw(A,B,D)

def point_in_polygon(pt, poly):
result = False
maxx = float(np.r_[pt.x, np.array([m.x for m in poly])].max())
for i in range(len(poly)-1):
if intersect(poly[i], poly[i+1], pt, Point(1.1*maxx, pt.y)):
result = not result
if intersect(poly[-1], poly[0], pt, Point(1.1*maxx, pt.y)):
result = not result
return result

class ErectionCost(CostModule):
"""
ErectionCost.py
Expand Down Expand Up @@ -643,7 +675,7 @@ def calculate_crane_lift_polygons(self, crane_grouped):
setup_time = max(crane['Setup time hr'])
breakdown_time = max(crane['Breakdown time hr'])
crew_type = crane.loc[0, 'Crew type ID'] # For every crane/boom combo the crew is the same, so we can just take first crew.
polygon = Polygon([(0, 0), (0, max(y)), (min(x), max(y)), (max(x), min(y)), (max(x), 0)])
polygon = [Point(0, 0), Point(0, max(y)), Point(min(x), max(y)), Point(max(x), min(y)), Point(max(x), 0)]
df = pd.DataFrame([[equipment_name,
equipment_id,
crane_name,
Expand Down Expand Up @@ -726,7 +758,7 @@ def calculate_component_lift_max_wind_speed(self, *, component_group, crane_poly
point = Point(component_only['Mass tonne'] / 2, (component_only['Section height m'] + component_only['Offload hook height m']))
else:
point = Point(component_only['Mass tonne'], (component_only['Lift height m'] + component_only['Offload hook height m']))
crane['Lift boolean {component}'.format(component=component)] = polygon.contains(point)
crane['Lift boolean {component}'.format(component=component)] = point_in_polygon(point, polygon)

# Transform the "Lift boolean" indexes in the series to a list of booleans
# that signify if the crane can lift a component.
Expand Down
58 changes: 20 additions & 38 deletions landbosse/model/FoundationCost.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,7 @@
import pandas as pd
import numpy as np
import math
from sympy.solvers import solve
from sympy import Symbol
from scipy.optimize import root_scalar

from .WeatherDelay import WeatherDelay as WD
from .CostModule import CostModule
Expand Down Expand Up @@ -343,41 +342,30 @@ def calculate_foundation_load(self, foundation_load_input_data, foundation_load_
if (r_test_gapping / 3) < e:
r_gapping = 0
else:
r_g = Symbol('r_g', real=True, positive=True)
foundation_vol = np.pi * r_g ** 2 * foundation_load_input_data['depth']
v_1 = (foundation_vol * (vol_fraction_fill * unit_weight_fill + vol_fraction_concrete * unit_weight_concrete) + f_dead)
e = m_tot / v_1
r_gapping = solve(e * 3 - r_g, r_g)
if len(r_gapping) > 0:
r_gapping = max(r_gapping)
else:
r_gapping = 0
def r_g(x):
foundation_vol = np.pi * x** 2 * foundation_load_input_data['depth']
v_1 = (foundation_vol * (vol_fraction_fill * unit_weight_fill + vol_fraction_concrete * unit_weight_concrete) + f_dead)
e = m_tot / v_1
return (e * 3 - x)
result = root_scalar(r_g, method='brentq', bracket=[0.9*r_overturn, 50], xtol=1e-4, maxiter=50)
r_gapping = result.root
if not result.converged:
raise ValueError(f'Warning {self.project_name} calculate_foundation_load r_gapping solve failed, {result.flag}')

r_test_bearing = max(r_test_gapping, r_gapping)

# calculate foundation radius based on bearing pressure
def r_b(x):
foundation_vol = np.pi * r_test_bearing ** 2 * foundation_load_input_data['depth']
v_1 = (foundation_vol * (vol_fraction_fill * unit_weight_fill + vol_fraction_concrete * unit_weight_concrete) + f_dead)
e = m_tot / v_1
a_eff = v_1 / bearing_pressure
return (2 * (x ** 2 - e * (x ** 2 - e ** 2) ** 0.5) - a_eff)
result = root_scalar(r_b, method='brentq', bracket=[0.9*r_overturn, 50], xtol=1e-10, maxiter=50)
r_bearing = result.root

# Restrict r_b to only real numbers. Positive solutions for r_b are
# selected below
r_b = Symbol('r_b', real=True)

foundation_vol = np.pi * r_test_bearing ** 2 * foundation_load_input_data['depth']
v_1 = (foundation_vol * (vol_fraction_fill * unit_weight_fill + vol_fraction_concrete * unit_weight_concrete) + f_dead)
e = m_tot / v_1
a_eff = v_1 / bearing_pressure
r_bearing = solve(2 * (r_b ** 2 - e * (r_b ** 2 - e ** 2) ** 0.5) - a_eff, r_b)

# Select only positive solutions to r_b. This is selected by max(). If there are
# not positive solutions to r_b, that means something is wrong with the foundation
# parameters. In that case, generate a warning below.

if len(r_bearing) > 0:
r_bearing = max(r_bearing)
else:
r_bearing = 0

if r_bearing < 0:
raise ValueError(f'Warning {self.project_name} calculate_foundation_load r_bearing is negative, r_bearing={r_bearing}')
if not result.converged:
raise ValueError(f'Warning {self.project_name} calculate_foundation_load r_bearing solve failed, {result.flag}')

# pick the largest foundation radius based on all 4 foundation design criteria: moment, gapping, bearing, slipping
r_choosen = max(r_bearing, r_overturn, r_slipping, r_gapping)
Expand Down Expand Up @@ -778,12 +766,6 @@ def outputs_for_detailed_tab(self, input_dict, output_dict):
'variable_df_key_col_name': 'Radius',
'value': float(self.output_dict['Radius_m'])
})
result.append({
'unit': 'm^3',
'type': 'variable',
'variable_df_key_col_name': 'foundation_volume_concrete_m3_per_turbine',
'value': float(self.output_dict['foundation_volume_concrete_m3_per_turbine'])
})
result.append({
'unit': 'short_ton',
'type': 'variable',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
join_landbosse_output_costs.to_csv("extended_landbosse_costs.csv", index=False)
join_landbosse_output_details.to_csv("extended_landbosse_details.csv", index=False)

load_into_database_enabled = True
load_into_database_enabled = False
if load_into_database_enabled:
print("Load into database...")

Expand Down
4 changes: 1 addition & 3 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,9 @@
test_suite='nose.collector',
tests_require=['nose'],
install_requires=[
'pandas==0.25.2',
'pandas',
'numpy',
'sympy',
'scipy',
'shapely',
'xlsxwriter',
'xlrd',
'psycopg2-binary',
Expand Down

0 comments on commit 458333f

Please sign in to comment.