小白的MatSWMM使用心路(二)——用matlab修改INP文件参数/使用matlab查找txt内容并修改多行内容

书接上文

小白的MatSWMM使用心路(一)——安装试运行过程与可能常见问题的解决_叶不伤的博客-CSDN博客上一篇中成功运行了MatSWMM,这一篇中来尝试自动率定最关键的一步,修改INP文件。

目录

目录

1. MatSWMM居然只能modify和get部分参数?悲催的事情发生了

2. 绕开MatSWMM,单独来看怎么批量修改Input(.INP文件)(其实是txt文件)

2.1 查询某个内容的所在的行

2.2 根据行号,提取指定某几行的内容并修改

提取查看

 进行修改

2.3 效果基本成功

3. 太长不看版的简单总结


1. MatSWMM居然只能modify和get部分参数?悲催的事情发生了

果然都是说的很美好,但是用起来会出各种各样的问题啊……

虽然一些文献中指出原版MatSWMM至少可以修改和调取管长、糙率等参数,但是它自己对于modify是这样写的:

也就是说按照这个说明,除了INVERT和DEPTH两个参数,其他的都无法进行修改

笔者进行实测,发现不止modify,就连get_from_input也只对这两个参数有反应,其他都会报错

 ……

但是get_all这个函数就很好用,全部数都可以调取出来,不太清楚为什么

关于这一点,2019年一位前辈的论文给出了SWMM增加API函数封装进dll的操作方法,大幅度增加了可以调整的参数并附上了源代码。可以说是完全解决了这个问题。(本人的研究思路也很大程度上借鉴了前辈的想法,向其致敬)。

基于改进和声搜索算法的城市雨洪模型参数率定 - 中国知网 (cnki.net)

但是!本人的C语言功底为0……所以,一时半会是复现不出这个做法了(悲)。

不过好消息是,既然SWMM的输入文件INP是一种比较灵活的文件格式,可以直接改后缀为txt,直接修改txt,然后再把后缀改回INP,就又能用了。那么干脆绕行,只要解决能够定位置批量修改INP的问题,其实也无需在意MatSWMM自己的功能嘛。

2. 绕开MatSWMM,单独来看怎么批量修改Input(.INP文件)

搜索了一下,很遗憾不太有Matlab直接修改input的方式。所以这一段直接其实就是怎么修改txt。

那还是再绕一下路,直接看matlab怎么修改txt的指定行,后期再批量修改后缀为inp罢。

这个还是比较现成的。

2.1 查询某个内容的所在的行

	a0=input('Input line content=','s');  %填写所需要查询的行的内容,储存为a0、
	fn=input('Input file address=','s');  %填写文件地址
	Origin= fopen(fn,'r');
	i=0;
	q=0;
	while  ~feof(Origin)   %循环体,feof为逐行查询txt
	 i=i+1;
	tline = fgetl(Origin);
	if strcmp(tline,a0);  %如果当前行是所查询的行
	  q=i;  %记录行号为q
	   end
	end
	fclose(Origin); %必须关,不然下次开会有问题
	fprintf( 'the line is line number')
	disp(q)   %输出查询到的行号

计划是提取txt中各个数据部分title的行号,以找到对应想修改的参数的位置,这部分参考教程为Matlab提取ABAQUS后处理文件inp中的节点数_dosper19的博客-CSDN博客_matlab怎么读取inp文件

而特别针对SWMM的INP文件以txt打开时,我们可以发现参数都是以[SUBCATCHMENT]这样的title开始,在出现第一个空格后结束。

那么进阶的,这个部分就可以以这种思路查找——查找出title后返回行号,之后继续接着查,查到第一个空行,再返回行号。

这一部分的代码改进为:

fn=input('Input file address=','s');  %填写文件地址
%全部粘贴完打回车后,出现Input file address=  在后面输入3tankstest.txt(不用加引号)。也可以输入自己的文件的完整地址

title=input('Input line content to find='); %填写要寻找的行内容
%全部粘贴完打回车后,出现Input line content to find= ,在后面输入["[SUBCATCHMENTS]";"[SUBAREAS]";"[INFILTRATION]"],也可以把每个双引号内改成自己想查询的行的完整内容

  Origin= fopen(fn,'r');
  len=length(title); %测量需要获取的信息长度
  q=zeros(len,2); %第一列用来储存数据起始,第二列储存数据结束
  for k=1:len %挨个title查询
   a0=title(k,1);
   i=0;
   frewind(Origin); %很重要,保证每次循环将指针复位到txt的首行,从头开始查
    while  ~feof(Origin)   %循环体,feof为逐行查询txt
     i=i+1;
     tline = fgetl(Origin);
        if strcmp(tline,a0) %如果当前行是所查询的行
        q(k,1)=i+2;%记录下来title的位置(其下2行开始为真实数据,故+2)
        break  %一旦查到就停止再往下查
        end
    end

    while  ~feof(Origin) %从上次从第i行的break的那里再开始,向后查询
    i=i+1;
    tline = fgetl(Origin);
        if  numel(tline)==0 %一旦出现第一个空行
        q(k,2)=i-1; %记录下来空行的位置(其上一行为真实数据,故-1)
        break  %一旦查到就停止再往下查
        end
    end
  end
disp(q) %查看矩阵q

2.2 根据行号,提取指定某几行的内容并修改

  • 提取查看

参考文章Matlab修改txt指定行内容_黑皮执事的博客-CSDN博客_matlab替换文本文件某一行

还是用MatSWMM里自带的示例文件3tanks.inp,后缀改成txt打开后看着是这样

 那么比如我们现在想批量修改汇水区【subcatchments】的坡度slope,变成3,3,2,2这样

先用上文查询所在行的代码查询一下【subcatchments】下属数据的行号。可以很轻松查询到汇水区参数真正的区域为56-59。

	fn= fopen('3tankstest.txt');    % 输入文件地址,确定提取文件fileID(fn)
	FormatString=repmat('%s %s %s %f %f %f %f %f',1,1);  
         %查看对应的txt里,每一段的格式
         %因为SWMM的inp文件格式固定,所以每种查一次就好
         %这里发现是前3个是字符,后5个是数字,所以这么写了,为了标准,其实也可以继续控制浮点的小数
	data = textscan(fn,FormatString,4,'headerlines',55);  
         %参数1:从fn里
         %参数2:以FormatString的格式提取值
         %参数3:提取4行
         %参数4:跳过前n行
         %参数5:跳过的n为55,即从56行开始提取
    fclose(fn); %记得有开有关,不然下次会报错

于是生成了data,查看一下为cell格式

 cell内为取值,和txt里一致

  •  进行修改

修改的时候最主要的麻烦出现在数据格式上,根据上述方法生成的data里,文本及参数均以数组格式储存起来,确实还是比较便于查看修改的。但是写入txt时,却变得麻烦了基本上要么写入纯文本,要么写入纯字符。至于数组,或者是字符和文本混合的形式,都不是被接受的状态……这个部分确实花了很多时间。

但是最终大概也是摸索出来了(好像有绕路,但是不管了XD)

修改完指定列后(比如修改了第7列slope):

%修改data里的指定列要素(这里以修改第7列slope为例子)
data{1,7}=[3;3;2;2];


	
%然后整理格式1 需要修改的部分有4行8列,因此创建一个4×8数组new储存
	new=cell(4,8);
	for i=1:4
	  for j=1:8
	     if j<4  %这里有点麻烦,前3列的字符是写在嵌套的cell里面的,所以得把字符串拿出来
	     aa=data{1,j}(i,1);
	            b=aa{1,1};
	            new{i,j}=b;
	    else
	     aa=data{1,j}(i,1);
	     b=num2str(aa);  %后5列则是直接写在第一层cell里,所以用num2str转成字符串
	      new{i,j}=b;
	end
	end
	end

	%整理格式2 将文本数字逐行转化成1个字符串储存进4×1的元胞数组new2
	 new2=cell(4,1); %同列合并起来
	 for i=1:4
	  tou=new{i,1};
	    for j=2:8
	      chuan=new{i,j};
	      chuan=[tou,' ',chuan]; %想到的方法只有循环,然后从头以空格连接8个要素,形成一个字符串
	      tou=chuan;
	   end
	 new2{i,1}=tou;
	end

继续进行把修改内容new2写进txt。至于怎么实现“替换txt中指定的几行”,可以参考以下教程,或其他教程也是一样的

matlab批量替换txt文本文件的特定行的内容_matlab 打开文件并覆盖指定行的数据-CSDN博客

总之实现“替换txt中指定的几行”步骤的思路差不多就是为:

1. 准备好需要替换的几行新内容(比如上述生成的变量new2)

2. 从头逐行抄写原txt

3. 如果到了需要修改行,那么则这几行就不抄原文,开始抄写新内容

4. 直到抄写完原txt最后一行

5. 把带有新内容的抄写版txt复制覆盖原txt/生成新txt

2.3 效果基本成功

打开新txt,可以看到虽然格式跟其他的已经不一样了(间隔符不一样),但是确实是写进去了

 那么swmm可以识别吗?

后缀直接改成inp然后导入一下:

(matlab控制修改后缀得教程可以参考:MATLAB 批量改文件后缀_凯旋16668的博客-CSDN博客_matlab批量修改后缀

 导入和识别都没有问题,坡度已经修改完成了,放进SWMM软件运行也完全没问题。

 利用MatSWMM在Matlab里运行也完全没有问题

3. 太长不看版的简单总结

整体上就是:因为MatSWMM无法实现所有参数的修改,所以:

将INP改成txt→(利用matlab与txt的交互)→对参数进行位置检索和提取→参数修改→参数写回txt→txt再改成INP。

肯定不是最简单的办法,但是感觉原理比较浅显也好理解吧,短时间内自己鼓捣也只能这么实现目标了。

下一篇的计划就是步入关键,整体批量修改和批量运算了。

还是,提前预祝自己成功啦(十一前要成功啊(哭))。

  • 9
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值