Пример #1
0
        /// <summary>
        /// Checks whetever actions and observations in this query are consistent with those
        /// </summary>
        /// <param name="state"></param>
        /// <param name="worldAction"></param>
        /// <param name="time"></param>
        /// <returns></returns>
        public override QueryResult CheckCondition(World.State state, World.WorldAction worldAction, int time)
        {
            _logger.Info("Checking if scenario: " + this._scenario + " with parameters:\nstate: " + state + "\naction: " + worldAction);

            var result = QueryResult.Undefined;

            if (this._scenario.observations.Any(sor => sor.Time.Equals(time) && !sor.Expr.Evaluate(state)))
            {
                result = QueryResult.False;
            }

            if (result == QueryResult.True)
            {
                if (this._scenario.actions.Any(sar => sar.Time.Equals(time) && sar.CheckIfActiveAt(time) && !sar.WorldAction.Equals(worldAction)))
                {
                    result = QueryResult.False;
                }
            }

            string logResult = "Executable: " + result;

            if (QueryResult.Undefined == result)
            {
                _logger.Warn(logResult);
            }
            else
            {
                _logger.Info(logResult);
            }

            return(result);
        }
Пример #2
0
    public void Update(World world, World.State state)
    {
        int index = world.GetIndex(Position.x, Position.y);

        AirTemperature[CurSampleIndex] = state.LowerAirTemperature[index];
        Pressure[CurSampleIndex]       = state.LowerAirPressure[index];
        Humidity[CurSampleIndex]       = state.Humidity[index];
        CloudCover[CurSampleIndex]     = state.CloudMass[index];
        Rainfall[CurSampleIndex]       = state.Rainfall[index];
        GroundWater[CurSampleIndex]    = state.GroundWater[index];
        Canopy[CurSampleIndex]         = state.Canopy[index];
        CurSampleIndex = (CurSampleIndex + 1) % SampleCount;
        TotalSamples   = Math.Min(SampleCount, TotalSamples + 1);
    }
Пример #3
0
        public override QueryResult CheckCondition(World.State state, World.WorldAction worldAction, int time)
        {
            _logger.Info("Checking Action: " + this._worldAction + "at time: " + this._time + "\nwith parameters:\nstate: " + state + "\naction: " + worldAction);

            var result = QueryResult.Undefined;

            if (time == _time || _time == -1)
            {
                if (this._worldAction == null)
                {
                    if (worldAction == null)
                    {
                        result = QueryResult.True;
                    }
                    else
                    {
                        result = QueryResult.False;
                    }
                }
                else if (this._worldAction.Equals(worldAction))
                {
                    result = QueryResult.True;
                }
                else
                {
                    result = QueryResult.False;
                }
            }
            else if (_time < time)
            {
                result = QueryResult.False;
            }
            else if (_time > time)
            {
                result = QueryResult.Undefined;
            }

            string logResult = "Method result: " + result;

            if (QueryResult.Undefined == result)
            {
                _logger.Warn(logResult);
            }
            else
            {
                _logger.Info(logResult);
            }

            return(result);
        }
Пример #4
0
 static public void MoveTile(World world, World.State state, World.State nextState, int index, int newIndex)
 {
     nextState.Plate[newIndex]                   = state.Plate[index];
     nextState.Elevation[newIndex]               = state.Elevation[index];
     nextState.Canopy[newIndex]                  = state.Canopy[index];
     nextState.WaterTableDepth[newIndex]         = state.WaterTableDepth[index];
     nextState.GroundWater[newIndex]             = state.GroundWater[index];
     nextState.ShallowSaltMass[newIndex]         = state.ShallowSaltMass[index];
     nextState.DeepSaltMass[newIndex]            = state.DeepSaltMass[index];
     nextState.ShallowWaterTemperature[newIndex] = state.ShallowWaterTemperature[index];
     nextState.ShallowWaterEnergy[newIndex]      = state.ShallowWaterEnergy[index];
     nextState.DeepWaterEnergy[newIndex]         = state.DeepWaterEnergy[index];
     nextState.IceMass[newIndex]                 = state.IceMass[index];
     nextState.SoilFertility[newIndex]           = state.SoilFertility[index];
 }
        /// <summary>
        /// Checks given parameters with conditionAtTimeQuery and ExecutableScenarioQuery
        /// </summary>
        /// <param name="state"></param>
        /// <param name="worldAction"></param>
        /// <param name="time"></param>
        /// <returns></returns>
        public override QueryResult CheckCondition(World.State state, World.WorldAction worldAction, int time)
        {
            _logger.Info("Checking condition: " + this._condition + "\n accesible with parameters:\nstate: " + state + "\naction: " + worldAction);

            QueryResult condAtTimeResult = CondAtTimeQuery.CheckCondition(state, worldAction, time);
            QueryResult execResult       = ExecQuery.CheckCondition(state, worldAction, time);



            QueryResult result;

            if (condAtTimeResult == QueryResult.Error || condAtTimeResult == QueryResult.Error)
            {
                result = QueryResult.Error;
            }
            else
            {
                if (condAtTimeResult == QueryResult.False || condAtTimeResult == QueryResult.False)
                {
                    result = QueryResult.False;
                }
                else
                {
                    if (condAtTimeResult == QueryResult.Undefined || condAtTimeResult == QueryResult.Undefined)
                    {
                        result = QueryResult.Undefined;
                    }
                    else
                    {
                        result = QueryResult.True;
                    }
                }
            }

            string logResult = "Accesible: " + result;

            if (QueryResult.Undefined == result)
            {
                _logger.Warn(logResult);
            }
            else
            {
                _logger.Info(logResult);
            }

            return(result);
        }
Пример #6
0
        static public void GetNormalAndFlow(World world, World.State state, int x, int y, int index, float elevation, float soilFertility, out Vector2 groundWaterFlowDirection, out Vector4 shallowWaterFlow, out Vector3 normal)
        {
            int   indexW = world.GetIndex(world.WrapX(x - 1), y);
            int   indexE = world.GetIndex(world.WrapX(x + 1), y);
            int   indexN = world.GetIndex(x, world.WrapY(y + 1));
            int   indexS = world.GetIndex(x, world.WrapY(y - 1));
            float e      = state.Elevation[index];
            float west   = e - state.Elevation[indexW];
            float east   = e - state.Elevation[indexE];
            float north  = e - state.Elevation[indexN];
            float south  = e - state.Elevation[indexS];

            var g = new Vector2(east > west ? Mathf.Max(0, east) : -Mathf.Max(0, west), north > south ? Mathf.Max(0, north) : -Mathf.Max(0, south));

            groundWaterFlowDirection = g * world.Data.InverseMetersPerTile * world.Data.GroundWaterFlowSpeed * soilFertility * world.Data.GravitationalAcceleration;

            shallowWaterFlow = Vector4.zero;
            float depth = state.WaterAndIceDepth[index];

            if (depth > 0)
            {
                west  += (depth - state.WaterAndIceDepth[indexW]);
                east  += (depth - state.WaterAndIceDepth[indexE]);
                north += (depth - state.WaterAndIceDepth[indexN]);
                south += (depth - state.WaterAndIceDepth[indexS]);

                shallowWaterFlow.x = Mathf.Max(0, west / 2) * world.Data.InverseMetersPerTile * world.Data.GravitationalAcceleration * world.Data.FlowSpeed * world.Data.SecondsPerTick;
                shallowWaterFlow.y = Mathf.Max(0, east / 2) * world.Data.InverseMetersPerTile * world.Data.GravitationalAcceleration * world.Data.FlowSpeed * world.Data.SecondsPerTick;
                shallowWaterFlow.z = Mathf.Max(0, north / 2) * world.Data.InverseMetersPerTile * world.Data.GravitationalAcceleration * world.Data.FlowSpeed * world.Data.SecondsPerTick;
                shallowWaterFlow.w = Mathf.Max(0, south / 2) * world.Data.InverseMetersPerTile * world.Data.GravitationalAcceleration * world.Data.FlowSpeed * world.Data.SecondsPerTick;

                float totalFlow = shallowWaterFlow.x + shallowWaterFlow.y + shallowWaterFlow.z + shallowWaterFlow.w;
                if (totalFlow > depth)
                {
                    shallowWaterFlow /= totalFlow;
                }
                else if (depth > 0)
                {
                    shallowWaterFlow /= depth;
                }
                shallowWaterFlow *= world.Data.FlowMax;
            }

            normal = Vector3.Normalize(new Vector3((west - east) / 2, (south - north) / 2, world.Data.MetersPerTile));
        }
Пример #7
0
        static private Vector2 GetPressureGradient(World world, World.State state, int x, int y, float[] neighborPressure, float[] neighborTemperature, bool isUpper, float pressureAtWindElevation, float windElevation, float molarMass)
        {
            Vector2 pressureDifferential = Vector2.zero;
            Vector2 nWind = Vector2.zero;

            for (int i = 0; i < 4; i++)
            {
                var nIndex = world.GetNeighborIndex(x, y, i);
                // see bottom of: https://en.wikipedia.org/wiki/Vertical_pressure_variation
                float neighborElevation = state.Elevation[nIndex] + state.WaterAndIceDepth[nIndex];
                float neighborTemperatureElevation;
                if (isUpper)
                {
                    neighborTemperatureElevation = neighborElevation + world.Data.BoundaryZoneElevation;
                }
                else
                {
                    neighborTemperatureElevation = neighborElevation;
                }
                float neighborTemperatureAtSeaLevel = neighborTemperature[nIndex] - neighborTemperatureElevation * world.Data.TemperatureLapseRate;
                float neighborElevationAtPressure   = neighborTemperatureAtSeaLevel / world.Data.TemperatureLapseRate * (Mathf.Pow(pressureAtWindElevation / neighborPressure[nIndex], -1.0f / (world.Data.PressureExponent * molarMass)) - 1);


                switch (i)
                {
                case 0:
                    pressureDifferential.x += neighborElevationAtPressure - windElevation;
                    break;

                case 1:
                    pressureDifferential.x -= neighborElevationAtPressure - windElevation;
                    break;

                case 2:
                    pressureDifferential.y -= neighborElevationAtPressure - windElevation;
                    break;

                case 3:
                    pressureDifferential.y += neighborElevationAtPressure - windElevation;
                    break;
                }
            }
            return(pressureDifferential);
        }
Пример #8
0
 static public void Tick(World world, World.State state, World.State nextState)
 {
     _ProfileEarthTick.Begin();
     for (int y = 0; y < world.Size; y++)
     {
         for (int x = 0; x < world.Size; x++)
         {
             int     index     = world.GetIndex(x, y);
             float   elevation = state.Elevation[index];
             Vector4 newShallowWaterFlow;
             Vector2 newFlowDirectionGroundWater;
             Vector3 newNormal;
             GetNormalAndFlow(world, state, x, y, index, elevation, state.SoilFertility[index], out newFlowDirectionGroundWater, out newShallowWaterFlow, out newNormal);
             nextState.FlowDirectionGroundWater[index] = newFlowDirectionGroundWater;
             nextState.ShallowWaterFlow[index]         = newShallowWaterFlow;
             nextState.Normal[index] = newNormal;
         }
     }
     _ProfileEarthTick.End();
 }
Пример #9
0
        static public void Tick(World world, World.State state, World.State nextState)
        {
            _ProfileEarthTick.Begin();
            float inverseFullIceCoverage = 1.0f / (world.Data.MassIce * world.Data.FullIceCoverage);

            for (int y = 0; y < world.Size; y++)
            {
                for (int x = 0; x < world.Size; x++)
                {
                    int index = world.GetIndex(x, y);

                    // Foliage
                    //float freshWaterAvailability = 0;
                    float canopy  = state.Canopy[index];
                    float airHeat = state.LowerAirTemperature[index];

                    float newCanopy = canopy;
                    //			if (canopy > 0)
                    {
                        float waterCoverage = Mathf.Clamp01(state.WaterDepth[index] / world.Data.FullWaterCoverage);
                        float t             = state.LowerAirTemperature[index];
                        float sf            = state.SoilFertility[index];
                        //float groundWaterSaturation = GetGroundWaterSaturation(state.GroundWater[index], state.WaterTableDepth[index], sf * world.Data.MaxSoilPorousness);
                        //float surfaceWater = state.SurfaceWater[index];
                        //freshWaterAvailability = GetFreshWaterAvailability(surfaceWater, groundWaterSaturation);

                        float iceCoverage = Mathf.Clamp01(state.IceMass[index] * inverseFullIceCoverage);

                        float desiredCanopy = sf * (state.Rainfall[index] + state.GroundWater[index]) * (1.0f - waterCoverage) * (1.0f - iceCoverage) * Mathf.Clamp01((t - world.Data.MinTemperatureCanopy) / (world.Data.MaxTemperatureCanopy - world.Data.MinTemperatureCanopy));
                        float canopyGrowth  = (desiredCanopy - canopy) * world.Data.canopyGrowthRate;
                        newCanopy += canopyGrowth;

                        //float expansion = canopy * canopyGrowth * 0.25f;
                        //for (int i = 0; i < 4; i++)
                        //{
                        //	var n = GetNeighbor(x, y, i);
                        //	int neighborIndex = GetIndex(n.x, n.y);
                        //	if (world.IsOcean(state.Elevation[neighborIndex], state.SeaLevel))
                        //	{
                        //		nextState.Canopy[neighborIndex] = Math.Min(1.0f, nextState.Canopy[neighborIndex] + expansion);
                        //	}
                        //}
                        nextState.Canopy[index] = Math.Max(0, newCanopy);
                    }
                }
            }

            for (int i = 0; i < world.MaxHerds; i++)
            {
                var species = state.Species[state.Herds[i].SpeciesIndex];

                // Migrate tiles
                nextState.Herds[i].ActiveTileCount = state.Herds[i].DesiredTileCount;
                for (int j = 0; j < Herd.MaxActiveTiles; j++)
                {
                    if (j < state.Herds[i].DesiredTileCount)
                    {
                        nextState.Herds[i].ActiveTiles[j] = state.Herds[i].DesiredTiles[j];
                    }
                }

                // Generate tile-based shared herd resources
                float water             = 0;
                float comfort           = 0;
                float food              = 0;
                float social            = 0;
                float populationDensity = 0;
                int   herdPopulation    = state.Herds[i].Population;
                float radiation         = 0;
                if (state.Herds[i].ActiveTileCount > 0)
                {
                    for (int j = 0; j < state.Herds[i].ActiveTileCount; j++)
                    {
                        var tile = state.Herds[i].ActiveTiles[j];
                        if (tile.x < 0 || tile.y < 0 || tile.x >= world.Size || tile.y >= world.Size)
                        {
                            // TODO: the active tiles should prob be a list, not a sparse array
                            continue;
                        }
                        int tileIndex = world.GetIndex(tile.x, tile.y);
                        //		water += state.SurfaceWater[tileIndex];
                        comfort   += Mathf.Clamp01((species.RestingTemperature + species.TemperatureRange - state.LowerAirTemperature[tileIndex]) / species.TemperatureRange);
                        food      += state.Canopy[tileIndex];
                        radiation += state.Radiation[tileIndex];
                    }
                }
                populationDensity = (float)state.Herds[i].Population / state.Herds[i].ActiveTileCount;
                social           += populationDensity;


                int population = nextState.Herds[i].Population;

                // Consume water
                float waterConsumptionRate = 0.1f;
                float waterConsumed        = Mathf.Clamp(population * waterConsumptionRate, water, GetMaxWaterHeld() - state.Herds[i].Water);
                nextState.Herds[i].Water += waterConsumed;
                water -= waterConsumed;

                // Consume food
                float foodConsumptionRate = 0.1f;
                float foodConsumed        = Mathf.Clamp(population * foodConsumptionRate, food, GetMaxFoodHeld() - state.Herds[i].Food);
                nextState.Herds[i].Food += foodConsumed;
                food -= foodConsumed;

                nextState.Herds[i].Social = social;

                // Update unit resources (disease)
                //float immuneSystem = 1;
                // Immune system strength is based on water/food/comfort consumed
                //				if (state.Herds[i].Units[j].Maturity)
                //nextState.Herds[i].Units[j].Disease += immuneSystem * populationDensity;

                // Death
                float lifeExpectancy = 10 * world.Data.TicksPerYear;
                float deathRate      = 1.0f / lifeExpectancy;
                float starvationRate = 1.0f * world.Data.TicksPerYear;
                float birthRate      = 10.0f * world.Data.TicksPerYear;

                if (nextState.Herds[i].Water <= 0)
                {
                    deathRate += starvationRate;
                }
                if (nextState.Herds[i].Food <= 0)
                {
                    deathRate += starvationRate;
                }
                herdPopulation = (int)Mathf.Max(0, herdPopulation * (1.0f - deathRate));

                // Birth
                if (nextState.Herds[i].Social > 0 &&
                    nextState.Herds[i].Water > 0 &&
                    nextState.Herds[i].Food > 0)
                {
                    int births = 0;
                    nextState.Herds[i].Birth += social;
                    if (nextState.Herds[i].Birth > birthRate)
                    {
                        births = (int)(nextState.Herds[i].Birth / birthRate);
                        nextState.Herds[i].Birth -= birthRate * births;
                        herdPopulation           += births;
                    }

                    // Mutation and evolution
                    float mutationSpeed = radiation * births;
                    nextState.Herds[i].EvolutionProgress += mutationSpeed;

                    float mutationHealthDelta = state.Herds[i].DesiredMutationHealth - state.Herds[i].MutationHealth;
                    nextState.Herds[i].MutationHealth += Math.Sign(mutationHealthDelta) * Math.Min(mutationSpeed, Math.Abs(mutationHealthDelta));

                    float mutationReproductionDelta = state.Herds[i].DesiredMutationReproduction - state.Herds[i].MutationReproduction;
                    nextState.Herds[i].MutationReproduction += Math.Sign(mutationReproductionDelta) * Math.Min(mutationSpeed, Math.Abs(mutationReproductionDelta));

                    float mutationSizeDelta = state.Herds[i].DesiredMutationSize - state.Herds[i].MutationSize;
                    nextState.Herds[i].MutationSize += Math.Sign(mutationSizeDelta) * Math.Min(mutationSpeed, Math.Abs(mutationSizeDelta));
                }

                nextState.Herds[i].Population = herdPopulation;

                // Collapse units if they can be combined
                // Split units if they hit population cap
            }

            //for (int i = 0;i<MaxHerds;i++)
            //{
            //	float population = state.Herds[i].Population;
            //	if (population > 0)
            //	{
            //		int tileIndex = GetIndex((int)state.Herds[i].Position.x, (int)state.Herds[i].Position.y);
            //		float newPopulation = population;

            //		if (world.IsOcean(state.Elevation[tileIndex], state.SeaLevel))
            //		{
            //			newPopulation = 0;
            //		}
            //		else
            //		{

            //			var species = state.Species[state.Herds[i].Species];
            //			float populationDensity = population / species.speciesMaxPopulation;

            //			float babiesBorn = population * species.speciesGrowthRate;
            //			newPopulation += babiesBorn;

            //			float diedOfOldAge = Math.Max(0, population * 1.0f / (species.Lifespan * Data.TicksPerYear));
            //			newPopulation -= diedOfOldAge;

            //			float diedFromTemperature = population * Math.Abs((state.Temperature[tileIndex] - species.RestingTemperature) / species.TemperatureRange);
            //			newPopulation -= diedFromTemperature;

            //			float freshWaterAvailability = GetFreshWaterAvailability(state.SurfaceWater[tileIndex], GetGroundWaterSaturation(state.GroundWater[tileIndex], state.WaterTableDepth[tileIndex], state.SoilFertility[tileIndex] * Data.MaxSoilPorousness));
            //			float diedOfDehydration = Math.Max(0, population * (populationDensity - freshWaterAvailability / Data.freshWaterMaxAvailability) * species.dehydrationSpeed);
            //			newPopulation -= diedOfDehydration;

            //			if (species.Food == SpeciesType.FoodType.Herbivore)
            //			{
            //				float canopy = nextState.Canopy[tileIndex];
            //				float diedOfStarvation = Math.Max(0, population * (populationDensity - canopy) * species.starvationSpeed);
            //				newPopulation -= diedOfStarvation;
            //				canopy -= population * species.speciesEatRate;
            //				nextState.Canopy[tileIndex] = canopy;
            //			}
            //			else
            //			{
            //				float availableMeat = 0;
            //				for (int m = 0; m < MaxGroupsPerTile; m++)
            //				{
            //					int meatGroupIndex = state.AnimalsPerTile[tileIndex * MaxGroupsPerTile + m];
            //					if (meatGroupIndex >= 0 && state.Species[state.Herds[meatGroupIndex].Species].Food == SpeciesType.FoodType.Herbivore)
            //					{
            //						availableMeat += state.Herds[meatGroupIndex].Population;
            //					}
            //				}
            //				float diedOfStarvation = Math.Max(0, population * (population - availableMeat) * species.starvationSpeed);
            //				newPopulation -= diedOfStarvation;

            //				float meatEaten = Math.Min(availableMeat, population * species.speciesEatRate);
            //				for (int m = 0; m < MaxGroupsPerTile; m++)
            //				{
            //					int meatGroupIndex = state.AnimalsPerTile[tileIndex * MaxGroupsPerTile + m];
            //					if (meatGroupIndex >= 0 && state.Species[state.Herds[meatGroupIndex].Species].Food == SpeciesType.FoodType.Herbivore)
            //					{
            //						float meatPop = nextState.Herds[meatGroupIndex].Population;
            //						nextState.Herds[meatGroupIndex].Population = Math.Max(0, meatPop - meatEaten * meatPop / availableMeat);
            //					}
            //				}
            //			}

            //			if (state.Herds[i].Destination != state.Herds[i].Position)
            //			{
            //				Vector2 diff = state.Herds[i].Destination - state.Herds[i].Position;
            //				float dist = diff.magnitude;
            //				var dir = diff.normalized;
            //				Vector2 move = dist <= species.MovementSpeed ? diff : (species.MovementSpeed * dir);
            //				Vector2 newPos = state.Herds[i].Position + move;
            //				Vector2Int newTile = new Vector2Int((int)newPos.x, (int)newPos.y);
            //				int newTileIndex = GetIndex(newTile.x, newTile.y);

            //				// Don't walk into water
            //				Vector2 nextPos = state.Herds[i].Position + dir;
            //				if (state.Elevation[GetIndex((int)nextPos.x, (int)nextPos.y)] <= state.SeaLevel)
            //				{
            //					nextState.Herds[i].Destination = new Vector2((int)state.Herds[i].Position.x + 0.5f, (int)state.Herds[i].Position.y + 0.5f);
            //				}

            //				// move tiles
            //				if ((int)state.Herds[i].Position.x != newTile.x || (int)state.Herds[i].Position.y != newTile.y)
            //				{
            //					for (int j = 0; j < MaxGroupsPerTile; j++)
            //					{
            //						int newGroupIndex = newTileIndex * MaxGroupsPerTile + j;
            //						if (nextState.AnimalsPerTile[newGroupIndex] == -1)
            //						{
            //							nextState.AnimalsPerTile[newGroupIndex] = i;
            //							nextState.Herds[i].Position = newPos;
            //							for (int k = 0; k < MaxGroupsPerTile; k++)
            //							{
            //								int groupIndex = tileIndex * MaxGroupsPerTile + k;
            //								if (nextState.AnimalsPerTile[groupIndex] == i)
            //								{
            //									nextState.AnimalsPerTile[groupIndex] = -1;
            //									break;
            //								}
            //							}
            //							break;
            //						}
            //					}
            //				}
            //				else
            //				{
            //					nextState.Herds[i].Position = newPos;
            //				}
            //			}

            //		}
            //		nextState.Herds[i].Population = Math.Max(0, newPopulation);
            //		if (newPopulation <= 0)
            //		{
            //			for (int j = 0; j < MaxGroupsPerTile; j++)
            //			{
            //				int groupIndex = tileIndex * MaxGroupsPerTile + j;
            //				if (nextState.AnimalsPerTile[groupIndex] == i)
            //				{
            //					nextState.AnimalsPerTile[groupIndex] = -1;
            //				}
            //			}
            //		}

            //	}
            //}

            _ProfileEarthTick.End();
        }
Пример #10
0
        static public void Tick(World world, World.State state, World.State nextState)
        {
            _ProfileWindTick.Begin();

            float inverseFullIceCoverage = 1.0f / world.Data.FullIceCoverage;

            for (int y = 0; y < world.Size; y++)
            {
                float latitude = world.Data.windInfo[y].latitude;
                var   windInfo = world.Data.windInfo[y];

                for (int x = 0; x < world.Size; x++)
                {
                    int index = world.GetIndex(x, y);

                    float upperPressure       = state.UpperAirPressure[index];
                    float lowerPressure       = state.LowerAirPressure[index];
                    float upperTemperature    = state.UpperAirTemperature[index];
                    float lowerTemperature    = state.LowerAirTemperature[index];
                    float elevation           = state.Elevation[index];
                    float waterDepth          = state.WaterDepth[index];
                    float waterAndIceDepth    = state.WaterAndIceDepth[index];
                    float elevationOrSeaLevel = elevation + waterAndIceDepth;
                    var   normal      = state.Normal[index];
                    float iceCoverage = state.IceMass[index] * inverseFullIceCoverage;
                    float friction;
                    if (waterDepth > 0)
                    {
                        friction = world.Data.WindOceanFriction;
                    }
                    else
                    {
                        friction = world.Data.WindLandFriction;
                    }
                    friction = Mathf.Clamp01(Mathf.Lerp(friction, world.Data.WindIceFriction, iceCoverage));
                    float lowerTemperatureAtSeaLevel = lowerTemperature - world.Data.TemperatureLapseRate * elevationOrSeaLevel;
                    float molarMassLowerAir          = Atmosphere.GetMolarMassAir(world, state.LowerAirMass[index], state.Humidity[index]);
                    float molarMassUpperAir          = Atmosphere.GetMolarMassAir(world, state.UpperAirMass[index] + state.StratosphereMass, state.CloudMass[index]);
                    float surfaceAirDensity          = Atmosphere.GetAirDensity(world, lowerPressure, lowerTemperatureAtSeaLevel, molarMassLowerAir);
                    float boundaryElevation          = elevationOrSeaLevel + world.Data.BoundaryZoneElevation;
                    float upperTemperatureAtSeaLevel = upperTemperature - world.Data.TemperatureLapseRate * boundaryElevation;
                    float tropopausePressure         = upperPressure * Mathf.Pow(1 + world.Data.TemperatureLapseRate / upperTemperatureAtSeaLevel * world.Data.TropopauseElevation, -world.Data.PressureExponent * molarMassUpperAir);
                    float tropopauseDensity          = Atmosphere.GetAirDensity(world, tropopausePressure, upperTemperature + world.Data.TemperatureLapseRate * (world.Data.TropopauseElevation - boundaryElevation), molarMassUpperAir);

                    var upperWindH = GetHorizontalWind(world, state, x, y, state.UpperWind[index], latitude, state.PlanetRotationSpeed, windInfo.coriolisParam, windInfo.inverseCoriolisParam, world.Data.GlobalCoriolisInfluenceWindUpper, state.UpperAirPressure, state.UpperAirTemperature, true, tropopausePressure, elevationOrSeaLevel, world.Data.TropopauseElevation, 0, tropopauseDensity, molarMassUpperAir);
                    var lowerWindH = GetHorizontalWind(world, state, x, y, state.LowerWind[index], latitude, state.PlanetRotationSpeed, windInfo.coriolisParam, windInfo.inverseCoriolisParam, world.Data.GlobalCoriolisInfluenceWindLower, state.LowerAirPressure, state.LowerAirTemperature, false, lowerPressure, elevationOrSeaLevel, elevationOrSeaLevel, friction, surfaceAirDensity, molarMassLowerAir);

                    // within 1 km of the ground, frictional forces slow wind down
                    float neighborPressureDifferential  = 0;
                    float neighborElevationDifferential = 0;
                    if (lowerWindH.x < 0)
                    {
                        int neighborIndex = world.GetNeighborIndex(x, y, 0);
                        neighborPressureDifferential  += -lowerWindH.x * (lowerPressure - state.LowerAirPressure[neighborIndex]);
                        neighborElevationDifferential += -lowerWindH.x * (state.Elevation[neighborIndex] + state.WaterAndIceDepth[neighborIndex] - elevationOrSeaLevel);
                    }
                    else
                    {
                        var neighborIndex = world.GetNeighborIndex(x, y, 1);
                        neighborPressureDifferential  += lowerWindH.x * (lowerPressure - state.LowerAirPressure[neighborIndex]);
                        neighborElevationDifferential += lowerWindH.x * (state.Elevation[neighborIndex] + state.WaterAndIceDepth[neighborIndex] - elevationOrSeaLevel);
                    }
                    if (lowerWindH.y < 0)
                    {
                        var neighborIndex = world.GetNeighborIndex(x, y, 3);
                        neighborPressureDifferential  += -lowerWindH.y * (lowerPressure - state.LowerAirPressure[neighborIndex]);
                        neighborElevationDifferential += -lowerWindH.y * (state.Elevation[neighborIndex] + state.WaterAndIceDepth[neighborIndex] - elevationOrSeaLevel);
                    }
                    else
                    {
                        var neighborIndex = world.GetNeighborIndex(x, y, 2);
                        neighborPressureDifferential  += lowerWindH.y * (lowerPressure - state.LowerAirPressure[neighborIndex]);
                        neighborElevationDifferential += lowerWindH.y * (state.Elevation[neighborIndex] + state.WaterAndIceDepth[neighborIndex] - elevationOrSeaLevel);
                    }
                    var verticalTemperatureDifferential = lowerTemperatureAtSeaLevel - upperTemperatureAtSeaLevel;

                    float lowerWindSpeedH = lowerWindH.magnitude;
                    float lowerWindV      = neighborElevationDifferential * world.Data.MountainUpdraftWindSpeed;
                    lowerWindV += neighborPressureDifferential * world.Data.DestinationPressureDifferentialToVerticalWindSpeed; // thermal
                    lowerWindV += (lowerPressure - upperPressure) * world.Data.PressureToVerticalWindSpeed;                     // thermal


                    nextState.LowerWind[index] = new Vector3(lowerWindH.x, lowerWindH.y, lowerWindV);
                    nextState.UpperWind[index] = new Vector3(upperWindH.x, upperWindH.y, 0);

                    if (float.IsNaN(nextState.UpperWind[index].x) || float.IsNaN(nextState.LowerWind[index].x) || float.IsNaN(nextState.LowerWind[index].z))
                    {
                        Debug.DebugBreak();
                    }

                    if (world.IsOcean(state.WaterDepth[index]))
                    {
                        Vector2 densityDifferential = Vector2.zero;
                        Vector2 shallowCurrentH;
                        float   shallowCurrentV = 0;

                        if (iceCoverage < 1)
                        {
                            shallowCurrentH = GetCurrentHorizontal(world, x, y, latitude, state.PlanetRotationSpeed, windInfo.coriolisParam, windInfo.inverseCoriolisParam, lowerWindH);
                            if (iceCoverage > 0)
                            {
                                shallowCurrentH *= 1.0f - iceCoverage;
                            }
                        }
                        else
                        {
                            shallowCurrentH = Vector2.zero;
                        }

                        if (state.DeepWaterMass[index] > 0)
                        {
                            float density = state.DeepWaterDensity[index];
                            for (int i = 0; i < 4; i++)
                            {
                                var neighbor = world.GetNeighbor(x, y, i);
                                int nIndex   = world.GetIndex(neighbor.x, neighbor.y);
                                if (state.DeepWaterMass[nIndex] > 0)
                                {
                                    //var neighborWind = state.Wind[nIndex];
                                    //nWind += neighborWind;

                                    switch (i)
                                    {
                                    case 0:
                                        densityDifferential.x += state.DeepWaterDensity[nIndex] - density;
                                        break;

                                    case 1:
                                        densityDifferential.x -= state.DeepWaterDensity[nIndex] - density;
                                        break;

                                    case 2:
                                        densityDifferential.y -= state.DeepWaterDensity[nIndex] - density;
                                        break;

                                    case 3:
                                        densityDifferential.y += state.DeepWaterDensity[nIndex] - density;
                                        break;
                                    }
                                }
                                else
                                {
                                    //switch (i)
                                    //{
                                    //	case 0:
                                    //		shallowCurrentV += shallowCurrentH.x;
                                    //		if (shallowCurrentH.x < 0)
                                    //		{
                                    //			shallowCurrentH.x = 0;
                                    //		}
                                    //		break;
                                    //	case 1:
                                    //		shallowCurrentV -= shallowCurrentH.x;
                                    //		if (shallowCurrentH.x > 0)
                                    //		{
                                    //			shallowCurrentH.x = 0;
                                    //		}
                                    //		break;
                                    //	case 2:
                                    //		shallowCurrentV -= shallowCurrentH.y;
                                    //		if (shallowCurrentH.y > 0)
                                    //		{
                                    //			shallowCurrentH.y = 0;
                                    //		}
                                    //		break;
                                    //	case 3:
                                    //		shallowCurrentV += shallowCurrentH.y;
                                    //		if (shallowCurrentH.y < 0)
                                    //		{
                                    //			shallowCurrentH.y = 0;
                                    //		}
                                    //		break;
                                    //}
                                }
                            }
                        }
                        densityDifferential *= world.Data.OceanDensityCurrentSpeed;
                        nextState.DeepWaterCurrent[index]    = new Vector3(densityDifferential.x, densityDifferential.y, 0);
                        nextState.ShallowWaterCurrent[index] = new Vector3(shallowCurrentH.x, shallowCurrentH.y, shallowCurrentV);
                    }
                    else
                    {
                        nextState.DeepWaterCurrent[index]    = Vector3.zero;
                        nextState.ShallowWaterCurrent[index] = Vector3.zero;
                    }
                }
            }


            _ProfileWindTick.End();
        }
Пример #11
0
        static public Vector2 GetHorizontalWind(World world, World.State state, int x, int y, Vector3 curWind, float latitude, float planetRotationSpeed, float coriolisParam, float inverseCoriolisParam, float coriolisInfluenceAtElevation, float[] worldPressure, float[] worldTemperature, bool isUpper, float thisPressure, float landElevation, float windElevation, float friction, float density, float molarMass)
        {
            float inverseDensity = 1.0f / density;
            float altitude       = Mathf.Max(0, windElevation - landElevation);
            float complementFrictionAtElevation = 1.0f - friction * Mathf.Max(0, (world.Data.BoundaryZoneElevation - altitude) / world.Data.BoundaryZoneElevation);
            var   pressureGradientForce         = GetPressureGradient(world, state, x, y, worldPressure, worldTemperature, isUpper, thisPressure, windElevation, molarMass);

            pressureGradientForce.x *= world.Data.GravitationalAcceleration * world.Data.InverseMetersPerTile;
            pressureGradientForce.y *= world.Data.GravitationalAcceleration * world.Data.InverseMetersPerTile;
            Vector2 wind = Vector2.zero;

            //for (int i = 0; i < 4; i++)
            //{
            //	var nIndex = world.GetNeighborIndex(x, y, i);
            //	var neighborWind = state.UpperWind[nIndex];
            //	float nWindSpeed = Mathf.Sqrt(neighborWind.x * neighborWind.x + neighborWind.y * neighborWind.y);
            //	switch (i)
            //	{
            //		case 0:
            //			if (neighborWind.x > 0)
            //			{
            //				wind += neighborWind.x / nWindSpeed * new Vector3(neighborWind.x, neighborWind.y, 0);
            //			}
            //			break;
            //		case 1:
            //			if (neighborWind.x < 0)
            //			{
            //				wind += -neighborWind.x / nWindSpeed * new Vector3(neighborWind.x, neighborWind.y, 0);
            //			}
            //			break;
            //		case 2:
            //			if (neighborWind.y < 0)
            //			{
            //				wind += -neighborWind.y / nWindSpeed * new Vector3(neighborWind.x, neighborWind.y, 0);
            //			}
            //			break;
            //		case 3:
            //			if (neighborWind.y > 0)
            //			{
            //				wind += neighborWind.y / nWindSpeed * new Vector3(neighborWind.x, neighborWind.y, 0);
            //			}
            //			break;
            //	}
            //}

            var pressureWind = pressureGradientForce * world.Data.PressureGradientWindMultiplier;

            if (coriolisParam != 0)
            {
                float geostrophicInfluence = Mathf.Clamp01(Mathf.Pow(Mathf.Abs(coriolisParam) * 2, 2)) * complementFrictionAtElevation * coriolisInfluenceAtElevation;
                var   geostrophicWind      = new Vector2(-pressureGradientForce.y, pressureGradientForce.x) * inverseCoriolisParam / planetRotationSpeed;
                wind = (geostrophicWind * geostrophicInfluence + pressureWind * (1.0f - geostrophicInfluence));
            }
            else
            {
                wind = pressureWind;
            }
            wind *= complementFrictionAtElevation * inverseDensity;


            //wind += inertialWind * world.Data.windInertia;
            return(wind);
        }
Пример #12
0
        static public void MovePlate(World world, World.State state, World.State nextState, int plateIndex, Vector2Int direction)
        {
            // TODO: enforce conservation of mass

            for (int y = 0; y < world.Size; y++)
            {
                for (int x = 0; x < world.Size; x++)
                {
                    int index = world.GetIndex(x, y);
                    if (state.Plate[index] == plateIndex)
                    {
                        Vector2Int newPoint = new Vector2Int(world.WrapX(x + direction.x), world.WrapY(y + direction.y));
                        int        newIndex = world.GetIndex(newPoint.x, newPoint.y);
                        if (state.Plate[newIndex] == plateIndex)
                        {
                            MoveTile(world, state, nextState, index, newIndex);

                            Vector2Int divergentPoint = new Vector2Int(world.WrapX(x - direction.x), world.WrapY(y - direction.y));
                            int        divergentIndex = world.GetIndex(divergentPoint.x, divergentPoint.y);
                            if (state.Plate[divergentIndex] != plateIndex)
                            {
                                // divergent zone
                                //								if (state.Elevation[index] > state.Elevation[divergentIndex])
                                {
                                    nextState.Plate[index] = state.Plate[divergentIndex];
                                }
                                nextState.Elevation[index]       = (state.Elevation[index] + state.Elevation[divergentIndex]) / 2 - 100;
                                nextState.WaterTableDepth[index] = (state.WaterTableDepth[index] + state.WaterTableDepth[divergentIndex]) / 2;
                                nextState.SoilFertility[index]   = (state.SoilFertility[index] + state.SoilFertility[divergentIndex]) / 2;
                            }
                        }
                        else
                        {
                            float startElevation = state.Elevation[index];
                            float endElevation   = state.Elevation[newIndex];
                            if (!world.IsOcean(state.WaterDepth[index]) && !world.IsOcean(state.WaterDepth[index]))                             // TODO: this is broken now that sealevel isnt a constant
                            {
                                // continental collision
                                nextState.Elevation[newIndex] += 50;
                                nextState.Elevation[index]    += 50;
                                nextState.Plate[newIndex]      = plateIndex;
                            }
                            else
                            {
                                // subduction
                                if (!world.IsOcean(state.WaterDepth[index]))
                                {
                                    // We are moving OVER the adjacent tile
                                    MoveTile(world, state, nextState, index, newIndex);
                                    Vector2Int subductionPoint = new Vector2Int(world.WrapX(newPoint.x + direction.x), world.WrapY(newPoint.y + direction.y));
                                    int        subductionIndex = world.GetIndex(subductionPoint.x, subductionPoint.y);
                                    nextState.Elevation[newIndex]         = (state.Elevation[newIndex] + state.Elevation[subductionIndex]) / 2;
                                    nextState.Elevation[subductionIndex] -= 100;
                                }
                                else
                                {
                                    // we are moving UNDER the adjacent tile
                                    nextState.Elevation[newIndex] = (state.Elevation[newIndex] + state.Elevation[index]) / 2;
                                    nextState.Elevation[index]   -= 100;
                                }
                            }
                        }
                    }
                }
            }

            for (int y = 0; y < world.Size; y++)
            {
                for (int x = 0; x < world.Size; x++)
                {
                    int     index     = world.GetIndex(x, y);
                    float   elevation = state.Elevation[index];
                    Vector2 newFlowDirectionGroundWater;
                    Vector4 newShallowWaterFlow;
                    Vector3 newNormal;
                    GetNormalAndFlow(world, nextState, x, y, index, elevation, state.SoilFertility[index], out newFlowDirectionGroundWater, out newShallowWaterFlow, out newNormal);
                    nextState.FlowDirectionGroundWater[index] = newFlowDirectionGroundWater;
                    nextState.ShallowWaterFlow[index]         = newShallowWaterFlow;
                    nextState.Normal[index] = newNormal;
                }
            }
        }