概述
一、Eclipse油藏数值模拟源文件介绍:
--
-- -----------------------------------------------------------------------------
-- Office Simulation File (DATA) Data Section Version 2011.1 May 6 2011
-- -----------------------------------------------------------------------------
--
-- Created on: 2015-May-04 at: 11:24:17
--
-- *****************************************************************************
-- * WARNING *
-- * THIS FILE HAS BEEN AUTOMATICALLY GENERATED. *
-- * ANY ATTEMPT TO EDIT MANUALLY MAY RESULT IN INVALID DATA. *
-- *****************************************************************************
--
RUNSPEC
TITLE
Case
START
01 'JAN' 2010 /
DIMENS
9 9 6 /
FIELD
GAS
OIL
WATER
DISGAS
AQUDIMS
1 1 1 36 1 1 1 0 /
EQLDIMS
1 100 100 1 20 /
TABDIMS
1 1 20 20 1 20 20 1 1 1* 1 1 1* 1* /
VFPPDIMS
0 0 0 0 0 0 /
VFPIDIMS
0 0 0 /
FMTOUT
GRID
INCLUDE
'Case_grid.inc' /
PROPS
INCLUDE
'Case_pvt.inc' /
INCLUDE
'Case_rp.inc' /
REGIONS
INCLUDE
'Case_regs.inc' /
SOLUTION
INCLUDE
'Case_init.inc' /
SUMMARY
INCLUDE
'Case_sum.inc' /
SCHEDULE
INCLUDE
'Case_sch.inc' /
END
说明:其中INCLUDE关键字嵌套其他文件
思路:RUNSPEC、INCLUDE等视为一个关键字,定义成一个类型
二、处理数模文件功能设计
1、关键字抽象基类介绍
所有关键字的基类
2、实体关键字的抽象关系
应用封装继承多态增加扩展性和重用性
三、主要存在的文件和处理方法
1、问题:关键字好几千种,解析工作量大
处理方法:将关键字定义成一个类型,具有相似解析方法的关键字共同继承一个抽象基类,抽象基类封装解析规则,同时减少新增关键字解析的工作量;
示例:
说明:NTG和PORO是具有相同读取规则的关键字,共同继承TableKey抽象类复用规则;
2、问题:关键字内容格式写法多样,需要兼容多种写法,通用解析比较困难
处理方法:共同的解析方法封装在抽象基类中,不同的解析方法通过重写抽象基类中抽象方法实现兼容;
说明:PBVD和ROCK关键字公用RegionKey抽象类解析方法,定义不同的Item实现不同的列数据,重写Build方法或使用委托规则外挂的方式实现不同的转换规则;
3、关键字间关系紧密复杂,多个关键字共同构成一个业务,需要保证一致性完整性
处理方法:将基础业务封装成通用服务,针对不同模拟器的业务封装在上层业务中,实现通用部分重用,特殊业务部分扩展;
说明:ServiceFactory基类主要实现单例,缓存;
四、设计结构示意图
按三层架构划分
1、实体数据:
主要是处理数模原始文件(可以理解为数据库)
2、数据层:
关键字数据实体:以关键字为一个最小单元定义成一个实体(可以理解为一张表,多种数模文件可共用或重写相同名称关键字);
数模文件数据结构:将数模原始文件关键字信息组装到数模文件数据结构 (主要作为一个引擎,存储控制参数、构建关键字的树形逻辑关系,负责读取原始文件,保存原始文件等操作,多种模拟器实现扩展) 中;
数据层通用服务:将通用的增删改查、可复用的业务封装成服务(如:重启、输出、生产数据处理、文件加载等);
3、业务逻辑层:
主要针对各自的业务特征,应用数据层通用服务和扩展特定的业务,拼装组合数模关键字绑定到表现层;
主要逻辑:加载数模文件,切换流体模型,切换单位,切换介质类型,更改网格范围,分区处理,多种关键字切换配置,导入第三方地质模型,断层模型,读取数据源,生产数据统计,重启信息生成加载,保存数模文件等等;
加载流程:通过数据层将数模文件加载到内存中,根据关键字信息更新配置文件,根据配置文件生成树结构;
操作流程:通过配置界面更改配置文件,生成对应的树结构,实现业务切换;
保存流程:根据树结构保存关键字到数据层中,将数据层中数据保存到数模文件;
4、表现层:
复用性方面:以关键字为基本单元,关键字信息基本不会改变,定义后其他模型均可以复用,数据层封装通用服务,通过服务复用,以关键字形式存储的数模文件可以复用通用读法;
扩展性方面:数模中的一套逻辑大致由一系列关键字组成,对于新加的功能可以看做增加一些关键字,而以关键字为基本类型的解析方法可以支持无限扩展,对于结构相似的关键字可以继承扩展;
维护性方面:关键字是通用的,且有公用文档参考,对于更换开发人员只需对关键字了解即可做出维护;
示例:BaseKey代码
/// <summary> 关键字基类 包含子节点 父节点 文件基类一级基本读写方法 </summary>
public partial class BaseKey : IDisposable
{
#region - 关键字成员属性 -
public BaseKey(string pname)
{
name = pname;
this.ID = Guid.NewGuid().ToString();
}
BaseFile baseFile = null;
/// <summary> 文件基类 </summary>
[Browsable(false), ReadOnly(true)]
public BaseFile BaseFile
{
get { return baseFile; }
set { baseFile = value; }
}
List<BaseKey> keys = new List<BaseKey>();
/// <summary> 子关键字 </summary>
[Browsable(false), ReadOnly(true)]
public List<BaseKey> Keys
{
get { return keys; }
set { keys = value; }
}
private BaseKey parentKey;
/// <summary> 父节点 </summary>
[Browsable(false), ReadOnly(true)]
public BaseKey ParentKey
{
get { return parentKey; }
set { parentKey = value; }
}
string _ID;
/// <summary> 关键字的唯一标识 </summary>
[Browsable(false), ReadOnly(true)]
public string ID
{
get { return _ID; }
set { _ID = value; }
}
string pid;
[Browsable(false), ReadOnly(true)]
public string Pid
{
get
{
return parentKey == null ? string.Empty : parentKey.ID;
}
set { parentKey.ID = value; }
}
string name;
/// <summary> 关键字 </summary>
[Browsable(false), ReadOnly(true)]
public string Name
{
get { return name; }
set { name = value; }
}
List<string> lines = new List<string>();
/// <summary> 关键字内容 </summary>
//[Browsable(false), ReadOnly(true)]
public List<string> Lines
{
get { return lines; }
set { lines = value; }
}
bool isUnKnowKey = false;
/// <summary> 是否解析 true为解析 </summary>
public bool IsUnKnowKey
{
get
{
isUnKnowKey = !(this is UnkownKey);
return isUnKnowKey;
}
set { isUnKnowKey = value; }
}
string titleStr;
/// <summary> 描述信息 </summary>
public string TitleStr
{
get { return titleStr; }
set { titleStr = value; }
}
private ReadState _runState;
/// <summary> 解析状态 </summary>
public ReadState RunState
{
get { return _runState; }
set { _runState = value; }
}
Predicate<string> _match = l => KeyChecker.IsKeyFormat(l);
/// <summary> 当前关键字定义的检验是否为普通未识别关键字的方法 </summary>
[Browsable(false), ReadOnly(true)]
public Predicate<string> Match
{
get { return _match; }
set { _match = value; }
}
Action<BaseKey, BaseKey> _createrHandler = BaseKeyHandleFactory.Instance.AddNodeHandler;
/// <summary> 创建节点结构关系 T1本节点 T2下一节点 </summary>
[Browsable(false), ReadOnly(true)]
public Action<BaseKey, BaseKey> CreaterHandler
{
get { return _createrHandler; }
set { _createrHandler = value; }
}
Func<BaseKey, BaseKey, BaseKey> _builderHandler = BaseKeyHandleFactory.Instance.InitLineHandler;
/// <summary> 读取到下一关键字前要做的处理方法 T1上一节点 T2下一节点 T3 构建返回的节点一般是本节点 DATES特殊情况 </summary>
[Browsable(false), ReadOnly(true)]
public Func<BaseKey, BaseKey, BaseKey> BuilderHandler
{
get { return _builderHandler; }
set { _builderHandler = value; }
}
Action<string> _readNewLineHandler;
/// <summary> 当读取到一行信息触发 </summary>
public Action<string> ReadNewLineHandler
{
get { return _readNewLineHandler; }
set { _readNewLineHandler = value; }
}
private Func<string, string> eachLineCmdHandler = BaseKeyHandleFactory.Instance.EachLineCmdHandler;
/// <summary> 每到一行,对这一行进行的处理 </summary>
public Func<string, string> EachLineCmdHandler
{
get { return eachLineCmdHandler; }
set { eachLineCmdHandler = value; }
}
private Predicate<string> _isKeyChar = BaseKeyHandleFactory.Instance.IsKeyFormat;
/// <summary> 当前关键字下判断子内容是否是关键字的方法 </summary>
public Predicate<string> IsKeyChar
{
get { return _isKeyChar; }
set { _isKeyChar = value; }
}
#endregion
#region - 关键字操作方法 -
/// <summary> 写关键字 </summary>
public virtual void WriteKey(StreamWriter writer)
{
BaseKey index = null;
// 写本行
foreach (var str in this.lines)
{
writer.WriteLine(str);
}
// 写子关键字
foreach (BaseKey key in this.keys)
{
key.WriteKey(writer);
}
}
/// <summary> 读取关键字内容 (具体关键字读取方法不同) return 用于关键字传递 </summary>
public virtual BaseKey ReadKeyLine(StreamReader reader)
{
string tempStr = string.Empty;
#region - 读取数据 -
while (!reader.EndOfStream)
{
// HTodo :读取数据要处理的方法 一般用来截取前面空格判断是否解析成关键字
tempStr = this.eachLineCmdHandler(reader.ReadLine());
try
{
// HTodo :当前关键字用来判断文本是否为关键字的方法
if (this.IsKeyChar(tempStr))
{
#region - 交接关键字 -
// Todo :没有找到主文件默认Eclipse关键字
SimKeyType typesim = this.baseFile == null ? SimKeyType.Eclipse : this.baseFile.SimKeyType;
BaseKey newKey = KeyConfigerFactroy.Instance.CreateKey<BaseKey>(tempStr, typesim);
LogProviderHandler.Instance.OnRunLog("", "正在读取关键字 - " + newKey.Name);
BaseKey perTempKey = this;
if (this._builderHandler != null)
{
// Todo :当碰到新关键字 触发本节点构建方法
BaseKey temp = this._builderHandler.Invoke(this, newKey);
if (temp != null)
{
perTempKey = temp;
}
if (this.baseFile != null && this is IProductTime)
{
// HTodo :将读取到的生产信息记录到主文件中,用于解析TSTEP
IProductTime p = this as IProductTime;
this.baseFile.ReadTempTime = p.DateTime;
}
}
if (newKey._createrHandler != null)
{
// Todo :触发新关键字构建节点结构的方法
newKey._createrHandler.Invoke(perTempKey, newKey);
}
// Todo :读到未解析关键字触发事件
if (newKey is UnkownKey)
{
// Todo :触发事件
if (newKey.BaseFile != null && newKey.BaseFile.OnUnkownKey != null)
{
newKey.BaseFile.OnUnkownKey(newKey.BaseFile, newKey);
}
}
// Todo :开始读取新关键字
newKey.ReadKeyLine(reader);
#endregion
}
else
{
#region - 记录数据 -
if (tempStr.IsNotExcepLine())
{
if (this.ReadNewLineHandler == null)
{
// Todo :当前关键字没有实时读取方法
this.Lines.Add(tempStr);
}
else
{
// Todo :当前关键字实现实时读取方法
this.ReadNewLineHandler(tempStr);
}
}
#endregion
}
}
catch (Exception ex)
{
LogProviderHandler.Instance.OnErrLog("读取关键字" + this.GetType().Name + "错误!", ex);
}
finally
{
}
}
#endregion
return this;
}
#endregion
#region - 关键字查询操作 -
/// <summary> 是否相等(只比较名称) </summary>
public override bool Equals(object obj)
{
if (!(obj is BaseKey)) return false;
BaseKey pKey = obj as BaseKey;
return pKey.ID.Equals(this.ID);
}
/// <summary> 递归获取节点 match1 = 查找匹配条件 match2 = 结束查找匹配条件 </summary>
public bool GetKeys<T>(ref List<T> findKey, BaseKey key, Predicate<BaseKey> match, Predicate<BaseKey> endOfMatch) where T : class
{
if (endOfMatch(key))
{
return true;
}
if (match(key) && key is T)
{
T find = key as T;
findKey.Add(find);
}
if (key.Keys.Count > 0)
{
foreach (var k in key.Keys)
{
if (k is BaseKey)
{
BaseKey kn = k as BaseKey;
// 递归处
bool isEndOfMatch = GetKeys(ref findKey, kn, match, endOfMatch);
if (isEndOfMatch) return true;
}
}
}
return false;
}
/// <summary> 查找所有匹配类型和匹配规则的项 </summary>
public List<T> FindAll<T>(Predicate<T> match) where T : class
{
Predicate<BaseKey> m = l =>
{
if (l is T)
{
T t = l as T;
return match(t);
}
return false;
};
List<T> findKeys = new List<T>();
// l=>false 一直查询
GetKeys<T>(ref findKeys, this, m, l => false);
return findKeys;
}
/// <summary> 查找所有关键字类型 </summary>
public List<T> FindAll<T>() where T : class
{
return FindAll<T>(l => l is T);
}
/// <summary> 对每个节点执行方法 </summary>
public void Foreach(Action<BaseKey> act)
{
// 执行方法
act(this);
// 子节点执行方法
if (this.Keys.Count > 0)
{
foreach (BaseKey k in this.Keys)
{
// 递归处
k.Foreach(act);
}
}
}
/// <summary> 对指定类型的节点执行方法 </summary>
public void Foreach<T>(Action<BaseKey> act) where T : BaseKey
{
if (this is T)
{
// 执行方法
act(this);
}
// 子节点执行方法
if (this.Keys.Count > 0)
{
foreach (BaseKey k in this.Keys)
{
// 递归处
k.Foreach(act);
}
}
}
/// <summary> 获取匹配的一个节点 找到一个立即返回 </summary>
T GetKeys<T>(BaseKey key, Predicate<BaseKey> match) where T : class
{
if (match(key) && key is T)
{
T find = key as T;
return find;
}
if (key.Keys.Count > 0)
{
foreach (var k in key.Keys)
{
if (k is BaseKey)
{
BaseKey kn = k as BaseKey;
T temp = GetKeys<T>(kn, match);
// 递归处
if (temp != null)
{
return temp;
}
}
}
return null;
}
else
{
return null;
}
}
/// <summary> 查找所有关键字类型 </summary>
public T Find<T>() where T : BaseKey
{
return this.Find<T>(l => true);
}
/// <summary> 查找所有关键字类型 按基类BaseKey查找 </summary>
public T Find<T>(Predicate<T> match) where T : BaseKey
{
Predicate<BaseKey> m = l =>
{
if (l is T)
{
T t = l as T;
return match(t);
}
return false;
};
return GetKeys<T>(this, m);
}
/// <summary> 查找关键字类型最后一个 按泛型查找 </summary>
public T FindLast<T>(Predicate<T> match) where T : BaseKey
{
Predicate<BaseKey> m = l =>
{
if (l is T)
{
T t = l as T;
return match(t);
}
return false;
};
var fs = this.FindAll<T>(m);
if (fs != null && fs.Count > 0) return fs.Last();
return null;
}
/// <summary> 移除 </summary>
public void Delete(BaseKey key)
{
this.keys.Remove(key);
}
/// <summary> 移除 </summary>
public void Delete()
{
this.parentKey.Delete(this);
}
/// <summary> 删除所有节点 (不是父节点也删除) </summary>
public void DeleteAll<T>(List<T> keys) where T : BaseKey
{
if (keys == null || keys.Count == 0) return;
foreach (T b in keys) // 注:这个删除方法用迭代器删除可能会有问题
{
b.Delete();
}
}
/// <summary> 删除所有类型节点) </summary>
public void DeleteAll<T>() where T : BaseKey
{
var keys = this.FindAll<T>();
foreach (var v in keys)
{
if (v.parentKey != null)
{
v.parentKey.Delete(v);
}
}
}
/// <summary> 删除所有类型节点 </summary>
public void DeleteAll<T>(Predicate<T> match) where T : BaseKey
{
var keys = this.FindAll<T>();
foreach (var v in keys)
{
if (!match(v)) continue;
if (v.parentKey != null)
{
v.parentKey.Delete(v);
}
}
}
/// <summary> 插入节点到指定位置 </summary>
public void InsertKey(int index, BaseKey key)
{
this.keys.Insert(index, key);
key.parentKey = this;
this.Lines.Add(key.ID);
key.baseFile = this.baseFile;
}
/// <summary> 插入在指定节点后 </summary>
public bool InsertAfter(BaseKey key, BaseKey inKey)
{
BaseKey parentKey = key.parentKey;
inKey.parentKey = parentKey;
if (parentKey == null)
{
return false;
}
else
{
int findKey = parentKey.Keys.FindIndex(l => l.Equals(key));
// 找到到当前行的占位标记
int findLine = parentKey.lines.FindIndex(l => l == key.ID);
if (findKey == -1 || findLine == -1)
{
return false;
}
else
{
parentKey.Keys.Insert(findKey + 1, inKey);
parentKey.lines.Insert(findLine + 1, inKey.ID);
return true;
}
}
}
/// <summary> 插入在本节点后 </summary>
public bool InsertAfter(BaseKey inKey)
{
BaseKey parentKey = this.parentKey;
inKey.parentKey = parentKey;
if (parentKey == null)
{
return false;
}
else
{
int findKey = parentKey.Keys.FindIndex(l => l.Equals(this));
找到到当前行的占位标记
//int findLine = parentKey.lines.FindIndex(l => l == this.ID);
if (findKey == -1)
{
return false;
}
else
{
parentKey.Keys.Insert(findKey + 1, inKey);
return true;
}
}
}
/// <summary> 插入在指定节点前 </summary>
public bool InsertBefore(BaseKey key, BaseKey inKey)
{
BaseKey parentKey = key.parentKey;
inKey.parentKey = parentKey;
if (parentKey == null)
{
return false;
}
else
{
// 当前关键字标记
int findKey = parentKey.Keys.FindIndex(l => l.Equals(key));
// 找到到当前行的占位标记
int findLine = parentKey.lines.FindIndex(l => l == key.ID);
if (findKey == -1 || findLine == -1)
{
return false;
}
else
{
parentKey.Keys.Insert(findKey, inKey);
parentKey.lines.Insert(findLine, inKey.ID);
return true;
}
}
}
/// <summary> 插入在本节点前 </summary>
public bool InsertBefore(BaseKey inKey)
{
BaseKey parentKey = this.parentKey;
inKey.parentKey = parentKey;
if (parentKey == null)
{
return false;
}
else
{
// 当前关键字标记
int findKey = parentKey.Keys.FindIndex(l => l.Equals(this));
// 找到到当前行的占位标记
//int findLine = parentKey.lines.FindIndex(l => l == this.ID);
if (findKey == -1)//|| findLine == -1
{
return false;
}
else
{
parentKey.Keys.Insert(findKey, inKey);
//parentKey.lines.Insert(findLine, inKey.ID);
return true;
}
}
}
/// <summary> 是否存在关键字 </summary>
public bool Exist(string key)
{
return this.Keys.Exists(l => l.Name == key);
}
/// <summary> 查找Key </summary>
public BaseKey Find(BaseKey key)
{
return this.Keys.Find(l => l.Equals(key));
}
/// <summary> 查找关键字Key </summary>
public BaseKey Find(string key)
{
return this.Keys.Find(l => l.Name.Equals(key));
}
/// <summary> 查找指定关键字处的索引 </summary>
public int FindIndex(BaseKey key)
{
return this.keys.FindIndex(l => l == key);
}
/// <summary> 从索引出移除所有关键字 </summary>
public void RemoveRange(int index)
{
this.keys.RemoveRange(index, this.keys.Count - index);
}
/// <summary> 从索引出移除所有关键字 </summary>
public void RemoveRange<T>(int index) where T : BaseKey
{
if (index >= this.keys.Count)
{
return;
}
List<T> fs = new List<T>();
for (int i = index; i < this.keys.Count; i++)
{
if (this.keys[i] is T)
{
fs.Add(this.keys[i] as T);
}
}
foreach (var v in fs)
{
// 清除数据
this.keys.Remove(v);
// 清除占位标识
this.lines.Remove(v._ID);
}
string ss = null;
}
/// <summary> 在本节点下面查找 如果有返回 如果没有创建并插入到本节点下</summary>
public T CreateSingle<T>(string keyName) where T : BaseKey
{
Type t = typeof(T);
T find = this.Find<T>();
if (find == null)
{
find = Activator.CreateInstance(t, new string[] { keyName }) as T;
this.Add(find);
}
return find;
}
/// <summary> 在本节点下面查找指定数量的关键字 如果有返回 如果没有创建并插入到本节点下</summary>
public List<T> CreateOfCount<T>(int count) where T : BaseKey
{
Type t = typeof(T);
List<T> find = this.FindAll<T>();
int addCount = count - find.Count;
addCount.DoCountWhile(l =>
{
T f = Activator.CreateInstance(t, new string[] { typeof(T).Name }) as T;
this.Add(f);
find.Add(f);
});
return find;
}
/// <summary> 增加节点 注意: 此方法改变了原节点的父节点引用 </summary>
public void Add(BaseKey key)
{
key.ParentKey = this;
// 记录位置
//this.Lines.Add(key.ID);
this.keys.Add(key);
key.baseFile = this.baseFile;
// Todo :替换所有关键字文件
key.Foreach(l => l.baseFile = this.baseFile);
}
/// <summary> 批量增加节点 </summary>
public void AddRange<T>(List<T> keys) where T : BaseKey
{
foreach (var v in keys)
{
this.Add(v);
}
}
/// <summary> 增加节点 注意: 此方法改变了原节点的父节点引用 </summary>
public void AddClone(BaseKey key)
{
this.keys.Add(key);
key.baseFile = this.baseFile;
}
/// <summary> 批量增加节点 </summary>
public void AddCloneRange<T>(List<T> keys) where T : BaseKey
{
foreach (var v in keys)
{
this.AddClone(v);
}
}
/// <summary> 清理数据 </summary>
public void Clear()
{
this.Lines.Clear();
this.Keys.Clear();
}
/// <summary> 清理数据 </summary>
public void ClearChild(Predicate<BaseKey> match)
{
this.Lines.Clear();
List<BaseKey> bk = this.keys.FindAll(l => match(l));
bk.ForEach(l => this.keys.Remove(l));
//this.keys.RemoveAll(bk);
//this.keys.ForEach(l =>
// {
// if (match(l))
// {
// this.Keys.Remove(l);
// }
// }
//);
}
/// <summary> 替换对应节点的所有内容 </summary>
public bool ExChangeData(BaseKey key)
{
// 删除本节点所有数据
this.Keys.RemoveAll(l => true);
if (key == null) return true;
添加替换的数据
//this.Keys.AddRange(key.Keys);
foreach (var item in key.Keys)
{
this.Add(item);
}
return true;
}
/// <summary> 将本节点替换为指定节点 </summary>
public void ReplaceTo(BaseKey key)
{
this.InsertBefore(key);
this.Delete();
}
#endregion
public override string ToString()
{
return this.name;
}
}
partial class BaseKey : IDisposable
{
#region - 资源释放 -
protected bool _isDisposed = false;
~BaseKey()
{
Dispose(false);
}
public void Dispose()
{
Dispose(true);
// 告诉GC不需要再次调用
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (!_isDisposed)
{
// 释放托管资源
// 释放非托管资源
// 释放大对象
this._isDisposed = true;
}
}
#endregion
}
源代码: https://github.com/HeBianGu/SimalorManager.git
最后
以上就是花痴火车为你收集整理的封装:Eclipse油藏数值模拟源文件解析封装的全部内容,希望文章能够帮你解决封装:Eclipse油藏数值模拟源文件解析封装所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复