Adding a New Cost Calculation Method in SINDBAD
This documentation provides a framework for adding new cost calculation methods while maintaining consistency with SINDBAD's existing architecture.
For a more detailed view of available cost methods and their purposes, use:
using Sindbad
showMethodsOf(CostMethod)
This will display a formatted list of all cost methods and their descriptions.
Overview
SINDBAD uses a type-based dispatch system for cost calculation methods. To add a new cost calculation method, you need to:
Define a new type in
src/Types/OptimizationTypes.jl
Implement the cost calculation function in
cost.jl
Update the cost preparation in
prepOpti.jl
if needed
Step 1: Define the New Cost Method Type
In src/Types/OptimizationTypes.jl
, add a new struct that subtypes CostMethod
:
struct YourNewCostMethod <: CostMethod end
For example, the existing cost methods are (but can change, use showMethodsOf(CostMethod)
for current implementations):
CostModelObs
: Basic cost calculation between model and observationsCostModelObsMT
: Multi-threaded version ofCostModelObs
CostModelObsPriors
: Cost calculation including prior informationCostModelObsLandTS
: Cost calculation for land time series
Step 2: Implement the Cost Calculation Function
In cost.jl
, implement your cost calculation function with the following signature:
function cost(parameter_vector, default_values, selected_models, space_forcing, space_spinup_forcing,
loc_forcing_t, output_array, space_output, space_land, tem_info, observations,
parameter_updater, cost_options, multi_constraint_method, parameter_scaling_type,
::YourNewCostMethod)
# Your implementation here
end
The function should:
Update model parameters using
updateModels
Run the model simulation
Calculate the cost using
metricVector
andcombineMetric
Example implementation structure:
function cost(parameter_vector, _, selected_models, space_forcing, space_spinup_forcing,
loc_forcing_t, output_array, space_output, space_land, tem_info, observations,
parameter_updater, cost_options, multi_constraint_method, parameter_scaling_type,
::YourNewCostMethod)
# Update models with new parameters
updated_models = updateModels(parameter_vector, parameter_updater, parameter_scaling_type, selected_models)
# Run the model simulation
runTEM!(updated_models, space_forcing, space_spinup_forcing, loc_forcing_t, space_output, space_land, tem_info)
# Calculate cost vector
cost_vector = metricVector(output_array, observations, cost_options)
# Combine costs using specified method
cost_metric = combineMetric(cost_vector, multi_constraint_method)
return cost_metric
end
Step 3: Update Cost Preparation (if needed)
If your new cost method requires special preparation, update prepOpti.jl
:
function prepOpti(forcing, observations, info, ::YourNewCostMethod)
# Get base helpers
opti_helpers = prepOpti(forcing, observations, info, CostModelObs())
# Add your custom preparation here
return opti_helpers
end
Example: Adding a Weighted Cost Method
Here's a complete example of adding a new weighted cost method:
- In
src/Types/OptimizationTypes.jl
:
struct CostModelObsWeighted <: CostMethod end
- In
cost.jl
:
function cost(parameter_vector, _, selected_models, space_forcing, space_spinup_forcing,
loc_forcing_t, output_array, space_output, space_land, tem_info, observations,
parameter_updater, cost_options, multi_constraint_method, parameter_scaling_type,
::CostModelObsWeighted)
# Update models
updated_models = updateModels(parameter_vector, parameter_updater, parameter_scaling_type, selected_models)
# Run simulation
runTEM!(updated_models, space_forcing, space_spinup_forcing, loc_forcing_t, space_output, space_land, tem_info)
# Calculate weighted cost vector
cost_vector = metricVector(output_array, observations, cost_options)
# Apply custom weights
weights = getWeights(cost_options) # getWeights is a hypothetical function, you would need to implement such function
weighted_cost = cost_vector .* weights
# Combine costs
cost_metric = combineMetric(weighted_cost, multi_constraint_method)
return cost_metric
end
Important Considerations
Parameter Scaling: Ensure your method properly handles parameter scaling using
parameter_scaling_type
.Multi-threading: If your method can benefit from parallelization, consider implementing a multi-threaded version like
CostModelObsMT
.Cost Options: Your method should respect the
cost_options
configuration, which includes:
Cost metrics
Spatial and temporal aggregation
Minimum data points
Weights
Performance: For large-scale optimizations, consider implementing efficient memory management and parallelization.
Documentation: Add comprehensive docstrings explaining:
The purpose of your cost method
Required parameters
Return values
Any special considerations
Testing
After implementing your new cost method:
Test with small parameter sets first
Verify the cost calculation matches expected values
Check performance with larger parameter sets
Ensure compatibility with different optimization algorithms