/// <summary> /// Define al FEM triangle functions and add them to the given list of energy functions. /// </summary> /// <param name="efs"></param> private void initFEMTriangleFunctions(List <EnergyFunction> efs) { // Initial values taken from https://github.com/InteractiveComputerGraphics/PositionBasedDynamics/blob/master/Demos/Simulation/SimulationModel.cpp#L11 onwards. const float youngsModulusX = 1; const float youngsModulusY = 1; const float youngsModulusShear = 1; const float poissonRatioXY = 0.3f; const float poissonRatioYX = 0.3f; // https://github.com/InteractiveComputerGraphics/PositionBasedDynamics/blob/master/Demos/ClothDemo/main.cpp#L354 // loop over every triangle foreach (Util.Triangle triangle in triangles) { // Only add FEMTetConstriant for now EnergyFunction fem = FEMTriangleFunction.create(this, triangle.a, triangle.b, triangle.c, youngsModulusX, youngsModulusY, youngsModulusShear, poissonRatioXY, poissonRatioYX); if (fem != null) { efs.Add(fem); } // TODO: OR we can only add Distance and Volume constraints // https://github.com/InteractiveComputerGraphics/PositionBasedDynamics/blob/master/Demos/ClothDemo/main.cpp#L340 } Debug.Log(efs.Count + " FEMFunctions created for " + triangles.Length + " triangles"); }
// find state that has minimum energy public static double FindMinimumState(double initialState, EnergyFunction energyFunc, SimulatedAnnealingParams param, NotifyProgressFunction notifyFunc) { double currentState = initialState; double currentEnergy = energyFunc(currentState); double bestState = currentState; double bestEnergy = currentEnergy; double T = param.initialTemp; double coolingFactor = CalculateCoolingFactor(param.initialTemp, param.maxIteration, param.freezeIteration); Console.WriteLine("state {0} energy {1} T {2} cooling {3} ", currentState, currentEnergy, T, coolingFactor); int i = 0; notifyFunc(i); // count how many times in a row the random walk has met a higher energy neighbour and not switch state // the search area should be wider as the count is higher int noSwitchCount = 0; double stepModifier = 1.0; while (i < param.maxIteration) { if (bestEnergy <= EPSILON && stepModifier <= EPSILON) { break; } double newState = NeighborFunction(currentState, param.stepSize * stepModifier); if (newState != currentState) { double newEnergy = energyFunc(newState); Console.WriteLine("iteration {0} modifier {1} state {2} energy {3} newstate {4} energy {5} ", i, stepModifier, currentState, currentEnergy, newState, newEnergy); bool takeStep = false; if (Double.IsNaN(newEnergy)) { // new energy has bad value, skip } else { if (newEnergy < bestEnergy) { bestState = newState; bestEnergy = newEnergy; } if (newEnergy < currentEnergy) { takeStep = true; } else { double r = rand.NextDouble(); double prob = AcceptanceProbability(currentEnergy, newEnergy, T, param.boltzmanConstant); takeStep = r < prob; Console.WriteLine("energy {0} newenergy {1} T {2} prob {3}", currentEnergy, newEnergy, T, prob); } // use local gradient to estimate step modifier bounds double gradient = Math.Min(Math.Max(Math.Abs((newEnergy - currentEnergy) / (newState - currentState)), EPSILON), 1.0e10); if (takeStep) { noSwitchCount = 0; currentState = newState; currentEnergy = newEnergy; } else { ++noSwitchCount; } if (currentEnergy > T) { stepModifier = Math.Max(Math.Min(stepModifier * 2.0, bestEnergy / gradient), EPSILON); } else { stepModifier = Math.Max(stepModifier / 2.0, currentEnergy / gradient); } } } else { // if newState == currentState skip } T = Math.Max(T * coolingFactor, MIN_TEMPERATURE); ++i; notifyFunc(i); } // rounding for cleaner result bestState = Math.Round(bestState, 9); return(bestState); }
public void Add(EnergyFunction f) { functions.Add(f); }