mirror of
https://github.com/SamyRai/turash.git
synced 2025-12-26 23:01:33 +00:00
- 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
348 lines
17 KiB
Go
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
|
|
}
|