Assumptions and FAQ
This page summarizes important assumptions, simplifications, default values, and common questions for users of VITAL.
The details below are provided to help users interpret screening-level results and understand where additional engineering review may be needed.
General Scope
What is VITAL intended to do?
VITAL is intended to support early-stage assessment of tidal turbine systems integrated with vessels or floating platforms. It combines tidal resource processing, rotor performance data, rotor dynamic simulation, vessel loading, constraint checking, cost estimation, and LCOE calculation.
The tool is designed for comparative analysis and screening studies. It is not a substitute for detailed engineering design, certification, environmental review, or site-specific permitting analysis.
What applications are currently represented?
The software includes cost configuration support for:
Battery charging applications.
Grid connection applications.
However, some application-specific models are simplified and should be reviewed before use in decision-critical studies.
What global physical constants are used?
The following global physical constants are defined in constGlobal.py:
Quantity |
Symbol / variable |
Default value |
|---|---|---|
Seawater density |
|
|
Atmospheric pressure |
|
|
Seawater vapor pressure at 25 deg C |
|
|
Gravitational acceleration |
|
|
These constants are used in hydrodynamic force calculations, cavitation checks, and flow-related calculations.
Tidal Data
Where does tidal data come from?
The module_tidal workflow attempts to retrieve tidal current predictions from NOAA APIs. If NOAA access fails and a local fallback file is supplied, the workflow can use local tidal data instead.
The high-level function is:
process_tidal_data(
station,
startdate,
range_hrs=2 * 7 * 24,
time_step_s=3600,
city_data_file="../data/AlaskaCityLatLong.txt",
local_file=None,
fallback_metadata=None,
)
What are the default tidal-data processing values?
The following defaults are used by process_tidal_data and module_tidal.py:
Quantity |
Variable |
Default value |
|---|---|---|
Time range |
|
|
Interpolated time step |
|
|
City data file |
|
|
Minimum flow speed floor |
|
|
Default mooring distance |
|
|
Earth radius for distance calculations |
|
|
The NOAA request internally extends the requested range by 2 hours before interpolation. For example, if range_hrs = 336, the NOAA request uses 338 hours. This helps provide enough data for interpolation at the end of the requested interval.
What units are used for tidal speed?
NOAA current prediction speeds are converted internally from cm/s to m/s using:
Local fallback files should provide speed directly in m/s.
Why are flow speeds made nonnegative?
The current implementation uses the magnitude of flow speed by applying an absolute value:
self.flow_speeds_m_s = np.abs(self.flow_speeds_m_s)
This means flow reversal direction is not explicitly modeled. The rotor simulation treats the input as a speed magnitude rather than a signed vector velocity.
Is there a minimum flow speed?
Yes. A small minimum speed floor is applied to avoid numerical issues in interpolation and rotor dynamics calculations:
This value is defined as MIN_FLOW_SPEED = 1e-4 in module_tidal.py.
How is mooring distance determined?
For most NOAA stations, the code attempts to retrieve deployment depth information. If depth is unavailable, a default mooring distance is used:
For older station IDs beginning with PCT, the code uses station metadata and applies the same default mooring distance of 50.0 m.
If NOAA reports depth in feet, the code converts it to meters using:
How is cable length estimated?
Cable length is estimated as the great-circle distance between the tidal station/buoy location and the nearest city in the provided city metadata file.
The calculation uses:
This is a simplified estimate and does not represent actual cable routing, bathymetry, landfall constraints, permitting constraints, installation feasibility, or final engineering design.
What local fallback data format is expected?
If NOAA data are unavailable, a local fallback file can be supplied. The local file must be whitespace-delimited and contain at least the following columns:
Column |
Meaning |
Units |
|---|---|---|
|
Time |
seconds |
|
Flow speed |
m/s |
Example:
t U
0 0.85
3600 1.10
7200 0.95
10800 0.40
When using a local fallback file, fallback_metadata must include:
station_namelatitude_deglongitude_degmooring_distance_m
Optional metadata fields are:
nearest_citycable_length_m
If city_data_file is provided, the code attempts to compute nearest city and cable length from the fallback latitude and longitude.
Rotor Data
What rotor data columns are required?
The rotor performance data file must contain the following columns:
TSRCtCq
The power coefficient is computed internally as:
What happens to negative rotor coefficients?
The rotor data are processed using the following physical sign constraints:
self.cq = np.maximum(self.cq, 0.0)
self.ct = np.maximum(self.ct, 0.0)
self.cpmin = np.minimum(self.cpmin, 0.0)
self.cp = np.maximum(self.cp, 0.0)
Thus:
Cqis clipped to be nonnegative.Ctis clipped to be nonnegative.Cpis clipped to be nonnegative.Cpminis clipped to be nonpositive.
How are rotor coefficients interpolated?
The code uses monotonic PCHIP interpolation for Cq and Ct through scipy.interpolate.PchipInterpolator.
Outside the provided TSR range, the implementation applies simplified behavior:
Below the minimum TSR,
CqandCtare held at the first measured value.Above the maximum TSR,
CqandCtdecay exponentially toward zero.
This low-TSR behavior avoids forcing Cq or Ct to zero at TSR = 0. That assumption can be incorrect for drag-based turbines, where torque and thrust coefficients may be nonzero or even large at low TSR.
For the above-range exponential decay, the decay scale is based on the maximum TSR in the supplied rotor data:
Because the power coefficient is computed as:
Cp still approaches zero as TSR approaches zero, even if Cq is held nonzero below the measured TSR range.
The extrapolated values should not be interpreted as validated rotor performance. Users should provide rotor data over the expected operating TSR range whenever possible.
What happens if Cpmin data is not provided?
If no Cpmin file is provided, the code assumes:
across the TSR range.
This affects the cavitation constraint and should be replaced with rotor-specific minimum pressure coefficient data when available.
Rotor Simulation
What dynamics are modeled?
The rotor simulation models generator-side angular speed using a drivetrain dynamic equation with effective inertia, friction, hydrodynamic torque, and generator torque.
The effective inertia is calculated as:
where:
J_ris rotor inertia.J_dis drivetrain inertia.N_gis gear ratio.
The default controller uses an optimal torque law intended to track the optimal tip-speed ratio.
What inputs are required in the rotor simulation configuration?
The RotorSimulation class expects the configuration dictionary to include, at minimum:
RadiusPratedTrateddHubdMoorUinftCpFuncCqFuncCtFuncCpOptTSROptTSRmaxNgJ_dB_dJ_r
For the simple electrical power model, the configuration must also include:
KtRw
What validation is performed in rotor simulation?
The rotor simulation checks several basic conditions:
Check |
Requirement |
|---|---|
Gear ratio |
|
Rotor radius |
|
Time vector |
|
Optimal TSR |
|
What power conversion model is used by default?
The default power conversion model is:
power_model = "simple"
This model requires generator constants Kt and Rw.
What power conversion models are supported?
The rotor simulation supports the following power-conversion options:
|
Description |
|---|---|
|
Built-in generator electrical model using |
|
Built-in generator electrical model plus user-supplied power-electronics loss model. |
|
User-supplied generator loss model. No power-electronics loss model is applied. |
|
User-supplied generator loss model and user-supplied power-electronics loss model. |
For user-supplied generator or power-electronics loss models, the functions are assumed to use generator-side angular speed and generator torque:
omega_g = self.wtau_g = self.Tg
What numerical solver is used?
Rotor dynamics are solved using scipy.integrate.solve_ivp with:
method = "Radau"
The Radau method is an implicit method suitable for stiff systems.
What happens if rated torque is exceeded?
The simulation first solves closed-loop dynamics. If the generator torque exceeds the rated torque, the torque is clipped at:
The dynamics are then re-solved in open-loop mode using the clipped torque trajectory.
What is Pelec?
For compatibility with downstream code, Pelec is the primary electrical output used by the LCOE and constraint calculations.
In simple and simple_with_pe_loss modes, Pelec comes from the built-in generator electrical model. In these modes, Pac is calculated as nonnegative AC-side electrical power.
In generator_loss_model and generator_and_pe_loss_models modes, Pelec is treated as AC-side power and is equal to Pac.
If power-electronics losses are included, battery-side power is available separately as Pbat.
For battery-charging studies, users should verify whether Pelec, Pac, or Pbat is the appropriate power signal for their intended analysis. The current LCOE workflow uses Pelec for annual energy calculations.
Flow-at-Depth Model
How is flow adjusted for turbine depth?
The simulation uses a simplified vertical profile correction through the flowAtDepth method. This estimates an adjusted flow speed at the rotor location based on hub depth, rotor radius, and mooring depth.
The method uses an internal average-flow scaling:
and then estimates an equivalent velocity based on a depth-dependent power calculation.
This model is a simplification and does not fully resolve site-specific bathymetry, turbulence, shear, wave-current interaction, or three-dimensional flow effects.
Constraint Checking
What constraints are checked?
The ConstraintChecker evaluates:
Power constraint.
Rotor submergence/depth constraint.
Cavitation constraint.
Vessel pitch stability constraint.
What numerical tolerances are used in constraint checks?
The power constraint uses a small tolerance of 1e-9:
Pelec >= -1e-9
Prated - Pelec >= -1e-9
The other constraints use strict positivity:
depth_constraint() > 0
cavitation_constraint() > 0
pitch_constraint() > 0
How is the power constraint interpreted?
The electrical power must be nonnegative and must not exceed rated turbine power:
In the implementation, this is checked with the 1e-9 numerical tolerance described above.
How is the depth constraint interpreted?
The depth constraint requires:
This means the top of the rotor must remain below the water surface.
How is cavitation checked?
The cavitation check estimates minimum blade pressure using the supplied or default minimum pressure coefficient.
The effective velocity is estimated as:
The pressure at the rotor tip is estimated using:
The cavitation constraint is implemented as:
and must satisfy:
The default values used in this calculation are:
Quantity |
Variable |
Default value |
|---|---|---|
Seawater density |
|
|
Atmospheric pressure |
|
|
Vapor pressure |
|
|
Gravitational acceleration |
|
|
Default |
|
|
The cavitation model depends strongly on the quality of the Cpmin data.
How is pitch stability checked?
Pitch stability is checked using a simplified moment balance involving vessel drag, turbine thrust, turbine hub depth, mooring angle, vessel geometry, and pitch hydrostatic stiffness.
The code computes vessel drag as:
and turbine thrust as:
The total horizontal load used in the pitch check is:
The pitch constraint margin is implemented as:
where:
Kphiis the pitch hydrostatic stiffness.phiis the representative pitch angle.dHubis the hub depth.Xmis the horizontal force-application distance.Zmis the vertical force-application distance.theta_mis the mooring line angle.
The constraint must satisfy:
This check is intended as a screening-level constraint and should not replace detailed vessel stability analysis.
Vessel Model
What vessel properties are required for user-defined vessels?
For user-defined vessels, the following keys are expected in vessel_properties:
XmZmKphithetaphiareaCd
If any of these are missing, VesselData will raise an error.
What default vessel properties are used?
If the vessel is not user-defined, the following default vessel properties are used:
Quantity |
Variable |
Default value |
|---|---|---|
Vessel height |
|
|
Vessel density |
|
|
Mooring line angle |
|
|
Aspect ratio |
|
|
Drag coefficient |
|
|
Pitch angle |
|
|
Submerged height |
|
|
Cross-sectional area |
|
|
Some vessel attributes, such as Xm, Zm, Kphi, and VesselVolume, are not assigned by the default vessel model. These should be supplied explicitly for analyses that require them.
How is vessel drag calculated?
Vessel drag is calculated as:
where:
rho = 1025.0 kg/m^3by default.Cdis the vessel drag coefficient.Ais the vessel cross-sectional area.Uis the adjusted flow speed.
For the default vessel model:
and:
LCOE Calculation
What does the LCOE calculation include?
The LCOE calculation includes:
CAPEX from the configured cost functions.
OPEX as a fraction of CAPEX.
Annual energy production estimated from simulated electrical power.
Discounted project lifetime.
The result is reported in USD/kWh.
What power signal is used for annual energy in LCOE?
The current LCOE workflow calculates annual energy from Pelec.
For battery-charging studies with power-electronics losses, Pbat may be a more appropriate delivered-energy metric. Users should review whether Pelec or Pbat is appropriate for their analysis.
What LCOE defaults are used by the optimizer?
When using LCOEOptimizer.optimize without overriding defaults, the following values are used:
Quantity |
Variable |
Default value |
|---|---|---|
Customer |
|
|
Application |
|
|
Battery capacity |
|
|
Project lifetime |
|
|
Discount rate |
|
|
Turbulence intensity |
|
|
These defaults are optimizer defaults only. If users instantiate LCOEData directly, these values must be provided explicitly.
How is annual energy calculated?
The code integrates the simulated power time series to estimate average power, then scales it to annual energy using:
Annual energy is reported in kWh.
Does the capacity factor include all turbines?
The annual energy calculation multiplies instantaneous power by the number of turbines:
instantaneous_power = Pelec / ((1 + turbulence_intensity) ** 3) * number_of_turbines
Users should ensure that rated power and turbine count are interpreted consistently when comparing capacity factor or system-level power.
How is turbulence intensity used?
The LCOE calculation adjusts instantaneous power by dividing by:
where TI is the turbulence intensity input.
The optimizer default is:
This is a simplified correction and should be reviewed for the intended application.
How is OPEX calculated?
The current active implementation calculates OPEX as:
That is, annual OPEX is assumed to be 4% of total CAPEX.
A SITKANA-specific operating cost function exists in the code, but the currently active calculate_total_opex method uses the 4% of CAPEX approximation for all customers.
What CAPEX adjustment factors are applied?
After component CAPEX values are summed, an adjustment factor is applied.
Customer |
Adjustment factor |
|---|---|
|
|
Other customers, including |
|
What happens if battery capacity is missing?
For grid_connection applications, battery capacity is internally set to zero.
For non-grid applications, such as battery_charging, battery capacity must be provided and must be greater than zero.
If battery capacity is missing or nonpositive for a non-grid application, the code raises an error.
Cost Models
Are the cost models general?
No. The cost models are configuration-dependent and include customer/application-specific assumptions. Users should review module_cost_config.py and module_cost_calculations.py before applying results to a new use case.
What cost model configurations are included?
The cost configuration includes two customer keys:
customer_Acustomer_B
Each customer has:
rotor_and_drivetraincost components.applicationscost components forgrid_connectionand/orbattery_charging.
What battery cost is currently used for SITKANA-style battery charging?
The battery cost function calculate_battery_cost_SITKANA uses:
Thus, the assumed battery cost is:
What currency conversion is used?
The following conversion is defined in constUnitConvert.py:
Costs based on kEuro values are converted using:
Are permitting costs included?
No. Permitting costs are not currently included in the LCOE calculation.
See the permitting information page for a qualitative list of agencies and considerations.
Optimization
What optimization method is used?
The current LCOEOptimizer performs an explicit grid search over user-specified parameter values.
Although older code used scipy.optimize.brute, the current implementation explicitly constructs the grid and evaluates each point.
What defaults are used by the optimizer?
The optimizer defaults are:
Quantity |
Variable |
Default value |
|---|---|---|
Customer |
|
|
Application |
|
|
Battery capacity |
|
|
Lifetime |
|
|
Discount rate |
|
|
Turbulence intensity |
|
|
What happens when a design violates constraints?
If a design violates any checked constraint, it is assigned a penalty LCOE value of:
This value is used numerically to exclude infeasible designs from the feasible design table. It is not a physical cost estimate.
Why did optimization fail to find a feasible design?
Common reasons include:
Hub depth too shallow relative to rotor radius.
Rated power too low for simulated electrical power.
Cavitation constraint violation.
Pitch stability violation.
Missing or inconsistent turbine configuration parameters.
Missing vessel properties.
Battery capacity not provided for battery-charging applications.
Search bounds too narrow.
Grid step sizes too coarse.
How are variable bounds interpreted?
The optimizer expects variable_bounds to map variable names to tuples of:
(minimum, maximum, step)
The grid values are generated using:
np.arange(low, high + 0.5 * step, step)
This means the upper bound is usually included if it falls on the step spacing.
Numerical and Software Notes
Does the software validate every physical input?
No. Some validation is included, but users are responsible for providing physically meaningful inputs, consistent units, and appropriate parameter ranges.
What unit system is used?
The software primarily uses SI units:
Quantity |
Unit |
|---|---|
Length |
m |
Time |
s |
Mass |
kg |
Force |
N |
Torque |
N m |
Power |
W |
Energy |
kWh for annual energy and battery capacity |
Cost |
USD |
What useful unit conversions are defined?
The following common unit conversions are defined in constUnitConvert.py:
Conversion |
Variable |
Value |
|---|---|---|
Seconds to days |
|
|
Miles to meters |
|
|
Meters to kilometers |
|
|
Watts to megawatts |
|
|
Watts to kilowatts |
|
|
Kilo-euros to euros |
|
|
Newtons to metric tons |
|
|
Newtons to kilonewtons |
|
|
Euros to dollars |
|
|
Feet to meters |
|
|
cm/s to m/s |
|
|
rad/s to rpm |
|
|
Cubic meters to cubic centimeters |
|
|
Hours to days |
|
|
What should users check before trusting results?
Users should verify:
Rotor performance data quality.
Cpmin/cavitation data quality.
Tidal data source and representativeness.
Hub depth and mooring depth consistency.
Vessel geometry and pitch-stiffness assumptions.
Cost model applicability.
Battery or grid-connection assumptions.
Whether power should be evaluated as
Pelec,Pac, orPbatfor the intended use case.Whether the default values listed on this page are appropriate for the intended site and design.