turash/models/params/params.go
Damir Mukimov 4a2fda96cd
Initial commit: Repository setup with .gitignore, golangci-lint v2.6.0, and code quality checks
- Initialize git repository
- Add comprehensive .gitignore for Go projects
- Install golangci-lint v2.6.0 (latest v2) globally
- Configure .golangci.yml with appropriate linters and formatters
- Fix all formatting issues (gofmt)
- Fix all errcheck issues (unchecked errors)
- Adjust complexity threshold for validation functions
- All checks passing: build, test, vet, lint
2025-11-01 07:36:22 +01:00

348 lines
17 KiB
Go

package params
import (
"encoding/json"
"fmt"
"strconv"
"gopkg.in/yaml.v3"
)
// Params holds all parameters for the mathematical model.
// All values are normalized to per-year units.
type Params struct {
Time TimeParams `json:"time" yaml:"time"`
Adoption AdoptionParams `json:"adoption" yaml:"adoption"`
Pricing PricingParams `json:"pricing" yaml:"pricing"`
Transactions TransactionParams `json:"transactions" yaml:"transactions"`
Municipal MunicipalParams `json:"municipal" yaml:"municipal"`
ImplServices ImplementationParams `json:"impl_services" yaml:"impl_services"`
Impact ImpactParams `json:"impact" yaml:"impact"`
Costs CostParams `json:"costs" yaml:"costs"`
Market MarketParams `json:"market" yaml:"market"`
UnitEconomics UnitEconomicsParams `json:"unit_economics" yaml:"unit_economics"`
Profitability ProfitabilityParams `json:"profitability" yaml:"profitability"`
Transport TransportParams `json:"transport" yaml:"transport"`
}
// TimeParams defines the time horizon for the model.
type TimeParams struct {
Years []int `json:"years" yaml:"years"` // e.g., [1, 2, 3] for Y1, Y2, Y3
}
// AdoptionParams defines customer adoption parameters per year.
type AdoptionParams struct {
TotalOrgs YearlyInt `json:"total_orgs" yaml:"total_orgs"` // Total organizations onboarded
PayingShare YearlyFloat `json:"paying_share" yaml:"paying_share"` // Percentage that are paying (0.0-1.0)
}
// PricingParams defines subscription pricing tiers and tier mix.
type PricingParams struct {
Basic float64 `json:"basic" yaml:"basic"` // Monthly price for Basic tier (EUR)
Business float64 `json:"business" yaml:"business"` // Monthly price for Business tier (EUR)
Enterprise float64 `json:"enterprise" yaml:"enterprise"` // Monthly price for Enterprise tier (EUR)
BlendedUplift BlendedUplift `json:"blended_uplift" yaml:"blended_uplift"` // Transaction uplift per tier
TierMix YearlyTierMix `json:"tier_mix" yaml:"tier_mix"` // Tier distribution per year
}
// BlendedUplift defines transaction fee uplift for each tier.
type BlendedUplift struct {
Basic float64 `json:"basic" yaml:"basic"` // e.g., 0.20 = 20% uplift
Business float64 `json:"business" yaml:"business"` // e.g., 0.25 = 25% uplift
Enterprise float64 `json:"enterprise" yaml:"enterprise"` // e.g., 0.25 = 25% uplift
}
// TierMix defines the distribution of paying customers across tiers.
type TierMix struct {
Basic float64 `json:"basic" yaml:"basic"` // e.g., 0.54 = 54%
Business float64 `json:"business" yaml:"business"` // e.g., 0.38 = 38%
Enterprise float64 `json:"enterprise" yaml:"enterprise"` // e.g., 0.08 = 8%
}
// TransactionParams defines transaction revenue parameters.
type TransactionParams struct {
AvgIntroFee float64 `json:"avg_intro_fee" yaml:"avg_intro_fee"` // Average fee per introduction (EUR)
IntrosPerYear YearlyInt `json:"intros_per_year" yaml:"intros_per_year"` // Introductions per year
IntroConversion YearlyFloat `json:"intro_conversion" yaml:"intro_conversion"` // Conversion rate (0.0-1.0)
ServiceGMV YearlyFloat `json:"service_gmv" yaml:"service_gmv"` // Service marketplace GMV (EUR)
ServiceCommission float64 `json:"service_commission" yaml:"service_commission"` // Commission rate (0.0-1.0)
GroupGMV YearlyFloat `json:"group_gmv" yaml:"group_gmv"` // Group buying GMV (EUR)
GroupCommission float64 `json:"group_commission" yaml:"group_commission"` // Commission rate (0.0-1.0)
}
// MunicipalParams defines municipal/license revenue parameters.
type MunicipalParams struct {
Cities YearlyInt `json:"cities" yaml:"cities"` // Number of cities with licenses
AvgLicense YearlyFloat `json:"avg_license" yaml:"avg_license"` // Average license fee per city (EUR/year)
DataLicensing YearlyFloat `json:"data_licensing" yaml:"data_licensing"` // Data licensing revenue (EUR/year)
}
// ImplementationParams defines implementation services revenue parameters.
type ImplementationParams struct {
MatchesPerOrg float64 `json:"matches_per_org" yaml:"matches_per_org"` // Average matches per organization
PaidShare float64 `json:"paid_share" yaml:"paid_share"` // Share using paid implementation (0.0-1.0)
AvgFee float64 `json:"avg_fee" yaml:"avg_fee"` // Average implementation fee (EUR)
}
// ImpactParams defines environmental impact calculation parameters.
type ImpactParams struct {
HeatMWh YearlyFloat `json:"heat_mwh" yaml:"heat_mwh"` // Heat recovered (MWh/year)
GridFactor float64 `json:"grid_factor" yaml:"grid_factor"` // Grid emission factor (t CO₂/MWh)
HXEff float64 `json:"hx_eff" yaml:"hx_eff"` // Heat exchanger efficiency (0.0-1.0)
Utilization float64 `json:"utilization" yaml:"utilization"` // Utilization rate (0.0-1.0)
WaterPerOrg float64 `json:"water_per_org" yaml:"water_per_org"` // Water flow per organization (m³/year)
WaterReuseRate YearlyFloat `json:"water_reuse_rate" yaml:"water_reuse_rate"` // Water reuse rate (0.0-1.0)
WastePerOrg float64 `json:"waste_per_org" yaml:"waste_per_org"` // Waste generation per organization (t/year)
WasteDiversionRate YearlyFloat `json:"waste_diversion_rate" yaml:"waste_diversion_rate"` // Waste diversion rate (0.0-1.0)
}
// CostParams defines cost structure parameters.
type CostParams struct {
Engineers YearlyInt `json:"engineers" yaml:"engineers"` // Number of engineers
EngineerSalary float64 `json:"engineer_salary" yaml:"engineer_salary"` // Average engineer salary (EUR/year)
Infrastructure YearlyFloat `json:"infrastructure" yaml:"infrastructure"` // Infrastructure costs (EUR/year)
MarketingSales YearlyFloat `json:"marketing_sales" yaml:"marketing_sales"` // Marketing & sales costs (EUR/year)
Operations YearlyFloat `json:"operations" yaml:"operations"` // Operations costs (EUR/year)
}
// MarketParams defines market size constants for documentation context.
// These represent the problem space, not drivers of calculations.
type MarketParams struct {
TAM float64 `json:"tam" yaml:"tam"` // Total Addressable Market (EUR)
AddressableDigital float64 `json:"addressable_digital" yaml:"addressable_digital"` // Addressable via digital platforms (EUR)
PilotCityEconomicBenefit float64 `json:"pilot_city_economic_benefit" yaml:"pilot_city_economic_benefit"` // Economic benefit per city (EUR/year)
ScalabilityPotential float64 `json:"scalability_potential" yaml:"scalability_potential"` // Scalability potential if replicated (EUR/year)
EUIndustrialFacilities int `json:"eu_industrial_facilities" yaml:"eu_industrial_facilities"` // EU industrial facilities count
EnergyWastePotential float64 `json:"energy_waste_potential" yaml:"energy_waste_potential"` // Energy waste recovery potential (0.0-1.0)
ResourceCostReduction float64 `json:"resource_cost_reduction" yaml:"resource_cost_reduction"` // Resource cost reduction via symbiosis (0.0-1.0)
ViableExchangeRate float64 `json:"viable_exchange_rate" yaml:"viable_exchange_rate"` // Viable exchange rate for SAM calc (0.0-1.0)
PlatformCaptureRate float64 `json:"platform_capture_rate" yaml:"platform_capture_rate"` // Platform capture rate for SAM calc (0.0-1.0)
SOM YearlyFloat `json:"som" yaml:"som"` // Serviceable Obtainable Market per year (EUR)
}
// UnitEconomicsParams defines unit economics and customer lifecycle parameters.
type UnitEconomicsParams struct {
ChurnRates TierRates `json:"churn_rates" yaml:"churn_rates"` // Annual churn rates by tier
RetentionMonths TierRates `json:"retention_months" yaml:"retention_months"` // Average retention periods (months)
TransactionFees TierRates `json:"transaction_fees" yaml:"transaction_fees"` // Additional transaction revenue per tier per year
UpsellRates UpsellRates `json:"upsell_rates" yaml:"upsell_rates"` // Probability of upgrading to next tier
EnterpriseExpansion EnterpriseExpansion `json:"enterprise_expansion" yaml:"enterprise_expansion"` // Multi-site expansion for enterprise
PlatformCosts float64 `json:"platform_costs" yaml:"platform_costs"` // Platform/transaction costs as % of revenue
}
// TierRates represents rates for each tier (basic, business, enterprise).
type TierRates struct {
Basic float64 `json:"basic" yaml:"basic"`
Business float64 `json:"business" yaml:"business"`
Enterprise float64 `json:"enterprise" yaml:"enterprise"`
}
// UpsellRates represents upgrade probabilities between tiers.
type UpsellRates struct {
BasicToBusiness float64 `json:"basic_to_business" yaml:"basic_to_business"`
BusinessToEnterprise float64 `json:"business_to_enterprise" yaml:"business_to_enterprise"`
}
// EnterpriseExpansion represents multi-site expansion for enterprise customers.
type EnterpriseExpansion struct {
MultiSiteRate float64 `json:"multi_site_rate" yaml:"multi_site_rate"` // Percentage of enterprise customers that expand
AdditionalSites float64 `json:"additional_sites" yaml:"additional_sites"` // Average additional sites per customer
SiteRevenue float64 `json:"site_revenue" yaml:"site_revenue"` // Monthly revenue per additional site
}
// ProfitabilityParams defines parameters for profitability analysis.
type ProfitabilityParams struct {
DiscountRate float64 `json:"discount_rate" yaml:"discount_rate"` // Discount rate for NPV calculations (0.0-1.0)
}
// TransportParams defines parameters for transport cost calculations.
type TransportParams struct {
// Heat transport constants
HeatFixedCostPerMeter float64 `json:"heat_fixed_cost_per_meter" yaml:"heat_fixed_cost_per_meter"`
HeatVariableCostPerMeter float64 `json:"heat_variable_cost_per_meter" yaml:"heat_variable_cost_per_meter"`
HeatEnergyCostPerKwh float64 `json:"heat_energy_cost_per_kwh" yaml:"heat_energy_cost_per_kwh"`
HeatLossFactor float64 `json:"heat_loss_factor" yaml:"heat_loss_factor"`
// Water transport constants
WaterBaseCapitalCost float64 `json:"water_base_capital_cost" yaml:"water_base_capital_cost"`
WaterCapitalCostPerKm float64 `json:"water_capital_cost_per_km" yaml:"water_capital_cost_per_km"`
WaterPumpingCostFactor float64 `json:"water_pumping_cost_factor" yaml:"water_pumping_cost_factor"`
WaterDensity float64 `json:"water_density" yaml:"water_density"`
WaterGravity float64 `json:"water_gravity" yaml:"water_gravity"`
WaterPumpHead float64 `json:"water_pump_head" yaml:"water_pump_head"`
WaterPumpEfficiency float64 `json:"water_pump_efficiency" yaml:"water_pump_efficiency"`
// Solids transport constants
SolidsTransportCostPerTonneKm float64 `json:"solids_transport_cost_per_tonne_km" yaml:"solids_transport_cost_per_tonne_km"`
SolidsBaseCapitalCost float64 `json:"solids_base_capital_cost" yaml:"solids_base_capital_cost"`
// Gas transport constants
GasDensity float64 `json:"gas_density" yaml:"gas_density"`
GasCompressionCostPerTonneKm float64 `json:"gas_compression_cost_per_tonne_km" yaml:"gas_compression_cost_per_tonne_km"`
GasPipelineCostPerTonneKm float64 `json:"gas_pipeline_cost_per_tonne_km" yaml:"gas_pipeline_cost_per_tonne_km"`
GasBaseCapitalCost float64 `json:"gas_base_capital_cost" yaml:"gas_base_capital_cost"`
GasCapitalCostPerKm float64 `json:"gas_capital_cost_per_km" yaml:"gas_capital_cost_per_km"`
// General constants
DefaultOperatingHours int `json:"default_operating_hours" yaml:"default_operating_hours"`
}
// YearlyInt is a map from year index (string) to integer value.
type YearlyInt map[string]int
// YearlyFloat is a map from year index (string) to float value.
type YearlyFloat map[string]float64
// UnmarshalYAML implements custom YAML unmarshaling for YearlyFloat
func (yf *YearlyFloat) UnmarshalYAML(unmarshal func(interface{}) error) error {
var raw map[interface{}]interface{}
if err := unmarshal(&raw); err != nil {
return err
}
*yf = make(YearlyFloat)
for k, v := range raw {
key := fmt.Sprintf("%v", k)
switch val := v.(type) {
case int:
(*yf)[key] = float64(val)
case float64:
(*yf)[key] = val
default:
return fmt.Errorf("invalid value type for year %s: %T", key, v)
}
}
return nil
}
// YearlyTierMix is a map from year index (string) to tier mix.
type YearlyTierMix map[string]TierMix
// LoadFromJSON loads parameters from a JSON byte slice.
func LoadFromJSON(data []byte) (*Params, error) {
var p Params
if err := json.Unmarshal(data, &p); err != nil {
return nil, err
}
return &p, nil
}
// LoadFromYAML loads parameters from a YAML byte slice.
func LoadFromYAML(data []byte) (*Params, error) {
var p Params
if err := yaml.Unmarshal(data, &p); err != nil {
return nil, err
}
return &p, nil
}
// GetYearInt returns an integer value for a given year, or 0 if not found.
func (yi YearlyInt) GetYear(year int) int {
return yi[yearKey(year)]
}
// GetYearFloat returns a float value for a given year, or 0.0 if not found.
func (yf YearlyFloat) GetYear(year int) float64 {
return yf[yearKey(year)]
}
// GetYearTierMix returns a tier mix for a given year.
func (ytm YearlyTierMix) GetYear(year int) TierMix {
return ytm[yearKey(year)]
}
// yearKey converts a year index to a string key.
func yearKey(year int) string {
return strconv.Itoa(year)
}
// YearKey is a public version of yearKey for use in tests.
func YearKey(year int) string {
return yearKey(year)
}
// Validate performs basic validation on parameters.
func (p *Params) Validate() error {
// Basic sanity checks
if len(p.Time.Years) == 0 {
return ErrInvalidParams{Field: "time.years", Message: "must have at least one year"}
}
// Check that all years have corresponding values for required fields
for _, year := range p.Time.Years {
// Adoption parameters
if p.Adoption.TotalOrgs.GetYear(year) == 0 {
return ErrInvalidParams{Field: "adoption.total_orgs", Message: "missing value for year " + yearKey(year)}
}
if p.Adoption.PayingShare.GetYear(year) == 0 {
return ErrInvalidParams{Field: "adoption.paying_share", Message: "missing value for year " + yearKey(year)}
}
// Pricing parameters
if p.Pricing.TierMix.GetYear(year) == (TierMix{}) {
return ErrInvalidParams{Field: "pricing.tier_mix", Message: "missing value for year " + yearKey(year)}
}
// Transaction parameters
if p.Transactions.IntrosPerYear.GetYear(year) == 0 {
return ErrInvalidParams{Field: "transactions.intros_per_year", Message: "missing value for year " + yearKey(year)}
}
if p.Transactions.IntroConversion.GetYear(year) == 0 {
return ErrInvalidParams{Field: "transactions.intro_conversion", Message: "missing value for year " + yearKey(year)}
}
if p.Transactions.ServiceGMV.GetYear(year) == 0 {
return ErrInvalidParams{Field: "transactions.service_gmv", Message: "missing value for year " + yearKey(year)}
}
if p.Transactions.GroupGMV.GetYear(year) == 0 {
return ErrInvalidParams{Field: "transactions.group_gmv", Message: "missing value for year " + yearKey(year)}
}
// Municipal parameters
if p.Municipal.Cities.GetYear(year) == 0 {
return ErrInvalidParams{Field: "municipal.cities", Message: "missing value for year " + yearKey(year)}
}
if p.Municipal.AvgLicense.GetYear(year) == 0 {
return ErrInvalidParams{Field: "municipal.avg_license", Message: "missing value for year " + yearKey(year)}
}
// Impact parameters
if p.Impact.HeatMWh.GetYear(year) == 0 {
return ErrInvalidParams{Field: "impact.heat_mwh", Message: "missing value for year " + yearKey(year)}
}
if p.Impact.WaterReuseRate.GetYear(year) == 0 {
return ErrInvalidParams{Field: "impact.water_reuse_rate", Message: "missing value for year " + yearKey(year)}
}
if p.Impact.WasteDiversionRate.GetYear(year) == 0 {
return ErrInvalidParams{Field: "impact.waste_diversion_rate", Message: "missing value for year " + yearKey(year)}
}
// Cost parameters
if p.Costs.Engineers.GetYear(year) == 0 {
return ErrInvalidParams{Field: "costs.engineers", Message: "missing value for year " + yearKey(year)}
}
if p.Costs.MarketingSales.GetYear(year) == 0 {
return ErrInvalidParams{Field: "costs.marketing_sales", Message: "missing value for year " + yearKey(year)}
}
if p.Costs.Operations.GetYear(year) == 0 {
return ErrInvalidParams{Field: "costs.operations", Message: "missing value for year " + yearKey(year)}
}
// Market parameters
if p.Market.SOM.GetYear(year) == 0 {
return ErrInvalidParams{Field: "market.som", Message: "missing value for year " + yearKey(year)}
}
}
return nil
}
// ErrInvalidParams represents a parameter validation error.
type ErrInvalidParams struct {
Field string
Message string
}
func (e ErrInvalidParams) Error() string {
return "invalid params [" + e.Field + "]: " + e.Message
}