public bool Initialize(string familyName, FluidInfo baseInfo, FluidRenderer renderer) { this.familyName = familyName; string result = null; BeginSimulatorProfilerSample(); Profiler.BeginSample("Initialize"); if (baseInfo == null) { result = "Attempting to initialize FluidSimulator without valid info"; } fluidParameters = baseInfo.fluidParameters; cellParameters = baseInfo.cellParameters; operationParameters = baseInfo.operationParameters; operationFlags = baseInfo.operationFlags; if (string.IsNullOrEmpty(result) && this.renderer != null) { result = "Attempting to re-initialize a FluidSimulator"; } if (string.IsNullOrEmpty(result)) { cellParameters.cellSize = fluidParameters.physicalSize / fluidParameters.gridSize; fluidParameters.container = fluidParameters.container ?? transform; // TODO Renderer stuff should probably just be handled by the dispatcher ... if simulator and renderer can be complete ignorant of each other, that would be best. This may not be possible as the Collider depends on both the renderer and the simulator. this.renderer = renderer; this.renderer.transform.parent = fluidParameters.container; this.renderer.gameObject.name = string.Format("{0} Renderer", familyName); result = this.renderer.Initialize(this, baseInfo); } Profiler.BeginSample("InitializeBuffers"); result = initializeBuffers(); if (!string.IsNullOrEmpty(result)) { EndSimulatorProfilerSample(); result = string.Format("Failed to initialize buffers: {0}", result); } Profiler.EndSample(); EndSimulatorProfilerSample(); if (!string.IsNullOrEmpty(result)) { Debug.LogError(result); return(false); } return(true); }
CalcEdge(int iEdge, int iNode, double Pin, double Qliq, double WCT, FluidInfo fluid, bool addEdgeInfo = true) { if (addEdgeInfo) { resEdgeInfo.Add(iEdge, new EdgeInfo(Q: Qliq, WCT: WCT, f: fluid)); } var e = edges[iEdge]; var(iNextNode, direction) = e.Next(iNode); var Pout = double.NaN; if (!double.IsNaN(Pin) && !fluid.IsEmpty) { var root = fluid.GetPvtContext(); var ctx = root.NewCtx() .With(PVT.Prm.P, U.Atm2MPa(Pin)) .Done(); var gd = new Gradient.DataInfo(); var GOR = root[PVT.Arg.Rsb]; // todo: what with GOR ? try { var angleDeg = e.GetAngleDeg(nodes) * direction; var P_MPa = PressureDrop.dropLiq(ctx, gd, D_mm: e.D, L0_m: 0, L1_m: e.L, Roughness: 0.0, flowDir: (PressureDrop.FlowDirection)direction, P0_MPa: ctx[PVT.Prm.P], Qliq, WCT, GOR, dL_m: 20, dP_MPa: 1e-4, maxP_MPa: 60, stepHandler: stepHandler, (iEdge + 1) * direction, getTempK: (Qo, Qw, L) => 273 + 20, getAngle: _ => angleDeg, gradCalc: Gradient.BegsBrill.Calc, WithFriction: false ); Pout = U.MPa2Atm(P_MPa); } catch (Exception ex) { var cn = nodes[iNode]; var nn = nodes[iNextNode]; Logger.TraceInformation($"Error calc for edge A->B\tNodeA={cn.Node_ID}\tNodeB={nn.Node_ID}\tP={ctx[PVT.Prm.P]}\tQ={Qliq}\tEx={ex.Message}"); } } UpdateNodeInfo(iNextNode, Pout); return(iNextNode, Pout); }
public string Initialize(FluidSimulator simulator, FluidInfo info) { string result = null; if (Simulator != null) { result = "Attempting to re-initialize FluidRenderer"; } this.Simulator = simulator; fluidParameters = info.fluidParameters; cellParameters = info.cellParameters; visualizationFlags = info.visualizationFlags; if (string.IsNullOrEmpty(result)) { Profiler.BeginSample("FluidRenderer.GenerateCells"); result = generateCells(); Profiler.EndSample(); } Profiler.EndSample(); return(result); }
protected internal override void RunLogic(TimeStep step) { for (int index = 0; index < items.Count; ++index) { Wrapper wrapper = items[index]; Body body = wrapper.body; if (wrapper.affectable == null || body.IgnoresPhysicsLogics || Scalar.IsPositiveInfinity(body.Mass.Mass)) { continue; } IShape shape = body.Shape; int isInsideCount = 0; foreach (Vector2D corner in body.Rectangle.Corners()) { Scalar distance = line.GetDistance(corner); if (distance <= 0) { isInsideCount++; } } if (isInsideCount == 0) { continue; } if (isInsideCount != 4) { Vector2D relativeVelocity = Vector2D.Zero; Vector2D velocityDirection = Vector2D.Zero; Vector2D dragDirection = Vector2D.Zero; Vector2D centroid = Vector2D.Zero; Line bodyLine; Line.Transform(ref body.Matrices.ToBody, ref line, out bodyLine); GetTangentCallback callback = delegate(Vector2D centTemp) { centroid = body.Matrices.ToWorldNormal * centTemp; PhysicsHelper.GetRelativeVelocity(ref body.State.Velocity, ref centroid, out relativeVelocity); relativeVelocity = FluidVelocity - relativeVelocity; velocityDirection = relativeVelocity.Normalized; dragDirection = body.Matrices.ToBodyNormal * velocityDirection.LeftHandNormal; return(dragDirection); }; FluidInfo lineInfo = wrapper.affectable.GetFluidInfo(callback, bodyLine); if (lineInfo == null) { continue; } // Vector2D centTemp = lineInfo.Centroid; Scalar areaTemp = lineInfo.Area; // Vector2D centroid = body.Matrices.ToWorldNormal * centTemp; Vector2D buoyancyForce = body.State.Acceleration.Linear * areaTemp * -Density; body.ApplyForce(buoyancyForce, centroid); /* * PhysicsHelper.GetRelativeVelocity(ref body.State.Velocity, ref centroid, out relativeVelocity); * relativeVelocity = FluidVelocity-relativeVelocity; * velocityDirection = relativeVelocity.Normalized; * dragDirection = body.Matrices.ToBodyNormal * velocityDirection.LeftHandNormal; * * lineInfo = wrapper.affectable.GetFluidInfo(dragDirection, bodyLine); * if (lineInfo == null) { continue; }*/ Scalar speedSq = relativeVelocity.MagnitudeSq; Scalar dragForceMag = -.5f * Density * speedSq * lineInfo.DragArea * DragCoefficient; Scalar maxDrag = -MathHelper.Sqrt(speedSq) * body.Mass.Mass * step.DtInv; if (dragForceMag < maxDrag) { dragForceMag = maxDrag; } Vector2D dragForce = dragForceMag * velocityDirection; body.ApplyForce(dragForce, body.Matrices.ToWorldNormal * lineInfo.DragCenter); body.ApplyTorque( -body.Mass.MomentOfInertia * (body.Coefficients.DynamicFriction + Density + DragCoefficient) * body.State.Velocity.Angular); } else { Vector2D relativeVelocity = body.State.Velocity.Linear - FluidVelocity; Vector2D velocityDirection = relativeVelocity.Normalized; Vector2D dragDirection = body.Matrices.ToBodyNormal * velocityDirection.LeftHandNormal; Vector2D centroid = wrapper.body.Matrices.ToWorldNormal * wrapper.affectable.Centroid; Vector2D buoyancyForce = body.State.Acceleration.Linear * wrapper.affectable.Area * -Density; wrapper.body.ApplyForce(buoyancyForce, centroid); if (velocityDirection == Vector2D.Zero) { continue; } DragInfo dragInfo = wrapper.affectable.GetFluidInfo(dragDirection); if (dragInfo.DragArea < .01f) { continue; } Scalar speedSq = relativeVelocity.MagnitudeSq; Scalar dragForceMag = -.5f * Density * speedSq * dragInfo.DragArea * DragCoefficient; Scalar maxDrag = -MathHelper.Sqrt(speedSq) * body.Mass.Mass * step.DtInv; if (dragForceMag < maxDrag) { dragForceMag = maxDrag; } Vector2D dragForce = dragForceMag * velocityDirection; wrapper.body.ApplyForce(dragForce, body.Matrices.ToWorldNormal * dragInfo.DragCenter); wrapper.body.ApplyTorque( -body.Mass.MomentOfInertia * (body.Coefficients.DynamicFriction + Density + DragCoefficient) * body.State.Velocity.Angular); } } }
/// <summary> /// Расчёт далее от узлов с, предположительно, известным давлением и входными дебитами /// </summary> /// <param name="nextNodes">узлы для дальнейшего расчёта</param> void CalcNextNodes() { // Начинаем с узлов с заданными параметрами var nextNodesQueue = new Queue <int>(resNodeInfo.Keys); while (nextNodesQueue.Count > 0) { int iNode = nextNodesQueue.Dequeue(); if (!nodeEdges.TryGetValue(iNode, out var lstEdges)) { continue; // одиночные узлы без связей пропускаем } // умеем считать только один неизвестный/исходящий из узла поток if (lstEdges.Count - 1 != lstEdges.Count(i => resEdgeInfo.TryGetValue(i, out var I))) { continue; // если не один, нижерасположенным расчётом посчитать не получится } var Pin = resNodeInfo[iNode].nodeP; FluidInfo fluid = null; int iEdgeOut = -1; double Qliq = 0, Qwat = 0; #region Определяем для узла дебит и характеристики флюида { double Qoil = 0, maxO = 0; foreach (var iEdge in lstEdges) { if (!resEdgeInfo.TryGetValue(iEdge, out var I)) { iEdgeOut = iEdge; continue; } if (double.IsNaN(I.edgeQ)) { continue; // ошибочно посчитанные пропускаем } var O = I.edgeQ * (1 - I.watercut); var W = I.edgeQ * I.watercut; if (maxO < O) { // характеристики флюида пока берём от входящего потока с наибольшим дебитом нефти fluid = I.fluid; maxO = O; } Qoil += O; Qwat += W; } Qliq = Qoil + Qwat; } #endregion int iNextNode; if (double.IsNaN(Pin)) { // протягиваем NaN-давление из тупика iNextNode = edges[iEdgeOut].Next(iNode).iNextNode; // из узла с NaN-давлением выходной дебит принимаем нулевым resEdgeInfo.Add(iEdgeOut, new EdgeInfo(0, 0, WellInfo <TID> .Unknown)); // в следующем узле, возможно, тоже будет NaN UpdateNodeInfo(iNextNode, double.NaN); } else if (fluid != null && !U.isZero(Qliq)) { var WCT = Qwat / Qliq; // пересчитываем обводнённость суммарного потока iNextNode = CalcEdge(iEdgeOut, iNode, Pin, Qliq, WCT, fluid).iNextNode; } else { continue; } // от узла с посчитанными или протянутыми данными потом будем пытаться считать дальше nextNodesQueue.Enqueue(iNextNode); } }
public EdgeInfo(double Q, double WCT, FluidInfo f) { edgeQ = Q; watercut = WCT; fluid = f; }
public EdgeInfo(double Q, double WCT, FluidInfo f, DataKind k) { edgeQ = Q; watercut = WCT; fluid = f; kind = k; }