/// <summary>Make vector object from other vector object</summary> /// <param name="size">size of vector</param> /// <param name="startNumber"></param> /// <param name="originalVector"></param> internal Vector(uint size, uint startNumber, Vector originalVector) { this.isVectorView = true; this.viewSize = size; this.viewStartNumber = startNumber; this.originalVector = originalVector; }
/// <summary>Constructor</summary> /// <param name="variableNumber">number of variables and functions</param> public MultiRoot(uint variableNumber) { this.VariableNumber = variableNumber; outputs1 = new double[variableNumber]; outputs2 = new double[variableNumber]; jacobian = new Matrix(variableNumber, variableNumber); fnc = new Vector(variableNumber); }
/// <summary>行列とベクトルの積と和を計算する(y = α op(A) x + βy)</summary> /// <param name="vectorX">ベクトルX</param> /// <param name="vectorY">ベクトルY(解が上書きされる)</param> /// <param name="alpha">第一項の係数</param> /// <param name="beta">第二項の係数</param> internal void VectorProduct(Vector vectorX, ref Vector vectorY, double alpha, double beta) { for (uint i = 0; i < this.Columns; i++) { vectorY.SetValue(i, vectorY.GetValue(i) * beta); for (uint j = 0; j < this.Rows; j++) { vectorY.AddValue(i, alpha * this.GetValue(i, j) * vectorX.GetValue(j)); } } }
/// <summary></summary> /// <param name="vector"></param> internal void LUSolve(ref Vector vector) { if (isMatrixView) { uint ii = 0; for (uint i = 0; i < Rows; i++) { uint ip = perm[i]; double sum = vector.GetValue(ip); vector.SetValue(ip, vector.GetValue(i)); if (ii != 0) { for (uint j = ii - 1; j < i; j++) sum -= GetValue(i, j) * vector.GetValue(j); } else if (sum != 0) ii = i + 1; vector.SetValue(i, sum); } for (int i = (int)Rows - 1; i >= 0; i--) { uint iii = (uint)i; double sum = vector.GetValue(iii); for (uint j = iii + 1; j < Columns; j++) sum -= GetValue(iii, j) * vector.GetValue(j); vector.SetValue(iii, sum / GetValue(iii, iii)); } } else { uint ii = 0; for (uint i = 0; i < Rows; i++) { uint ip = perm[i]; double sum = vector.GetValue(ip); vector.SetValue(ip, vector.GetValue(i)); if (ii != 0) { for (uint j = ii - 1; j < i; j++) sum -= mat[i, j] * vector.GetValue(j); } else if (sum != 0) ii = i + 1; vector.SetValue(i, sum); } for (int i = (int)Rows - 1; i >= 0; i--) { uint iii = (uint)i; double sum = vector.GetValue(iii); for (uint j = iii + 1; j < Columns; j++) sum -= mat[iii, j] * vector.GetValue(j); vector.SetValue(iii, sum / mat[iii, iii]); } } }
/// <summary>matrix1の逆行列を計算してmatrix2に設定する</summary> /// <param name="matrix"></param> internal void GetInverse(ref Matrix matrix) { LUDecomposition(); Vector col = new Vector(Columns); for (uint j = 0; j < Columns; j++) { col.SetValue(0); col.SetValue(j, 1); LUSolve(ref col); for (uint i = 0; i < Columns; i++) matrix.SetValue(i, j, col.GetValue(i)); } }
/// <summary>行列要素を設定する(JOSモデル)</summary> /// <param name="zm">ZMベクトル(要素の単位は全てW)</param> /// <param name="bm">BM行列(要素の単位は全てW/K)</param> private void makeJOSMatrix(ref Vector zm, ref Matrix bm) { const double RCS = HumanBody.RHO_C / 3.6d; //流量単位がL/hなので、ここで単位を調整 double dt = Body.timeStep; bool hasAVA = (heatCapacity_SuperficialVein != 0); double sum; //JOS計算用にコア・脂肪・筋肉層を統合 double hcapCore = heatCapacity_Core + heatCapacity_Fat + heatCapacity_Muscle; double bfCore = bloodFlow_Core + bloodFlow_Fat + bloodFlow_Muscle; double mrCore = metabolicRate_Core + metabolicRate_Fat + metabolicRate_Muscle; //皮膚・空気間の熱コンダクタンスを更新 updateHeatConductance_Skin_Air(); //蒸発熱損失を計算 //不感蒸泄分 double eMax = LatentHeatConductance_Skin_Air * (HumanBody.getSaturatedVaporPressure(SkinTemperature_NonContact) - HumanBody.getVaporPressure(DrybulbTemperature, RelativeHumidity, Body.AtmosphericPressure)); EvaporativeHeatLoss = 0.06 * eMax + EvaporativeHeatLoss_Sweat * 0.94; //ZMベクトルを設定************************************************************************* zm.SetValue(0, hcapCore * 3600 * coreTemperature / dt + mrCore + WorkLoad + ShiveringLoad); zm.SetValue(1, heatCapacity_Skin * 3600 * SkinTemperature_Contact / dt + MaterialTemperature * HeatConductance_Skin_Material * SurfaceArea + metabolicRate_Skin); zm.SetValue(2, heatCapacity_Skin * 3600 * SkinTemperature_NonContact / dt + OperativeTemperature * HeatConductance_Skin_Air + metabolicRate_Skin - EvaporativeHeatLoss); zm.SetValue(3, heatCapacity_Artery * 3600 * arteryTemperature / dt); zm.SetValue(4, heatCapacity_DeepVein * 3600 * deepVeinTemperature / dt); if (hasAVA) zm.SetValue(5, heatCapacity_SuperficialVein * 3600 * superficialVeinTemperature / dt); //BM行列を設定***************************************************************************** //コア層 bm.SetValue(0, 0, hcapCore * 3600d / dt + RCS * bfCore + 2 * heatConductance_Vein_Core + heatConductance_Core_Skin); bm.SetValue(0, 1, -ContactPortionRate * heatConductance_Core_Skin); bm.SetValue(0, 2, -NonContactPortionRate * heatConductance_Core_Skin); bm.SetValue(0, 3, -(RCS * bfCore + heatConductance_Vein_Core)); bm.SetValue(0, 4, -heatConductance_Vein_Core); if (hasAVA) bm.SetValue(0, 5, 0); //皮膚層接触部 bm.SetValue(1, 0, -heatConductance_Core_Skin); bm.SetValue(1, 1, heatCapacity_Skin * 3600d / dt + RCS * bloodFlow_Skin + heatConductance_Core_Skin + heatConductance_SuperficialVein_Skin + HeatConductance_Skin_Material * SurfaceArea); bm.SetValue(1, 2, 0); bm.SetValue(1, 3, -RCS * bloodFlow_Skin); bm.SetValue(1, 4, 0); if (hasAVA) bm.SetValue(1, 5, -heatConductance_SuperficialVein_Skin); //皮膚層非接触部 bm.SetValue(2, 0, -heatConductance_Core_Skin); bm.SetValue(2, 1, 0); bm.SetValue(2, 2, heatCapacity_Skin * 3600d / dt + RCS * bloodFlow_Skin + heatConductance_Core_Skin + heatConductance_SuperficialVein_Skin + HeatConductance_Skin_Air); bm.SetValue(2, 3, -RCS * bloodFlow_Skin); bm.SetValue(2, 4, 0); if (hasAVA) bm.SetValue(2, 5, -heatConductance_SuperficialVein_Skin); //動脈 bm.SetValue(3, 0, -heatConductance_Vein_Core); bm.SetValue(3, 1, 0); bm.SetValue(3, 2, 0); bm.SetValue(3, 3, heatCapacity_Artery * 3600d / dt + RCS * bloodFlow_Artery + heatConductance_Vein_Core + heatConductance_Artery_DeepVein); bm.SetValue(3, 4, -heatConductance_Artery_DeepVein); if (hasAVA) bm.SetValue(3, 5, 0); //深部静脈 bm.SetValue(4, 0, -(RCS * bfCore + heatConductance_Vein_Core)); bm.SetValue(4, 1, -ContactPortionRate * RCS * bloodFlow_Skin); bm.SetValue(4, 2, -NonContactPortionRate * RCS * bloodFlow_Skin); bm.SetValue(4, 3, -heatConductance_Artery_DeepVein); sum = heatCapacity_DeepVein * 3600d / dt + RCS * bfCore + RCS * bloodFlow_Skin + heatConductance_Vein_Core + heatConductance_Artery_DeepVein; foreach (BodyPart bp in bpConnectTo) { if (Position == HumanBody.Nodes.Pelvis) sum += RCS * (bp.GetBloodFlow(Segments.DeepVein) + bp.GetBloodFlow(Segments.SuperficialVein)); else sum += RCS * bp.GetBloodFlow(Segments.DeepVein); } bm.SetValue(4, 4, sum); if (hasAVA) bm.SetValue(4, 5, 0); //表在静脈 if (hasAVA) { bm.SetValue(5, 0, 0); bm.SetValue(5, 1, -ContactPortionRate * heatConductance_SuperficialVein_Skin); bm.SetValue(5, 2, -NonContactPortionRate * heatConductance_SuperficialVein_Skin); //四肢末端部の場合 if ((Position & HumanBody.Nodes.TerminalPart) != HumanBody.Nodes.None) bm.SetValue(5, 3, -RCS * GetBloodFlow(Segments.SuperficialVein)); //その他 else bm.SetValue(5, 3, 0); bm.SetValue(5, 4, 0); sum = heatCapacity_SuperficialVein * 3600d / dt + heatConductance_SuperficialVein_Skin; if ((Position & HumanBody.Nodes.TerminalPart) != HumanBody.Nodes.None) sum += RCS * GetBloodFlow(Segments.SuperficialVein); if (Position != HumanBody.Nodes.Pelvis) { foreach (BodyPart bp in bpConnectTo) sum += RCS * bp.GetBloodFlow(Segments.SuperficialVein); } bm.SetValue(5, 5, sum); } }
/// <summary>温度[C]を設定する</summary> /// <param name="temperatures">温度[C]</param> internal void setTemperature(Vector temperatures) { coreTemperature = temperatures.GetValue(0); SkinTemperature_Contact = temperatures.GetValue(1); SkinTemperature_NonContact = temperatures.GetValue(2); arteryTemperature = temperatures.GetValue(3); deepVeinTemperature = temperatures.GetValue(4); if (heatCapacity_SuperficialVein != 0) superficialVeinTemperature = temperatures.GetValue(5); if (! isJOSModel) { if (heatCapacity_SuperficialVein != 0) { muscleTemperature = temperatures.GetValue(6); fatTemperature = temperatures.GetValue(7); } else { muscleTemperature = temperatures.GetValue(5); fatTemperature = temperatures.GetValue(6); } } }
/// <summary>行列要素を設定する</summary> /// <param name="zm">ZMベクトル(要素の単位は全てW)</param> /// <param name="bm">BM行列(要素の単位は全てW/K)</param> internal void makeMatrix(ref Vector zm, ref Matrix bm) { if (isJOSModel) makeJOSMatrix(ref zm, ref bm); else make132MNMatrix(ref zm, ref bm); }
/// <summary>UX行列を更新する</summary> private void makeUMatrix() { uint mNumber = (uint)res.Length - 1; //逆行列計算領域を確保 if (uMatrix.Columns != mNumber) { uMatrix = new Matrix(mNumber, mNumber); uMatrix2 = new Matrix(mNumber, mNumber); //perm = new Permutation(mNumber); perm = new uint[mNumber]; uxMatrix = new Matrix(mNumber, mNumber); cfVector = new Vector(mNumber); uL = new double[mNumber]; uR = new double[mNumber]; ux0mMatrix = new Matrix(mNumber, 2); temperatures = new Vector(mNumber); temperaturesLMAT = new Vector(mNumber); temperaturesFRZ = new Vector(mNumber); fpt1 = new Vector(mNumber); fpt2 = new Vector(mNumber); } uMatrix.Initialize(0); //perm.Initialize(); for (int i = 0; i < mNumber; i++) { double c = 0.5 * (cap[i] + cap[i + 1]); uL[i] = timeStep / (c * res[i]); uR[i] = timeStep / (c * res[i + 1]); } uMatrix.SetValue(0, 0, 1d + uL[0] + uR[0]); for (uint i = 1; i < mNumber; i++) { uMatrix.SetValue(i, i, 1d + uL[i] + uR[i]); uMatrix.SetValue(i, i - 1, -uL[i]); uMatrix.SetValue(i - 1, i, -uR[i - 1]); } }
/// <summary>ベクトルをベクトルにコピーする</summary> /// <param name="vector">コピー先のベクトル</param> internal void CopyTo(ref Vector vector) { if (isVectorView) { for (uint i = 0; i < viewSize; i++) vector.vect[i] = originalVector.GetValue(i + viewStartNumber); } else { for (int i = 0; i < this.vect.Length; i++) vector.vect[i] = this.vect[i]; } }
/// <summary>ベクトルの内容をピーする</summary> /// <param name="vector">コピーもとのベクトル</param> internal void CopyFrom(Vector vector) { if (isVectorView) { for (uint i = 0; i < viewSize; i++) originalVector.SetValue(i + viewStartNumber, vector.vect[i]); } else { for (int i = 0; i < this.vect.Length; i++) this.vect[i] = vector.vect[i]; } }
/// <summary>体温を更新する</summary> private void updateBodyTemperature() { const double RCS = RHO_C / 3.6d; //流量単位がL/hなので、ここで単位を調整 //対流熱伝達率の補正係数を計算 double sumHc = 0; double sumVl = 0; double sumArea = 0; foreach (Nodes bp in parts.Keys) { BodyPart part = parts[bp]; sumVl += part.Velocity * part.SurfaceArea; sumHc += part.ConvectiveHeatTransferCoefficient * part.SurfaceArea; sumArea += part.SurfaceArea; } sumHc /= sumArea; sumVl /= sumArea; convectiveHeatTransferCoefficientMod = Math.Max(8.600001 * Math.Pow(sumVl, 0.53) / sumHc, 3d / sumHc); //行列初期化 bmMatrix.Initialize(0); zmVector.SetValue(0); //部位温度に関する行列を用意 Matrix bmView; Vector zmView; double coreSum = HeatCapacity_CentralBloodPool * 3600 / timeStep; foreach (Nodes bp in parts.Keys) { BodyPart part = parts[bp]; uint startPoint = bpDict[bp]; bool hasAVA = (part.GetHeatCapacity(BodyPart.Segments.SuperficialVein) != 0); //部位別の行列要素を設定****************** uint size = 5; if (!part.IsJOSModel) size += 2; if (part.GetHeatCapacity(BodyPart.Segments.SuperficialVein) != 0) size += 1; bmView = new Matrix(size, size, startPoint, startPoint, bmMatrix); zmView = new Vector(size, startPoint, zmVector); part.makeMatrix(ref zmView, ref bmView); //部位間血流に関する行列要素を設定******** BodyPart ptf = part.bpConnectFrom; //上流に部位が存在する場合 if (ptf != null) bmMatrix.SetValue(startPoint + 3, bpDict[ptf.Position] + 3, - RCS * part.GetBloodFlow(BodyPart.Segments.Artery)); //上流が中央血液だまりの場合 else { //動脈血流による熱移動 bmMatrix.SetValue(startPoint + 3, bmMatrix.Columns - 1, -RCS * part.GetBloodFlow(BodyPart.Segments.Artery)); //中央血液だまりへ向かう静脈血流による熱移動を計算 bmMatrix.SetValue(bmMatrix.Columns - 1, startPoint + 4, -RCS * part.GetBloodFlow(BodyPart.Segments.DeepVein)); if (hasAVA) bmMatrix.SetValue(bmMatrix.Columns - 1, startPoint + 5, -RCS * part.GetBloodFlow(BodyPart.Segments.SuperficialVein)); coreSum += RCS * part.GetBloodFlow(BodyPart.Segments.DeepVein) + RCS * part.GetBloodFlow(BodyPart.Segments.SuperficialVein); } //静脈血流による熱移動 List<BodyPart> ptts = part.bpConnectTo; foreach (BodyPart ptt in ptts) { uint stp2 = bpDict[ptt.Position]; //深部静脈血流による熱移動 bmMatrix.SetValue(startPoint + 4, stp2 + 4, -RCS * ptt.GetBloodFlow(BodyPart.Segments.DeepVein)); //表在静脈血流による熱移動 if (part.Position == Nodes.Pelvis) { //腰部の場合は深部静脈に流れ込む bmMatrix.SetValue(startPoint + 4, stp2 + 5, -RCS * ptt.GetBloodFlow(BodyPart.Segments.SuperficialVein)); } else { //腰部以外の場合は表在静脈に流れ込む if(ptt.GetHeatCapacity(BodyPart.Segments.SuperficialVein) != 0) bmMatrix.SetValue(startPoint + 5, stp2 + 5, -RCS * ptt.GetBloodFlow(BodyPart.Segments.SuperficialVein)); } } } //中央血液だまりに関する行列要素を設定 bmMatrix.SetValue(bmMatrix.Columns - 1, bmMatrix.Columns - 1, coreSum); zmVector.SetValue(zmVector.Size - 1, HeatCapacity_CentralBloodPool * 3600 * CentralBloodPoolTemperature / timeStep); //胸部に関して呼吸による項を設定 double wlSum = 0; foreach(Nodes bp in parts.Keys) wlSum += parts[bp].WorkLoad + parts[bp].ShiveringLoad; BodyPart head = parts[Nodes.Head]; HeatLossByBreathing = (0.0014 * (34 - head.DrybulbTemperature) + 0.0173 * (5.867 - getVaporPressure(head.DrybulbTemperature, head.RelativeHumidity, 101.325))) * (wlSum + BasicMetabolicRate); zmVector.AddValue(bpDict[Nodes.Chest], -HeatLossByBreathing); //逆行列を計算 for (uint i = 0; i < perm.Length; i++) perm[i] = i; bmMatrix.LUDecomposition(); bmMatrix.LUSolve(ref zmVector); //LinearAlgebra.LUDecomposition(ref bmMatrix, ref perm); //LinearAlgebra.LUSolve(bmMatrix, perm, ref zmVector); //温度を更新・設定 foreach (Nodes bp in parts.Keys) { BodyPart part = parts[bp]; uint size = 5; if (!part.IsJOSModel) size += 2; if (part.GetHeatCapacity(BodyPart.Segments.SuperficialVein) != 0) size += 1; zmView = new Vector(size, bpDict[bp], zmVector); part.setTemperature(zmView); } CentralBloodPoolTemperature = zmVector.GetValue(zmVector.Size - 1); }
/// <summary>初期化処理</summary> /// <param name="weight">体重[kg]</param> /// <param name="height">身長[m]</param> /// <param name="age">年齢</param> /// <param name="isMale">男性か否か</param> /// <param name="cardiacIndexAtRest">安静時の心係数[L/(min m^2)]</param> /// <param name="fatPercentage">体脂肪率[%]</param> private void initialize(double weight, double height, double age, bool isMale, double cardiacIndexAtRest, double fatPercentage) { Weight = weight; Height = height; Age = age; IsMale = isMale; CardiacIndexAtRest = cardiacIndexAtRest; FatPercentage = fatPercentage; //体表面積を初期化する SurfaceArea = 0.202 * Math.Pow(Weight, 0.425) * Math.Pow(Height, 0.725); //代謝量[W]を初期化する initMetabolicRate(); //血流量[L/h]を初期化する BaseBloodFlowRate = cardiacIndexAtRest * 60 * SurfaceArea; //中央血液だまりの熱容量[Wh/K]を初期化する HeatCapacity_CentralBloodPool = 1.999 * CardiacIndexAtRest * 60 * SurfaceArea / STANDARD_BLOOD_FLOW; //部位を作成 Nodes[] pos = (Nodes[])Enum.GetValues(typeof(Nodes)); foreach (Nodes bp in pos) { if (bp != Nodes.TerminalPart && bp != Nodes.None) { parts.Add(bp, new BodyPart(this, bp)); } } //部位を接続 parts[Nodes.Neck].connect(parts[Nodes.Head]); parts[Nodes.Pelvis].connect(parts[Nodes.LeftThigh]); parts[Nodes.Pelvis].connect(parts[Nodes.RightThigh]); parts[Nodes.LeftThigh].connect(parts[Nodes.LeftLeg]); parts[Nodes.RightThigh].connect(parts[Nodes.RightLeg]); parts[Nodes.LeftLeg].connect(parts[Nodes.LeftFoot]); parts[Nodes.RightLeg].connect(parts[Nodes.RightFoot]); parts[Nodes.LeftShoulder].connect(parts[Nodes.LeftArm]); parts[Nodes.RightShoulder].connect(parts[Nodes.RightArm]); parts[Nodes.LeftArm].connect(parts[Nodes.LeftHand]); parts[Nodes.RightArm].connect(parts[Nodes.RightHand]); //姿勢を設定 SetPosture(BodyPosture.Standing); //仕事量を設定 SetWorkLoad(58); //気流速度[m/s]を設定 SetVelocity(0); //着衣量[clo]を設定 SetClothingIndex(Nodes.Chest, 0.62); SetClothingIndex(Nodes.Back, 0.74); SetClothingIndex(Nodes.Pelvis, 1.18); SetClothingIndex(Nodes.LeftShoulder, 0.45); SetClothingIndex(Nodes.RightShoulder, 0.45); SetClothingIndex(Nodes.LeftThigh, 0.38); SetClothingIndex(Nodes.LeftLeg, 0.69); SetClothingIndex(Nodes.LeftFoot, 1.23); SetClothingIndex(Nodes.RightThigh, 0.38); SetClothingIndex(Nodes.RightLeg, 0.69); SetClothingIndex(Nodes.RightFoot, 1.23); //体温を初期化 InitializeTemperature(36); //行列初期化 uint varSum = 0; foreach (Nodes bp in parts.Keys) { bpDict.Add(bp, varSum); varSum += 5; BodyPart part = parts[bp]; //筋肉・脂肪・コアを統合するJOSモデルではない場合 if (!part.IsJOSModel) varSum += 2; //AVAによる表在静脈がある場合 if (part.GetHeatCapacity(BodyPart.Segments.SuperficialVein) != 0) varSum += 1; } //計算領域初期化 varSum++; bmMatrix = new Matrix(varSum, varSum); zmVector = new Vector(varSum); perm = new uint[varSum]; //セットポイント初期化 initializeSetPoint(); }
/// <summary>室の乾球温度を更新する</summary> public void UpdateRoomTemperatures() { //タイムステップ確認 if (!isTimeStepCorrect()) throw new Exception("計算時間間隔が不正です"); //壁および窓の構成が変化した場合には逆行列を初期化 if (hasFIOChanged) makeXAMatrix(); //各Roomの放射を壁面に設定 setRadiationToSurface(); //壁表面計算用行列を作成 makeARMatrixAndCAVector(); //行列入れ替え配列を作成 uint ffZones = makePermVectorDB(); //Bマトリクス・Bベクトル・Tマトリクスを作成 for (uint i = 0; i < zones.Length; i++) { //Bマトリクスを作成 //ゾーンの熱容量/時間間隔[W/K]を計算 double airSV = MoistAir.GetAirStateFromDBHR(zones[i].CurrentDrybulbTemperature, zones[i].CurrentHumidityRatio, MoistAir.Property.SpecificVolume); double cpAir = MoistAir.GetSpecificHeat(zones[i].CurrentHumidityRatio) * 1000; double zSH = (zones[i].Volume / airSV * cpAir + zones[i].SensibleHeatCapacity) / TimeStep; double cgo = zones[i].VentilationVolume / airSV / 3600d * cpAir; Dictionary<ImmutableZone, double> aFlow = airFlowToZone[zones[i]]; for (uint j = 0; j < zones.Length; j++) { double cgr = 0; //対角成分 if (i == j) { foreach (Zone key in aFlow.Keys) cgr += aFlow[key]; cgr = cgr / airSV / 3600d * cpAir; bMatrix.SetValue(arbPerm[i], arbPerm[j], zSH + arMatrix[i, j] + cgo + cgr); } //その他成分 else { if (aFlow.ContainsKey(zones[j])) cgr = aFlow[zones[j]] / airSV / 3600d * cpAir; else cgr = 0; bMatrix.SetValue(arbPerm[i], arbPerm[j], -(arMatrix[i, j] + cgr)); } } //Bベクトル・Tマトリクス bVector.SetValue(arbPerm[i], zSH * zones[i].CurrentDrybulbTemperature + caVector[i] + cgo * zones[i].VentilationAirState.DryBulbTemperature + zones[i].integrateConvectiveHeatGain()); if (zones[i].ControlDrybulbTemperature) { tzVector.SetValue(arbPerm[i], zones[i].DrybulbTemperatureSetPoint); } else { bVector.AddValue(arbPerm[i], zones[i].SensibleHeatSupply); //-供給熱量[W]が即ち熱負荷[W] zones[i].CurrentSensibleHeatLoad = -zones[i].SensibleHeatSupply; } } //定数部分を差し引く uint ccZones = (uint)(zones.Length - ffZones); for (uint i = 0; i < ffZones; i++) { double br = bVector.GetValue(i); for (uint j = 0; j < ccZones; j++) { br -= bMatrix.GetValue(i, j + ffZones) * tzVector.GetValue(j + ffZones); } bVector.SetValue(i, br); } //MatrixView mView = new MatrixView(bMatrix, 0, 0, ffZones, ffZones); //VectorView bView = new VectorView(bVector, 0, ffZones); //VectorView tView = new VectorView(tzVector, 0, ffZones); Matrix mView = new Matrix(ffZones, ffZones, 0, 0, bMatrix); Vector bView = new Vector(ffZones, 0, bVector); Vector tView = new Vector(ffZones, 0, tzVector); //空気温度が変動するゾーンを逆行列で解く if (0 < ffZones) { Matrix xmView = new Matrix(ffZones, ffZones, 0, 0, xbMatrix); mView.GetInverse(ref xmView); xmView.VectorProduct(bView, ref tView, 1, 0); } //温度をゾーンに設定 for (uint i = 0; i < zones.Length; i++) zones[i].setDrybulbTemperature(tzVector.GetValue(arbPerm[i])); if (0 < ccZones) { //空気温度指定ゾーンの熱負荷を計算 //ゾーン空気温度に依存する成分 mView = new Matrix(ccZones, (uint)zones.Length, ffZones, 0, bMatrix); tView = new Vector(tzVector.Size, 0, tzVector); bView = new Vector(ccZones, ffZones, bbVector); mView.VectorProduct(tView, ref bView, 1, 0); // for (uint i = 0; i < zones.Length; i++) { if (zones[i].ControlDrybulbTemperature) { zones[i].CurrentSensibleHeatLoad = -(bbVector.GetValue(arbPerm[i]) - bVector.GetValue(arbPerm[i])); } } } //表面温度を計算する surfaceTemperatures.SetValue(0); foreach (Zone spc in rxVector.Keys) { Vector vec = raVector[spc]; for (uint i = 0; i < vec.Size; i++) surfaceTemperatures.AddValue(i, vec.GetValue(i) * spc.CurrentDrybulbTemperature); } for (uint i = 0; i < craVector.Size; i++) surfaceTemperatures.AddValue(i, craVector.GetValue(i)); //室温を表面に設定 for (int i = 0; i < zones.Length; i++) { ISurface[] sfs = zones[i].getSurfaces(); for (int j = 0; j < sfs.Length; j++) { //表面近傍の空気温度を設定 sfs[j].AirTemperature = zones[i].CurrentDrybulbTemperature * sfs[j].ConvectiveRate; } } //放射を表面に設定 phi.VectorProduct(surfaceTemperatures, ref surfaceMRTs, 1, 0); for (uint i = 0; i < surfaces.Length; i++) { surfaces[i].Radiation += surfaceMRTs.GetValue(i) * surfaces[i].FilmCoefficient; } //平均放射温度[C]を計算して設定 foreach (Room room in rooms) { ImmutableSurface[] sfs = room.GetSurface(); double mrt = 0; double aSum = 0; for (int i = 0; i < sfs.Length; i++) { mrt += sfs[i].Temperature * sfs[i].Area; aSum += sfs[i].Area; } mrt /= aSum; Zone[] zns = room.getZone(); for (int i = 0; i < zns.Length; i++) zns[i].setMeanRadiantTemperature(mrt); } }
/// <summary>室の絶対湿度を更新する</summary> public void UpdateRoomHumidities() { //行列入れ替え配列を作成 uint ffZones = makePermVectorAH(); //Bマトリクス・Bベクトル・Tマトリクスを作成 for (uint i = 0; i < zones.Length; i++) { //Bマトリクスを作成 //ゾーンの水蒸気容量/時間間隔[W/K]を計算 double airSV = MoistAir.GetAirStateFromDBHR(zones[i].CurrentDrybulbTemperature, zones[i].CurrentHumidityRatio, MoistAir.Property.SpecificVolume); double zSH = (zones[i].Volume / airSV + zones[i].LatentHeatCapacity) / TimeStep; double cgo = zones[i].VentilationVolume / airSV / 3600d; Dictionary<ImmutableZone, double> aFlow = airFlowToZone[zones[i]]; for (uint j = 0; j < zones.Length; j++) { double cgr = 0; //対角成分 if (i == j) { foreach (Zone key in aFlow.Keys) cgr += aFlow[key]; cgr = cgr / airSV / 3600d; bMatrix.SetValue(arbPerm[i], arbPerm[j], zSH + cgo + cgr); } //その他成分 else { if (aFlow.ContainsKey(zones[j])) cgr = aFlow[zones[j]] / airSV / 3600d; else cgr = 0; bMatrix.SetValue(arbPerm[i], arbPerm[j], -cgr); } } //Bベクトル・Tマトリクス bVector.SetValue(arbPerm[i], zSH * zones[i].CurrentHumidityRatio + cgo * zones[i].VentilationAirState.HumidityRatio + zones[i].integrateLatentHeatGain() / MoistAir.LatentHeatOfVaporization / 1000); if (zones[i].ControlHumidityRatio) { tzVector.SetValue(arbPerm[i], zones[i].HumidityRatioSetPoint); } else { bVector.AddValue(arbPerm[i], zones[i].LatentHeatSupply / MoistAir.LatentHeatOfVaporization / 1000); //-供給熱量[W]が即ち熱負荷[W] zones[i].CurrentLatentHeatLoad = -zones[i].LatentHeatSupply; } } //定数部分を差し引く uint ccZones = (uint)(zones.Length - ffZones); for (uint i = 0; i < ffZones; i++) { double br = bVector.GetValue(i); for (uint j = 0; j < ccZones; j++) { br -= bMatrix.GetValue(i, j + ffZones) * tzVector.GetValue(j + ffZones); } bVector.SetValue(i, br); } //MatrixView mView = new MatrixView(bMatrix, 0, 0, ffZones, ffZones); //VectorView bView = new VectorView(bVector, 0, ffZones); //VectorView tView = new VectorView(tzVector, 0, ffZones); Matrix mView = new Matrix(ffZones, ffZones, 0, 0, bMatrix); Vector bView = new Vector(ffZones, 0, bVector); Vector tView = new Vector(ffZones, 0, tzVector); //空気湿度が変動するゾーンを逆行列で解く if (0 < ffZones) { //int sig; Matrix xmView = new Matrix(ffZones, ffZones, 0, 0, xbMatrix); mView.GetInverse(ref xmView); xmView.VectorProduct(bView, ref tView, 1, 0); } //絶対湿度をゾーンに設定 for (uint i = 0; i < zones.Length; i++) zones[i].setHumidityRatio(tzVector.GetValue(arbPerm[i])); if (0 < ccZones) { //絶対湿度指定ゾーンの熱負荷を計算 //ゾーン絶対湿度に依存する成分 //mView.Initialize(bMatrix, ffZones, 0, ccZones, (uint)zones.Length); //tView.Initialize(tzVector, 0, tzVector.Size); //bView.Initialize(bbVector, ffZones, ccZones); mView = new Matrix(ccZones, (uint)zones.Length, ffZones, 0, bMatrix); tView = new Vector(tzVector.Size, 0, tzVector); bView = new Vector(ccZones, ffZones, bbVector); //Blas.DGemv(Blas.TransposeType.NoTranspose, 1, mView, tView, 0, ref bView); mView.VectorProduct(tView, ref bView, 1, 0); // for (uint i = 0; i < zones.Length; i++) { if (zones[i].ControlHumidityRatio) { zones[i].CurrentLatentHeatLoad = - MoistAir.LatentHeatOfVaporization * 1000 * (bbVector.GetValue(arbPerm[i]) - bVector.GetValue(arbPerm[i])); } } } }
/// <summary>初期化処理</summary> public void Initialize() { sfNumber = new uint[rooms.Length]; znNumber = new uint[rooms.Length]; //壁表面とゾーンの数を積算 uint sfSum = 0; uint sfZnSum = 0; uint znSum = 0; List<ISurface> sfs = new List<ISurface>(); List<Zone> zns = new List<Zone>(); for (int i = 0; i < rooms.Length; i++) { //AX行列におけるRoom要素の開始列数 if(axRmIndices.ContainsKey(rooms[i])) axRmIndices[rooms[i]] = sfSum; else axRmIndices.Add(rooms[i], sfSum); //壁表面数 sfNumber[i] = rooms[i].SurfaceNumber; sfSum += rooms[i].SurfaceNumber; //ゾーン数 znNumber[i] = rooms[i].ZoneNumber; znSum += rooms[i].ZoneNumber; zns.AddRange(rooms[i].getZone()); for (uint j = 0; j < rooms[i].ZoneNumber; j++) { Zone zn = rooms[i].getZone(j); if (znToRm.ContainsKey(zn)) znToRm[zn] = rooms[i]; else znToRm.Add(zn, rooms[i]); //AX行列におけるZone要素の開始列数 if (axZnIndices.ContainsKey(zn)) axZnIndices[zn] = sfZnSum; else axZnIndices.Add(zn, sfZnSum); sfZnSum += (uint)zn.Surfaces.Length; } //壁表面リスト sfs.AddRange(rooms[i].getSurface()); for (uint j = 0; j < rooms[i].SurfaceNumber; j++) { if (sfToRm.ContainsKey(rooms[i].getSurface(j))) sfToRm[rooms[i].getSurface(j)] = rooms[i]; else sfToRm.Add(rooms[i].getSurface(j), rooms[i]); } } surfaces = sfs.ToArray(); zones = zns.ToArray(); //行列・ベクトルのメモリ領域を用意 tzVector = new Vector(znSum); arbPerm = new uint[znSum]; arMatrix = new double[znSum, znSum]; bMatrix = new Matrix(znSum, znSum); xa = new Matrix(sfSum, sfSum); phi = new Matrix(sfSum, sfSum); surfaceTemperatures = new Vector(sfSum); surfaceMRTs = new Vector(sfSum); crxVector = new Vector(sfSum); craVector = new Vector(sfSum); caVector = new double[znSum]; bMatrix = new Matrix(znSum, znSum); xbMatrix = new Matrix(znSum, znSum); bVector = new Vector(znSum); bbVector = new Vector(znSum); for (int i = 0; i < rooms.Length; i++) { for (uint j = 0; j < rooms[i].ZoneNumber; j++) { if(! rxVector.ContainsKey(rooms[i].getZone(j))) rxVector.Add(rooms[i].getZone(j), new Vector(sfSum)); if (!raVector.ContainsKey(rooms[i].getZone(j))) raVector.Add(rooms[i].getZone(j), new Vector(sfSum)); } } for (int i = 0; i < zones.Length; i++) { if (!airFlowToZone.ContainsKey(zones[i])) airFlowToZone.Add(zones[i], new Dictionary<ImmutableZone, double>()); } //表面温度計算式の逆行列を計算する makeXAMatrix(); //壁および窓構成変更イベントへの対応 foreach (ISurface sf in surfaces) { sf.FIOChangeEvent += new EventHandler(sf_FIOChangeEvent); } }